diff --git a/app.js b/app.js index ea40e27..c45a92c 100644 --- a/app.js +++ b/app.js @@ -1,4 +1,4 @@ -import { app, errorHandler } from "mu"; +import { app, errorHandler, uuid } from "mu"; import fetch from "node-fetch"; import { CronJob } from "cron"; import { @@ -9,74 +9,96 @@ import { createKboOrganisation, createNewKboOrg, linkAbbOrgToKboOrg, + getKboIdentifiers, } from "./lib/queries"; -import { CRON_PATTERN } from "./config"; +import { CRON_PATTERN, ORGANIZATION_STATUS } from "./config"; -app.post("/sync-kbo-data/:kboStructuredIdUuid", async function (req, res) { - try { - const kboStructuredIdUuid = req.params.kboStructuredIdUuid; - const identifiers = await getIdentifiers(kboStructuredIdUuid); +app.post( + "/sync-kbo-data/:kboStructuredIdUuid/:ovoOrKbo", + async function (req, res) { + try { + const kboStructuredIdUuid = req.params.kboStructuredIdUuid; + const createKbo = req.params.ovoOrKbo === "kbo" ? true : false; + const identifiers = await getIdentifiers(kboStructuredIdUuid); + console.log("create kbo? " + createKbo); - const wegwijsUrl = `https://api.wegwijs.vlaanderen.be/v1/search/organisations?q=kboNumber:${identifiers.kbo}&fields=changeTime,name,ovoNumber,kboNumber,labels,contacts,organisationClassifications,locations,parents)`; + const wegwijsUrl = `https://api.wegwijs.vlaanderen.be/v1/search/organisations?q=kboNumber:${identifiers.kbo}&fields=changeTime,name,shortName,ovoNumber,kboNumber,labels,contacts,organisationClassifications,locations,parents`; + console.log("url: " + wegwijsUrl); + const response = await fetch(wegwijsUrl); + const data = await response.json(); - const response = await fetch(wegwijsUrl); - const data = await response.json(); - - - let wegwijsOvo = null; - if (data.length) { - // We got a match on the KBO, getting the associated OVO back - const wegwijsInfo = data[0]; // Wegwijs should only have only one entry per KBO - let kboObject = getKboFields(wegwijsInfo); - if (kboObject.ovoNumber) { - wegwijsOvo = kboObject.ovoNumber; + let wegwijsOvo = null; + let kboObject = null; + if (data.length) { + // We got a match on the KBO, getting the associated OVO back + const wegwijsInfo = data[0]; // Wegwijs should only have only one entry per KBO + kboObject = getKboFields(wegwijsInfo); + if (kboObject.ovoNumber) { + wegwijsOvo = kboObject.ovoNumber; + } } - let kboOrg = ""; - //console.log(kboObject); - if (!identifiers.kboOrg) { - kboOrg = await createNewKboOrg(kboObject, "null"); + if (createKbo && kboObject) { + //create kbo organisation + let kboOrg = null; + const kboIdentifiers = await getKboIdentifiers(identifiers.adminUnit); + let update = false; + + if (kboIdentifiers) { + update = new Date(kboObject.changeTime).getTime() < new Date(kboIdentifiers.changeTime).getTime() ? true : false; + } + if(!kboIdentifiers || update){ + kboOrg = await createNewKboOrg(kboObject, identifiers.kboId); + await linkAbbOrgToKboOrg(identifiers.adminUnit, kboOrg); + } + return res.status(200).send(); + } + //Update Ovo Number + if (wegwijsOvo && wegwijsOvo != identifiers.ovo) { + console.log(identifiers.ovo); + + let ovoStructuredIdUri = identifiers.ovoStructuredId; + + if (!ovoStructuredIdUri) { + ovoStructuredIdUri = await constructOvoStructure( + identifiers.kboStructuredId + ); + } + await updateOvoNumberAndUri(ovoStructuredIdUri, wegwijsOvo); } - await linkAbbOrgToKboOrg(identifiers.adminUnit, kboOrg, identifiers.kbo); + return res.status(200).send(); // since we await, it should be 200 + } catch (e) { + console.log("Something went wrong while calling /sync-from-kbo", e); + return res.status(500).send(); } - - //Update Ovo Number - if (wegwijsOvo && wegwijsOvo != identifiers.ovo) { - console.log(identifiers.ovo); - - let ovoStructuredIdUri = identifiers.ovoStructuredId; - - if (!ovoStructuredIdUri) { - ovoStructuredIdUri = await constructOvoStructure( - identifiers.kboStructuredId - ); - } - await updateOvoNumberAndUri(ovoStructuredIdUri, wegwijsOvo); - } - - return res.status(200).send(); // since we await, it should be 200 - } catch (e) { - console.log("Something went wrong while calling /sync-from-kbo", e); - return res.status(500).send(); } -}); +); function getKboFields(data) { - console.log(data.organisationClassifications); - let changeTime = data.changeTime; + //wegwijs naam let organisationName = data.name; + let shortName = data.shortName; let ovoNumber = data.ovoNumber; let kboNumber = data.kboNumber; //no lables = undefined + //formal naam according to KBO let formalName = data.labels ?.filter((fields) => { return fields.labelTypeId === "83c1c22a-6776-0ad6-68d2-819e1c6eec66"; }) .pop()?.value; - + let startDate = data.labels + ?.filter((fields) => { + return fields.labelTypeId === "83c1c22a-6776-0ad6-68d2-819e1c6eec66"; + }) + .pop()?.validity?.start; + let activeState = (data.labels + ?.filter((fields) => { + return fields.labelTypeId === "83c1c22a-6776-0ad6-68d2-819e1c6eec66" && !fields.validity.hasOwnProperty("end"); + }) ? ORGANIZATION_STATUS.ACTIVE : ORGANIZATION_STATUS.INACTIVE) let email = data.contacts ?.filter((fields) => { return ( @@ -85,19 +107,16 @@ function getKboFields(data) { ); }) .pop()?.value; - let rechtsvorm = data.organisationClassifications ?.filter((fields) => { - console.log(fields); return ( - fields.organisationClassificationTypeId === "9bae7539-64fd-5759-743c-ad9dfa4143d4" || - fields.organisationClassificationTypeId === "1131205e-9212-435d-b4cd-b0d955d08bcf" + fields.organisationClassificationTypeId === + "9bae7539-64fd-5759-743c-ad9dfa4143d4" || + fields.organisationClassificationTypeId === + "1131205e-9212-435d-b4cd-b0d955d08bcf" ); }) .pop()?.organisationClassificationName; - - console.log(rechtsvorm) - let phone = data.contacts ?.filter((fields) => { return ( @@ -106,7 +125,6 @@ function getKboFields(data) { ); }) .pop()?.value; - let website = data.contacts ?.filter((fields) => { return ( @@ -115,9 +133,7 @@ function getKboFields(data) { ); }) .pop()?.value; - let province = data.parents?.parentOrganisationName; - let formattedAddress = data.locations ?.filter((fields) => { return ( @@ -127,29 +143,32 @@ function getKboFields(data) { }) .pop()?.formattedAddress; + //main location according to KBO let adressComponent = data.locations ?.filter((fields) => { return ( - fields.isMainLocation === true && + fields.locationTypeId === '537c0b5b-8ab8-fc3d-0b37-f8249cbdd3ba' && !fields.validity?.hasOwnProperty("end") ); }) .pop()?.components; - return { - changeTime: (typeof changeTime != 'undefined' ? changeTime : ""), - organisationName: (typeof organisationName != 'undefined' ? organisationName : ""), - ovoNumber: (typeof ovoNumber != 'undefined' ? ovoNumber : ""), - kboNumber: (typeof kboNumber != 'undefined' ? kboNumber : ""), - formalName: (typeof formalName != 'undefined' ? formalName : ""), - rechtsvorm: (typeof rechtsvorm != 'undefined' ? rechtsvorm : ""), - email: (typeof email != 'undefined' ? email : ""), - phone: (typeof phone != 'undefined' ? phone : ""), - website: (typeof website != 'undefined' ? website : ""), - province: (typeof province != 'undefined' ? province : ""), - formattedAddress: (typeof formattedAddress != 'undefined' ? formattedAddress : ""), - adressComponent: (typeof adressComponent != 'undefined' ? adressComponent : ""), + changeTime: (changeTime ? changeTime : " "), + organisationName: (organisationName ? organisationName : " "), + shortName: (shortName ? shortName : organisationName), + ovoNumber: (ovoNumber ? ovoNumber : " "), + kboNumber: (kboNumber ? kboNumber : " "), + formalName: (formalName ? formalName : " "), + startDate: (startDate ? startDate : " "), + activeState: activeState, + rechtsvorm: (rechtsvorm ? rechtsvorm : " "), + email: (email ? email : " "), + phone: (phone ? phone : " "), + website: (website ? website : " "), + province: (province ? province : " "), + formattedAddress: (formattedAddress ? formattedAddress : " "), + adressComponent: (adressComponent ? adressComponent : " "), }; } diff --git a/config.js b/config.js index de6c026..49b8353 100644 --- a/config.js +++ b/config.js @@ -1 +1,6 @@ -export const CRON_PATTERN = process.env.CRON_PATTERN || '0 0 0 * * *'; // every day at midnight \ No newline at end of file +export const CRON_PATTERN = process.env.CRON_PATTERN || '0 0 0 * * *'; // every day at midnight + +export const ORGANIZATION_STATUS = { + ACTIVE: "http://lblod.data.gift/concepts/63cc561de9188d64ba5840a42ae8f0d6", + INACTIVE: "http://lblod.data.gift/concepts/d02c4e12bf88d2fdf5123b07f29c9311" +} \ No newline at end of file diff --git a/lib/queries.js b/lib/queries.js index ec0aaaa..6173ad9 100644 --- a/lib/queries.js +++ b/lib/queries.js @@ -3,7 +3,7 @@ import { querySudo as query, updateSudo as update } from '@lblod/mu-auth-sudo'; export async function getIdentifiers(kboStructuredIdUuid) { const queryStr = ` - SELECT DISTINCT ?kbo ?ovo ?kboStructuredId ?ovoStructuredId ?bestuurseenheid ?kboOrganisation WHERE { + SELECT DISTINCT ?kbo ?kboId ?ovo ?kboStructuredId ?ovoStructuredId ?bestuurseenheid WHERE { VALUES ?g { @@ -26,10 +26,9 @@ export async function getIdentifiers(kboStructuredIdUuid) { ?ovoId ?ovoStructuredId ; ?ovoNotation . - OPTIONAL { ?ovoStructuredId ?ovo . } + OPTIONAL { ?ovoStructuredId ?ovo . + } - ?bestuurseenheid owl:sameAs ?kboOrganisation . - FILTER (?ovoNotation IN ("OVO-nummer"@nl, "OVO-nummer")) } } @@ -45,6 +44,7 @@ export async function getIdentifiers(kboStructuredIdUuid) { kboStructuredId: binding.kboStructuredId.value, ovo: binding.ovo?.value, ovoStructuredId: binding.ovoStructuredId?.value, + kboId: binding.kboId?.value, adminUnit: binding.bestuurseenheid.value, kboUnit: binding.kboOrganisation?.value } @@ -52,6 +52,43 @@ export async function getIdentifiers(kboStructuredIdUuid) { return null; } +export async function getKboIdentifiers(administrativeUnit, changeTime) { + const queryStr = ` + SELECT DISTINCT ?kboUnit ?abbUnit ?changeTime ?contactPointUri ?addressUri WHERE { + VALUES ?g { + + + } + GRAPH ?g { + ?kboUnit a ; + ?uuid ; + ?contactPointUri ; + ?changeTime . + + ?contactPointUri ?addressUri . + + ?kboUnit owl:sameAs ?abbUnit + + FILTER(?abbUnit = ${sparqlEscapeUri(administrativeUnit)}) + } + } + `; + + const result = await query(queryStr); + + if (result.results.bindings.length) { + const binding = result.results.bindings[0]; // We should only have one KBO/OVO couple + return { + kboUnit: binding.kboUnit?.value, + abbUnit: binding.abbUnit?.value, + changeTime: binding.changeTime?.value, + contactPointUri: binding.contactPointUri?.value, + addressUri: binding.addressUri?.value, + } + } + return null; +} + export async function constructOvoStructure(kboStructuredId) { const idUuid = uuid(); const idUri = `http://data.lblod.info/id/identificatoren/${idUuid}` @@ -187,36 +224,46 @@ export async function getAllOvoAndKboCouples() { return null; } -export async function createRechtsVormStructure(){ - -} - -export async function createNewKboOrg(kboOrg ,kboNummer){ +export async function createNewKboOrg(kboOrg, kboId, isUpdate, oldKbo){ const newKboOrgIdUuId = uuid(); const newKboIdUri = `http://data.lblod.info/id/kboBestuurseenheden/${newKboOrgIdUuId}`; const contactPointUuidId = uuid(); const contactPointUri = `http://data.lblod.info/id/contact-punten/${contactPointUuidId}`; - let updateStr = ` + const adressUuidId = uuid(); + const adressUri = `http://data.lblod.info/id/adressen/${adressUuidId}`; + + let updateStr = ""; + + + updateStr += ` INSERT { GRAPH ?g { + ${sparqlEscapeUri(adressUri)} a ; + ${sparqlEscapeString(adressUuidId)} ; + ${sparqlEscapeString(kboOrg.formattedAddress)} . ${sparqlEscapeUri(contactPointUri)} a ; ${sparqlEscapeString(contactPointUuidId)} ; ${sparqlEscapeString(kboOrg.email)} ; ${sparqlEscapeString(kboOrg.phone)} ; ${sparqlEscapeString("Kbocontact")} ; - ${sparqlEscapeString(kboOrg.website)}. + ${sparqlEscapeString(kboOrg.website)} ; + ${sparqlEscapeUri(adressUri)}. ${sparqlEscapeUri(newKboIdUri)} a ; ${sparqlEscapeString(newKboOrgIdUuId)} ; ${sparqlEscapeString(kboOrg.rechtsvorm)} ; + ${sparqlEscapeString(kboOrg.shortName)} ; + ${sparqlEscapeString(kboOrg.startDate)} ; ${sparqlEscapeString(kboOrg.organisationName)} ; ${sparqlEscapeString(kboOrg.formalName)} ; ${sparqlEscapeString(kboOrg.changeTime)} ; + ${sparqlEscapeUri(kboId)} ; + ${sparqlEscapeUri(kboOrg.activeState)} ; ${sparqlEscapeUri(contactPointUri)} . } }WHERE{ @@ -230,8 +277,6 @@ export async function createNewKboOrg(kboOrg ,kboNummer){ return newKboIdUri; } - - export async function linkAbbOrgToKboOrg(abbOrgUri ,kboOrgUri){ let updateStr = ` INSERT { @@ -242,6 +287,9 @@ export async function linkAbbOrgToKboOrg(abbOrgUri ,kboOrgUri){ VALUES ?g { } + + ${sparqlEscapeUri(kboOrgUri)} a . + } `