diff --git a/openfn-cd92dd57-9a3c-4318-bdcb-f57a386cf811-state.json b/openfn-cd92dd57-9a3c-4318-bdcb-f57a386cf811-state.json index 7a1522c..f8fca99 100644 --- a/openfn-cd92dd57-9a3c-4318-bdcb-f57a386cf811-state.json +++ b/openfn-cd92dd57-9a3c-4318-bdcb-f57a386cf811-state.json @@ -3,8 +3,11 @@ "name": "msf-lime-iraq", "description": null, "inserted_at": "2024-09-05T06:59:05Z", - "updated_at": "2024-10-01T10:13:58Z", + "updated_at": "2024-10-01T11:42:17Z", "scheduled_deletion": null, + "history_retention_period": null, + "dataclip_retention_period": null, + "retention_policy": "retain_all", "project_credentials": { "mtuchi@openfn.org-OpenMRS-Demo": { "id": "3141d874-5456-4168-9680-ce04efb1089c", @@ -22,145 +25,73 @@ "owner": "mtuchi@openfn.org" } }, - "history_retention_period": null, - "dataclip_retention_period": null, - "retention_policy": "retain_all", "workflows": { - "wf1-dhis2-omrs-migration": { - "id": "94e04fb5-d5ae-45ad-be31-98b902f36861", - "name": "wf1-dhis2-omrs-migration", - "inserted_at": "2024-10-01T07:13:00.890263Z", - "lock_version": 41, - "triggers": { - "cron": { - "enabled": false, - "id": "0e7d525f-c24a-4969-8131-397cc94a6065", - "type": "cron", - "cron_expression": "0 0 * * *" - } - }, - "jobs": { - "Get-Teis": { - "id": "be724c80-92c8-4fa9-8c3a-d28c5a298fd5", - "name": "Get Teis", - "body": "fn(state => {\n // const manualCursor = '2023-06-20T17:00:00.00';\n state.cursor = state.manualCursor || state.lastRunDateTime;\n console.log('Date cursor to filter TEI extract ::', state.cursor);\n\n return state;\n});\n\n// Get trackedEntityInstances that are \"active\" in the target program\nget(\n 'tracker/trackedEntities',\n {\n orgUnit: 'OPjuJMZFLop',\n program: 'w9MSPn5oSqp',\n programStatus: 'ACTIVE',\n },\n {},\n state => {\n const trackedEntityInstances = state.data.instances\n .filter(tei => tei.updatedAt >= state.cursor) //for testing\n //.filter(tei => tei.createdAt > state.cursor) //for prod\n //.slice(0, 1); //to limit 1 for testing\n const offset = 2; // GMT+2 (Geneva time)\n const currentDateTime = new Date();\n currentDateTime.setHours(currentDateTime.getHours() + offset);\n\n const lastRunDateTime = currentDateTime.toISOString().replace('Z', '');\n //console.log('TEI payload found before filter ::', JSON.stringify(state.data.instances, null, 2));\n console.log('# of TEIs found before filter ::', state.data.instances.length);\n //console.log('lastUpdated of TEI eWXRNHtmHB0 :: ', JSON.stringify(state.data.instances.filter(tei => tei.trackedEntity == 'eWXRNHtmHB0'), null, 2)); \n console.log('# of TEIs to migrate to OMRS ::', trackedEntityInstances.length);\n // console.log(\n // 'trackedEntityInstance IDs ::',\n // trackedEntityInstances.map(tei => tei.trackedEntityInstance)\n // );\n\n console.log('Next sync start date:', lastRunDateTime);\n return {\n ...state,\n // data: {},\n references: [],\n trackedEntityInstances,\n lastRunDateTime,\n };\n }\n);\n", - "adaptor": "@openfn/language-dhis2@latest", - "project_credential_id": "8a5ead9b-5f9e-49b1-9e9a-9dc3c4ccf72d" - }, - "Get-Locations": { - "id": "2c1dc59e-c8c0-409d-813f-d0eb3f812a07", - "name": "Get Locations", - "body": "get('optionGroups/kdef7pUey9f', {\n fields: 'id,displayName,options[id,displayName,code]',\n});\n\nfn(({ data, ...state }) => {\n state.locations = data;\n return state;\n});\n\nfn(state => {\n state.nationalityMap = {\n afghanistan: '84066564-253e-43d8-b141-76730cffa878',\n albania: 'db21f4f9-faf2-4358-8297-0ae76627b3b8',\n algeria: '5f6c017f-074c-46b3-92d0-d055e2094366',\n angola: '8a2e5a03-8a74-41ae-9a98-2310f9ce400d',\n anguilla: 'c911af8a-171c-4ee9-b1ff-934373e8a819',\n argentina: 'b83d24e8-34d8-4920-83c0-8ba014467ff4',\n armenia: '39f1652a-f2b7-4b65-a7e1-7097ac6cdef0',\n aruba: 'f3f1cba1-7c1e-4234-86a2-f27bb5964fee',\n azerbaijan: '29750013-0e35-47ca-8f77-9192a923fb07',\n bangladesh: 'a99de53c-ce76-4b1e-91b2-461094baf79e',\n belarus: '664baba4-c552-47b9-97c0-ff67dafd27d6',\n benin: 'cf863e31-bb38-48ed-90dd-f3dedcac304c',\n bhutan: 'd45a57c9-994f-4deb-8845-9b785860a2ec',\n bolivia: 'd8800d10-862b-42f1-8e22-cac1ce1bbcae',\n bosnia_and_herzegovina: '05d8f4ef-45eb-463d-b2f3-8a5a613ee6b9',\n botswana: '1304a0de-5b70-4d36-a873-e72a82963316',\n brazil: '353ff388-64e6-434c-b78f-ca9636390389',\n british_virgin_islands: 'b02c6d20-83a2-4947-8a7d-91d1f9c4d8a2',\n bulgaria: '91c85a62-2b02-483a-aefd-e29d368565fe',\n burkina_faso: '6c90c1ae-17a4-4e94-a267-4fba4c94efd8',\n burundi: '8a2ed0db-eaad-44bc-bf06-5cb1b2a3db0b',\n cambodia: '4fd14df8-8279-4dfa-bdd3-e1ab26bc0264',\n cameroon: '873552ac-9850-4cc1-ae09-17eb0fccf405',\n cape_verde: 'cfbc220a-1d6c-4469-bb6d-a8e3deb4f7e7',\n central_african_republic: '61a4c4a4-25c2-4459-a874-ec1d24f8323a',\n chad: '9e41e71c-f5d5-456c-a6f9-2129b8055bfc',\n chile: '05333883-44e9-4f57-836a-041391803007',\n china: '15016874-3e20-484a-baa8-9b94e1a3d358',\n colombia: 'a008dff8-ce96-4662-bf8a-372e43d424f0',\n comoros: '9d8738c8-40c2-4c66-aabb-ef176a20ffe8',\n costa_rica: 'fb52f8c9-40ec-4dc4-92a4-d465612de2ff',\n cote_divoire: '513cb36a-3f67-46ea-a789-fcdaca0e26f5',\n cuba: '147c2434-5d7e-420c-8053-ba623301f3f5',\n djibouti: 'cf5b334f-1c0f-41fc-ab54-53ff1e942830',\n dominica: 'f70e51e5-b76c-4c38-9bf2-ef8e1f308ce1',\n dominican_republic: 'ce72fc9b-619b-4c32-b865-600e888ad814',\n drc_congo: '8f6d3d2a-e09f-473b-99c9-e539f97ceab6',\n east_timor: '854f2f66-40e1-4a6a-9dee-09c832a52289',\n ecuador: 'f9810f9a-78a7-42a2-99e6-19c629642386',\n egypt: 'cc7343f8-9243-4d09-b378-58363850d624',\n el_salvador: '9a34935e-5a8a-45be-8ccd-cb23192e420f',\n equatorial_guinea: '7e591605-d723-4398-982a-8737af63a2dc',\n eritrea: 'c61f03c2-0d1f-444f-a974-0a61063aff71',\n ethiopia: '7478d375-014e-410e-a355-090143e88f5b',\n gabon: '9f46ae06-114a-47fa-8f8d-e9749f04da25',\n gambia: '5ec7ddd7-14a5-48ec-9e7c-8896d1010655',\n georgia: 'bc71788f-db69-4b6f-8d1c-57a74395bdd2',\n ghana: '2eb4ff46-d908-4148-9b0d-40ccfc1a655a',\n greece: 'b75d6bcc-fadf-4141-8d0f-2463154b89f7',\n guam: '51fa502b-98a3-4c42-b5fd-7b4d64489bb9',\n guatemala: '3725a4d2-b28f-466b-905a-bafeaeb75855',\n guinea: 'eeaff39c-8afd-43f7-b9a0-53729f5df1d8',\n guinea_bissau: '14e90203-9197-42ea-9222-acafd2fd6984',\n guyana: 'ba4dfa7e-f3cd-4e94-8ca7-6b96a93378a8',\n haiti: 'f76f7dcb-f82e-4257-a627-1685ff3f3586',\n honduras: 'cdd1336e-495b-4868-aace-57a84442d6fd',\n india: '378d0107-eb43-485d-930c-0704b4e5aa11',\n indonesia: '1cbe17e6-adc2-4680-bee0-54d94af75ebf',\n iran: 'b422270e-d8af-4a32-b523-742545a17a3f',\n iraq: '03aa7d6e-7656-48e4-8dc0-5e27706722c0',\n jordan: '842f963c-f84d-4076-a8db-337295fd9b91',\n kazakhstan: '6f6d0e78-2c81-411d-8d13-367e250dc110',\n kenya: 'ad351a33-8846-4cad-8195-b07b6041d4a5',\n kuwait: '4aee7a88-cda9-454e-9f25-4a6420270417',\n kyrgyzstan: 'ace3b851-042b-46a6-8fea-68aae042d614',\n laos: 'dfb01b39-c224-459e-b045-dd9461b9a1e5',\n lebanon: '7de78f22-f53e-48d2-923f-ae1e4d814f46',\n lesotho: 'b35b29c5-9bb7-4b40-ad33-29eecd28a9e6',\n liberia: 'a5fd61b4-fd27-433d-8428-7e88a7f27921',\n libya: '600c6af4-b767-423c-b942-7f06ca467258',\n macedonia: '5837cc40-9ab5-4088-91c8-ca6e4b57e903',\n madagascar: '3782bf3c-380e-4b60-b21a-38199073f112',\n malawi: 'e8b5f188-6a5c-43ae-b4a5-200abb13153e',\n malaysia: '3facca11-fbaa-4c40-8fac-4751d45c3f1b',\n mali: '3e844a47-526a-46f9-afea-1af9ff8690aa',\n martinique: '051ce04e-05e8-4430-8b75-3e499bbffbc8',\n mauritania: '8acb006b-8596-4a98-8177-acb4cb575956',\n mauritius: '17ced083-eb2a-4046-a713-26cabc7af95d',\n mayotte: '1af148fe-2698-4b89-bf7f-87e5c48b6848',\n mexico: '8381208f-01ca-4ed3-8f2c-f73ed1c316e3',\n moldova: 'f0e9c8b5-69b5-48df-8cb9-2d089ba04e46',\n mongolia: '9f341cb1-dcb5-4f6c-bd21-b57db01b4193',\n morocco: 'ef467a17-91e8-4124-a136-7ed8ff7c7d15',\n mozambique: '0916133b-4d93-4d60-9c20-e7ee3936f391',\n myanmar: 'e81ba700-f9fc-4ed0-b248-578a25717cdb',\n namibia: '0cb123dc-8810-4840-b6ab-6a527c5a79ef',\n nauru: '3386fe63-2158-4040-a502-9f65fd2079d3',\n nepal: 'fb01b01a-6775-423c-8012-7d43f587cb6c',\n new_caledonia: 'e67c072b-7707-491f-8c2e-13c914216b61',\n nicaragua: 'f6a9521c-596b-49f9-b914-67138e8c17e6',\n niger: '7561db90-a866-4443-93f4-95cac1d47e9c',\n nigeria: '4134651a-7f53-45fb-8bc6-7fed9cf36f51',\n north_korea: '4d3079e4-8568-48e6-9342-665896875a38',\n oman: '9b0af037-99d1-43b8-ac06-82137ec4b06d',\n other: 'Other',\n pakistan: 'f45d93c3-c9b0-4333-a5e6-299b7c425812',\n palestine: 'e2a19948-49aa-44c0-98ef-67ae1160ef43',\n panama: '1ef5a828-9d0d-4336-91ab-880d5dc0151c',\n papua_new_guinea: 'e1e6b451-d7fe-4954-b225-99b2de82a4c0',\n paraguay: 'd8412016-82f5-4801-a026-1bdc429850b7',\n peru: 'e74fa87f-8469-46b0-975f-6cb37c394564',\n philippines: 'bdbd5c9f-1f28-4f4d-a254-4a84f8bb2c8f',\n puerto_rico: '39fca1d0-d2e7-4b13-82bd-626fbec71252',\n republic_of_congo: '5db9afa5-b57e-4f45-8b1c-af766f14fc58',\n reunion: '1dae4b2d-50c9-4bf1-b25a-7063600a5e74',\n romania: '457e745e-ae97-463d-95a9-8d5689d3ca2b',\n rwanda: '6bc925a1-7699-496a-85b0-c290699381db',\n samoa: 'e03b381b-a7f4-40eb-964f-51571dc3c48c',\n sao_tome_and_principe: 'f66bbb42-684f-42d7-bfcd-95d586eb7dc9',\n saudi_arabia: 'fdf495a4-e60c-46f7-a8a2-61a216849086',\n senegal: 'ad948f1b-0733-4f8d-b049-d64289b43a10',\n serbia: 'd2e69cef-3bff-4220-ba91-a6a678fb606b',\n sierra_leone: 'ffba9caf-b6aa-4078-845e-578f7a7fd566',\n somalia: '99c8dccc-4dfa-4d30-86be-42a309ab431f',\n south_africa: '75882d62-1c55-480d-b411-8ca40c3307df',\n south_korea: '0603d6b9-334f-4443-ab60-7c5d457b95fc',\n south_sudan: 'f113e24e-2ea9-49a2-9b28-59241b9adb21',\n sri_lanka: 'b0031c01-d242-4410-b98b-cc1511590b85',\n sudan: '2f03a932-2b75-4e8b-9f44-0fcd83c75dc4',\n suriname: 'c65d3329-98d4-4dd7-89d3-141b70d00eb2',\n swaziland: '06a2703b-af17-4e44-83f5-6cc9a8a75320',\n switzerland: 'dcdcdc70-a006-4b0a-bac2-7de89b022b65',\n syria: '1e34ee55-ef9f-4386-bae6-6995555ded75',\n tajikistan: '34836c60-5449-48d6-b3c9-c0b3361b9f2c',\n tanzania: '050a8eb1-0d77-4f65-a2da-776a13bcd2a4',\n thailand: '289ac5bd-6434-4837-86bf-b54d22970ac8',\n togo: '6a583e64-869d-477d-a1c1-746320d45fc4',\n tonga: 'd381f06d-2365-4f40-948b-cfe90d8cb532',\n tunisia: '56be7864-fde6-4db3-8fa5-b9dd42cd9c53',\n turkey: '7429c779-1d3a-4aec-8256-d0b1637e1bd1',\n turkmenistan: '3ef17df5-299b-4385-9ea6-572df4b6f9ca',\n uganda: 'be3d11d3-446d-440c-a582-d01c7cbb0eda',\n ukraine: '38c99c8d-2b93-4848-a537-b1865a260bb2',\n unknown: 'Unknown',\n uruguay: 'c2e45baf-748b-4d7b-a391-ed6b802b6f94',\n uzbekistan: '60512350-d79b-41aa-aff0-1b28ca4aa5f1',\n venezuela: '557cea4a-0049-4b7a-b373-ed63f294a2a0',\n vietnam: '49509c5f-e533-48a8-bf06-86935e3376b2',\n western_sahara: '4086dfd2-f4f5-4107-93e8-07bee235af8f',\n yemen: '6a3214e0-f94b-414c-8148-968e24386671',\n zambia: '3ec0432d-ea37-4159-a658-29d6f07fe21a',\n zimbabwe: 'ce1b0d8d-0a2d-4f93-a6ed-64aca2fd0f45',\n };\n state.statusMap = {\n asylum_seeker: 'f921ffdd-72ca-4d58-a89b-1fa2e959d110',\n no_status: '2bacead2-f280-457c-9d28-e80e106f7d25',\n refugee: 'MSF-AAAAAA000000000000001929',\n single: '20b8524e-4c26-4fa0-81f0-fa23ebacc54d',\n married: 'MSF-AAAAAA000000000000001863',\n widowed: 'MSF-AAAAAA000000000000001864',\n divorced_separated: 'MSF-AAAAAA000000000000001865',\n concubine: '1060AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',\n not_applicable: 'MSF-AAAAAA000000000000001823',\n student: 'MSF-AAAAAA000000000000001871',\n permanent_employee: '4a18a820-f3a1-4bb7-9138-558a9ecc81da',\n occasional_employee: '2cb73bee-7f94-4695-89c7-c81187dbc90c',\n unemployed: 'MSF-AAAAAA000000000000001870',\n housewife: '9b14b4d4-b749-4acf-acfe-79c480f3c4b3',\n other: 'MSF-AAAAAA000000000000001329',\n unknown: '1067AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',\n idp: 'MSF-AAAAAA000000000000001930',\n internationally_displaced: '515c5abe-4172-4d0c-a991-0de2888228d7',\n non_displaced: 'bbdb287c-4ba1-4944-bd87-eb126c5f9d92',\n returnee: 'fc49acaa-ece2-4365-9dfb-70c2105de8b1',\n };\n return state;\n});\n", - "adaptor": "@openfn/language-dhis2@latest", - "project_credential_id": "8a5ead9b-5f9e-49b1-9e9a-9dc3c4ccf72d" - }, - "Create-Patients": { - "id": "fd21a322-aca4-404f-8b5c-93f5f23336fc", - "name": "Create Patients", - "body": "//Define gender options and prepare newPatientUuid and identifiers\nfn(state => {\n const genderOptions = {\n male: 'M',\n female: 'F',\n unknown: 'U',\n transgender_female: 'O',\n transgender_male: 'O',\n prefer_not_to_answer: 'O',\n gender_variant_non_conforming: 'O',\n };\n\n const identifiers = [];\n const newPatientUuid = [];\n\n const { trackedEntityInstances } = state;\n if (trackedEntityInstances.length > 0)\n console.log(\n '# of TEIs to send to OpenMRS: ',\n trackedEntityInstances.length\n );\n if (trackedEntityInstances.length === 0)\n console.log('No data fetched in step prior to sync.');\n\n return {\n ...state,\n genderOptions,\n newPatientUuid,\n identifiers,\n };\n});\n\n//First we generate a unique OpenMRS ID for each patient\neach(\n 'trackedEntityInstances[*]',\n post(\n 'idgen/identifiersource/8549f706-7e85-4c1d-9424-217d50a2988b/identifier',\n {}\n ).then(state => {\n state.identifiers.push(state.data.identifier);\n return state;\n })\n);\n\n// Then we map trackedEntityInstances to openMRS data model\nfn(state => {\n const {\n trackedEntityInstances,\n identifiers,\n genderOptions,\n nationalityMap,\n statusMap,\n locations,\n } = state;\n\n const getValueForCode = (attributes, code) => {\n const result = attributes.find(attribute => attribute.code === code);\n return result ? result.value : undefined;\n };\n\n const calculateDOB = age => {\n const currentDate = new Date();\n const currentYear = currentDate.getFullYear();\n const birthYear = currentYear - age;\n\n const birthday = new Date(\n birthYear,\n currentDate.getMonth(),\n currentDate.getDay()\n );\n\n return birthday.toISOString().replace(/\\.\\d+Z$/, '+0000');\n };\n\n state.patients = trackedEntityInstances.map((d, i) => {\n const patientNumber = getValueForCode(d.attributes, 'patient_number'); // Add random number for testing + Math.random()\n\n const nationality =\n nationalityMap[getValueForCode(d.attributes, 'origin_nationality')];\n const currentStatus =\n statusMap[getValueForCode(d.attributes, 'current_status')];\n const legalStatus =\n getValueForCode(d.attributes, 'legal_status') &&\n statusMap[getValueForCode(d.attributes, 'legal_status')];\n const maritalStatus =\n statusMap[getValueForCode(d.attributes, 'marital_status')];\n const employmentStatus =\n statusMap[getValueForCode(d.attributes, 'occupation')];\n\n const noOfChildren = d.attributes.find(\n a => a.attribute === 'SVoT2cVLd5O'\n )?.value;\n\n const lonlat = d.attributes.find(a => a.attribute === 'rBtrjV1Mqkz')?.value;\n const location = lonlat\n ? locations.options.find(o => o.code === lonlat)?.displayName\n : undefined;\n\n let countyDistrict, cityVillage;\n\n if (location) {\n const match = location.match(/^(.*?)\\s*\\((.*?)\\)/);\n if (match) {\n [, countyDistrict, cityVillage] = match;\n cityVillage = cityVillage.split('-')[0].trim(); // Remove country code and trim\n }\n }\n\n return {\n patientNumber,\n person: {\n age: getValueForCode(d.attributes, 'age'),\n gender: genderOptions[getValueForCode(d.attributes, 'sex')],\n birthdate:\n d.attributes.find(a => a.attribute === 'WDp4nVor9Z7')?.value ??\n calculateDOB(getValueForCode(d.attributes, 'age')),\n birthdateEstimated: d.attributes.find(\n a => a.attribute === 'WDp4nVor9Z7'\n )\n ? true\n : false,\n names: [\n {\n familyName:\n d.attributes.find(a => a.attribute === 'fa7uwpCKIwa')?.value ??\n 'unknown',\n givenName:\n d.attributes.find(a => a.attribute === 'Jt9BhFZkvP2')?.value ??\n 'unknown',\n },\n ],\n addresses: [\n {\n country: 'Iraq',\n stateProvince: 'Ninewa',\n countyDistrict,\n cityVillage,\n },\n ],\n attributes: [\n {\n attributeType: '24d1fa23-9778-4a8e-9f7b-93f694fc25e2',\n value: nationality,\n },\n {\n attributeType: 'e0b6ed99-72c4-4847-a442-e9929eac4a0f',\n value: currentStatus,\n },\n legalStatus && {\n attributeType: 'a9b2c642-097f-43f8-b96b-4d2f50ffd9b1',\n value: legalStatus,\n },\n {\n attributeType: '3884dc76-c271-4bcb-8df8-81c6fb897f53',\n value: maritalStatus,\n },\n employmentStatus && {\n attributeType: 'dd1f7f0f-ccea-4228-9aa8-a8c3b0ea4c3e',\n value: employmentStatus,\n },\n noOfChildren && {\n attributeType: 'e363161a-9d5c-4331-8463-238938f018ed',\n value: noOfChildren,\n },\n ].filter(i => i),\n },\n\n identifiers: [\n {\n identifier: identifiers[i], //map ID value from DHIS2 attribute\n identifierType: '05a29f94-c0ed-11e2-94be-8c13b969e334',\n location: 'cf6fa7d4-1f19-4c85-ac50-ff824805c51c', //default location old:44c3efb0-2583-4c80-a79e-1f756a03c0a1\n preferred: true,\n },\n {\n uuid: d.trackedEntity,\n identifier: patientNumber,\n identifierType: '8d79403a-c2cc-11de-8d13-0010c6dffd0f', //Old Identification number\n location: 'cf6fa7d4-1f19-4c85-ac50-ff824805c51c', //default location\n preferred: false, //default value for this identifiertype\n },\n ],\n };\n });\n\n return state;\n});\n\n// Creating patients in openMRS\neach(\n '$.patients[*]',\n upsert(\n 'patient',\n state => {\n return { q: state.data.patientNumber };\n },\n state => {\n const { patientNumber, ...patient } = state.data;\n console.log(\n 'Upserting patient record\\n',\n JSON.stringify(patient, null, 2)\n );\n return patient;\n },\n state => {\n state.newPatientUuid.push({\n patient_number: state.references.at(-1)?.patientNumber,\n uuid: state.data.uuid,\n });\n return state;\n }\n )\n);\n\n// Clean up state\nfn(({ data, references, ...state }) => state);\n", - "adaptor": "@openfn/language-openmrs@latest", - "project_credential_id": "3141d874-5456-4168-9680-ce04efb1089c" - }, - "Update-Teis": { - "id": "eed2a687-7ef3-4a38-819e-d50319874d03", - "name": "Update Teis", - "body": "fn(state => {\n if (state.newPatientUuid.length === 0) {\n console.log('No data fetched in step prior to sync.');\n }\n\n console.log(\n 'newPatientUuid ::',\n JSON.stringify(state.newPatientUuid, null, 2)\n );\n return state;\n});\n\n// Update TEI on DHIS2\neach(\n 'newPatientUuid[*]',\n upsert(\n 'trackedEntityInstances',\n state => ({\n ou: 'OPjuJMZFLop',\n program: 'w9MSPn5oSqp',\n filter: [`P4wdYGkldeG:Eq:${state.data.patient_number}`],\n }),\n {\n orgUnit: 'OPjuJMZFLop',\n program: 'w9MSPn5oSqp',\n trackedEntityType: 'cHlzCA2MuEF',\n attributes: [\n { attribute: 'P4wdYGkldeG', value: `${$.data.patient_number}` }, //DHIS2 patient number to use as lookup key\n { attribute: 'AYbfTPYMNJH', value: `${$.data.patient.uuid}` }, //OMRS patient uuid\n {\n attribute: 'ZBoxuExmxcZ',\n value: `${$.data.patient.identifier[0].identifier}`,\n }, //id generated in wf1-2 e.g., \"IQ146-24-000-027\"\n ],\n }\n )\n);\n", - "adaptor": "@openfn/language-dhis2@5.0.1", - "project_credential_id": "8a5ead9b-5f9e-49b1-9e9a-9dc3c4ccf72d" - } - }, + "wf2-omrs-dhis2": { + "id": "0f8ec062-1a2d-4f13-a8c5-b8298004512c", + "name": "wf2-omrs-dhis2", "edges": { - "cron->Get-Teis": { + "cron->Get-Patients": { "enabled": true, - "id": "f54f198a-5fa1-4ee0-803f-35316e32ab92", - "source_trigger_id": "0e7d525f-c24a-4969-8131-397cc94a6065", + "id": "7d239f46-635e-4b7f-8706-6a3d08d473db", + "source_trigger_id": "51283b68-c07a-4d85-854c-c2e6e93af041", "condition_type": "always", - "target_job_id": "be724c80-92c8-4fa9-8c3a-d28c5a298fd5" + "target_job_id": "ab326112-9cdd-4449-8611-b5abc659d4ca" }, - "Get-Teis->Get-Locations": { + "Upsert-TEIs->Get-Encounters": { "enabled": true, - "id": "dd4d3b24-f3c2-4162-895e-970aea5a50dc", - "source_job_id": "be724c80-92c8-4fa9-8c3a-d28c5a298fd5", - "condition_expression": "state.trackedEntityInstances.length > 0", + "id": "79ca3ec3-641f-4167-8fe3-a96c40cc9954", + "source_job_id": "6973c510-b36d-4c42-82f5-b26d8cd36a57", + "condition_expression": "state.patientUuids.length > 0 && !state.errors", "condition_type": "js_expression", - "condition_label": "has-teis", - "target_job_id": "2c1dc59e-c8c0-409d-813f-d0eb3f812a07" + "condition_label": "has-patient-uuids", + "target_job_id": "8fb577e5-d068-4d47-8172-81f08153ced9" }, - "Get-Locations->Create-Patients": { + "Get-Encounters->Get-Options-Map": { "enabled": true, - "id": "e80f8963-3c31-48cc-8df4-6b6dd89fd616", - "source_job_id": "2c1dc59e-c8c0-409d-813f-d0eb3f812a07", - "condition_expression": "!state.errors && state.trackedEntityInstances.length > 0", - "condition_type": "on_job_success", - "target_job_id": "fd21a322-aca4-404f-8b5c-93f5f23336fc" + "id": "e0c3565e-a875-429c-8ce3-138df39fdf4c", + "source_job_id": "8fb577e5-d068-4d47-8172-81f08153ced9", + "condition_expression": "state.encounters.length > 0", + "condition_type": "js_expression", + "condition_label": "has-encounters", + "target_job_id": "175ac575-ea3d-470e-8faf-61de514e222e" }, - "Create-Patients->Update-Teis": { + "Get-TEIs->Create-Events": { "enabled": true, - "id": "eb140757-c73f-4f9f-83d6-0ac0c76cf4da", - "source_job_id": "fd21a322-aca4-404f-8b5c-93f5f23336fc", + "id": "32b04529-a796-461c-8a0a-a5e543ef535e", + "source_job_id": "99e52cef-d4f2-4c5e-8718-e240bb3deab3", + "condition_expression": "state.TEIs && !state.errors", + "condition_type": "js_expression", + "condition_label": "has-teis", + "target_job_id": "932645d8-ddb8-4d00-841e-7fe7af214837" + }, + "Get-Options-Map->Get-TEIs": { + "enabled": true, + "id": "eb6bf369-19b8-4608-86a7-95935831ee6e", + "source_job_id": "175ac575-ea3d-470e-8faf-61de514e222e", + "condition_expression": "!state.errors && state.encounters.length > 0", "condition_type": "on_job_success", - "target_job_id": "eed2a687-7ef3-4a38-819e-d50319874d03" - } - } - }, - "wf-3-generate-optsmap": { - "id": "29376a74-d299-4066-9e78-271ca1777734", - "name": "wf-3-generate-optsmap", - "inserted_at": "2024-10-01T10:40:51.613510Z", - "lock_version": 35, - "triggers": { - "webhook": { - "enabled": false, - "id": "f970fb25-0dd8-4a90-80ef-aa95b11d6277", - "type": "webhook" - } - }, - "jobs": { - "Fetch-OptionSets-Metadata": { - "id": "ad22c664-8138-4536-8e57-7c5d90139c62", - "name": "Fetch OptionSets Metadata", - "body": "\ngetValues('1OuR7laA7Oc2QnoiT8S3Thhf-HNh7uFY8ILLEu-idXuk', \n'optionsets_oct1')\n", - "adaptor": "@openfn/language-googlesheets@latest", - "project_credential_id": "1e8b261f-54f8-49d0-b504-d96fc8751665" + "target_job_id": "99e52cef-d4f2-4c5e-8718-e240bb3deab3" }, - "Key-Value-Pair": { - "id": "ba19bc93-8f07-480f-80df-ee3f0b0d27e0", - "name": "Key Value Pair", - "body": "fn((state) => {\n const [keys, ...rows] = state.data.values;\n state.data = rows.map((item) => {\n const obj = item.reduce((acc, value, idx) => {\n acc[keys[idx]] = value;\n return acc;\n }, {});\n\n return obj;\n });\n\n return state;\n});\n\nfn((state) => {\n const isValidValue = value => value !== \"\" && value !== \"NA\";\n const optsMap = state.data.filter(o =>\n isValidValue(o[\"External ID\"]) && isValidValue(o[\"DHIS2 DE full name\"])\n )\n .map((o) => {\n return {\n \"value.display - Answers\": o[\"Answers\"],\n \"value.uuid - External ID\": o[\"External ID\"],\n \"DHIS2 DE full name\": o[\"DHIS2 DE full name\"],\n \"DHIS2 DE UID\": o[\"DHIS2 DE UID\"],\n \"OptionSet name\": o[\"OptionSet name\"],\n \"DHIS2 Option Set UID\": o[\"DHIS2 Option Set name\"],\n \"DHIS2 Option name\": o[\"DHIS2 Option name\"],\n \"DHIS2 Option UID\": o[\"DHIS2 Option UID\"],\n \"DHIS2 Option Code\": o[\"DHIS2 Option code\"],\n };\n })\n\n return { optsMap };\n});\n", - "adaptor": "@openfn/language-common@latest", - "project_credential_id": null - } - }, - "edges": { - "webhook->Fetch-OptionSets-Metadata": { + "Get-Patients->Mappings": { "enabled": true, - "id": "0bbc2e2f-b56f-463e-85f6-fefb2c15bfe3", - "source_trigger_id": "f970fb25-0dd8-4a90-80ef-aa95b11d6277", - "condition_type": "always", - "target_job_id": "ad22c664-8138-4536-8e57-7c5d90139c62" + "id": "65613153-275c-4897-a6ad-256ad818358c", + "source_job_id": "ab326112-9cdd-4449-8611-b5abc659d4ca", + "condition_expression": "state.patients.length > 0 && !state.errors", + "condition_type": "js_expression", + "condition_label": "has-patients", + "target_job_id": "79b58ab5-cb0a-44a5-b230-776b4016464a" }, - "Fetch-OptionSets-Metadata->Key-Value-Pair": { + "Mappings->Upsert-TEIs": { "enabled": true, - "id": "1a95d2d5-7d2f-4608-80cc-ec0df2a0ffd7", - "source_job_id": "ad22c664-8138-4536-8e57-7c5d90139c62", + "id": "5619b87c-685d-45b7-b2b6-ef598018d360", + "source_job_id": "79b58ab5-cb0a-44a5-b230-776b4016464a", "condition_type": "on_job_success", - "target_job_id": "ba19bc93-8f07-480f-80df-ee3f0b0d27e0" - } - } - }, - "wf2-omrs-dhis2": { - "id": "0f8ec062-1a2d-4f13-a8c5-b8298004512c", - "name": "wf2-omrs-dhis2", - "inserted_at": "2024-10-01T10:42:03.411272Z", - "lock_version": 167, - "triggers": { - "cron": { - "enabled": false, - "id": "51283b68-c07a-4d85-854c-c2e6e93af041", - "type": "cron", - "cron_expression": "0 0 * * *" + "target_job_id": "6973c510-b36d-4c42-82f5-b26d8cd36a57" } }, + "concurrency": null, + "inserted_at": "2024-09-06T11:58:48Z", + "updated_at": "2024-10-01T11:42:17Z", "jobs": { "Get-Patients": { "id": "ab326112-9cdd-4449-8611-b5abc659d4ca", @@ -200,7 +131,7 @@ "Create-Events": { "id": "932645d8-ddb8-4d00-841e-7fe7af214837", "name": "Create Events", - "body": "const processAnswer = (answer, conceptUuid, dataElement, optsMap) => {\n // console.log('Has answer', conceptUuid, dataElement);\n return typeof answer.value === 'object'\n ? processObjectAnswer(answer, conceptUuid, dataElement, optsMap)\n : processOtherAnswer(answer, conceptUuid, dataElement);\n};\n\nconst processObjectAnswer = (answer, conceptUuid, dataElement, optsMap) => {\n if (isDiagnosisByPsychologist(conceptUuid, dataElement)) {\n return '' + answer.value.uuid === '278401ee-3d6f-4c65-9455-f1c16d0a7a98';\n }\n return findMatchingOption(answer, optsMap);\n};\n\nconst processOtherAnswer = (answer, conceptUuid, dataElement) => {\n if (isPhq9Score(answer.value, conceptUuid, dataElement)) {\n return getRangePhq(answer.value);\n }\n return answer.value;\n};\n\nconst processNoAnswer = (data, conceptUuid, dataElement) => {\n // console.log('No answer', conceptUuid, dataElement);\n if (isEncounterDate(conceptUuid, dataElement)) {\n return data.encounterDatetime.replace('+0000', '');\n }\n return '';\n};\n\nconst findMatchingOption = (answer, optsMap) => {\n const matchingOption = optsMap.find(\n o => o['value.uuid - External ID'] === answer.value.uuid\n )?.['DHIS2 Option Code'];\n\n return matchingOption || '';\n};\n\nconst isEncounterDate = (conceptUuid, dataElement) => {\n return (\n conceptUuid === 'encounter-date' &&\n ['CXS4qAJH2qD', 'I7phgLmRWQq', 'yUT7HyjWurN'].includes(dataElement)\n );\n};\n\nconst isDiagnosisByPsychologist = (conceptUuid, dataElement) =>\n conceptUuid === '722dd83a-c1cf-48ad-ac99-45ac131ccc96' &&\n dataElement === 'pN4iQH4AEzk';\n\nconst isPhq9Score = (value, conceptUuid, dataElement) =>\n typeof value === 'number' &&\n conceptUuid === '5f3d618e-5c89-43bd-8c79-07e4e98c2f23' &&\n dataElement === 'tsFOVnlc6lz';\n\nconst getRangePhq = input => {\n if (input >= 20) return '>20';\n if (input >= 15) return '15_19';\n if (input >= 10) return '10_14';\n if (input >= 5) return '5_9';\n return '0_4';\n};\n\nconst dataValuesMapping = (data, dataValueMap, optsMap) => {\n return Object.keys(dataValueMap)\n .map(dataElement => {\n const conceptUuid = dataValueMap[dataElement];\n const answer = data.obs.find(o => o.concept.uuid === conceptUuid);\n const value = answer\n ? processAnswer(answer, conceptUuid, dataElement, optsMap)\n : processNoAnswer(data, conceptUuid, dataElement);\n\n return { dataElement, value };\n })\n .filter(d => d);\n};\n\n// Prepare DHIS2 data model for create events\nfn(state => {\n state.encountersMapping = state.encounters.map(data => {\n const form = state.formMaps[data.form.uuid];\n const eventDate = data.encounterDatetime.replace('+0000', '');\n const { trackedEntity, enrollment } = state.TEIs[data.patient.uuid];\n\n const event = {\n program: 'w9MSPn5oSqp',\n orgUnit: 'OPjuJMZFLop',\n trackedEntityInstance: trackedEntity,\n enrollment,\n eventDate,\n };\n if (form) {\n return {\n ...event,\n programStage: form.programStage,\n dataValues: dataValuesMapping(data, form.dataValueMap, state.optsMap),\n };\n }\n });\n\n console.log(\n 'dhis2 events to import:: ',\n JSON.stringify(state.encountersMapping, null, 2)\n );\n\n return state;\n});\n\n//Create events for each encounter\n// each(\n// '$.encountersMapping[*]',\n// create('events', $.data, {\n// params: {\n// dataElementIdScheme: 'UID',\n// },\n// })\n// );\n\n// // Return only lastRunDateTime\n// fn(({ lastRunDateTime }) => ({ lastRunDateTime }));\n", + "body": "const processAnswer = (answer, conceptUuid, dataElement, optsMap) => {\n // console.log('Has answer', conceptUuid, dataElement);\n return typeof answer.value === 'object'\n ? processObjectAnswer(answer, conceptUuid, dataElement, optsMap)\n : processOtherAnswer(answer, conceptUuid, dataElement);\n};\n\nconst processObjectAnswer = (answer, conceptUuid, dataElement, optsMap) => {\n if (isDiagnosisByPsychologist(conceptUuid, dataElement)) {\n return '' + answer.value.uuid === '278401ee-3d6f-4c65-9455-f1c16d0a7a98';\n }\n return findMatchingOption(answer, optsMap);\n};\n\nconst processOtherAnswer = (answer, conceptUuid, dataElement) => {\n if (isPhq9Score(answer.value, conceptUuid, dataElement)) {\n return getRangePhq(answer.value);\n }\n return answer.value;\n};\n\nconst processNoAnswer = (data, conceptUuid, dataElement) => {\n // console.log('No answer', conceptUuid, dataElement);\n if (isEncounterDate(conceptUuid, dataElement)) {\n return data.encounterDatetime.replace('+0000', '');\n }\n return '';\n};\n\nconst findMatchingOption = (answer, optsMap) => {\n const matchingOption = optsMap.find(\n o => o['value.uuid - External ID'] === answer.value.uuid\n )?.['DHIS2 Option Code'];\n\n return matchingOption || '';\n};\n\nconst isEncounterDate = (conceptUuid, dataElement) => {\n return (\n conceptUuid === 'encounter-date' &&\n ['CXS4qAJH2qD', 'I7phgLmRWQq', 'yUT7HyjWurN'].includes(dataElement)\n );\n};\n\nconst isDiagnosisByPsychologist = (conceptUuid, dataElement) =>\n conceptUuid === '722dd83a-c1cf-48ad-ac99-45ac131ccc96' &&\n dataElement === 'pN4iQH4AEzk';\n\nconst isPhq9Score = (value, conceptUuid, dataElement) =>\n typeof value === 'number' &&\n conceptUuid === '5f3d618e-5c89-43bd-8c79-07e4e98c2f23' &&\n dataElement === 'tsFOVnlc6lz';\n\nconst getRangePhq = input => {\n if (input >= 20) return '>20';\n if (input >= 15) return '15_19';\n if (input >= 10) return '10_14';\n if (input >= 5) return '5_9';\n return '0_4';\n};\n\nconst dataValuesMapping = (data, dataValueMap, optsMap) => {\n return Object.keys(dataValueMap)\n .map(dataElement => {\n const conceptUuid = dataValueMap[dataElement];\n const answer = data.obs.find(o => o.concept.uuid === conceptUuid);\n const value = answer\n ? processAnswer(answer, conceptUuid, dataElement, optsMap)\n : processNoAnswer(data, conceptUuid, dataElement);\n\n return { dataElement, value };\n })\n .filter(d => d);\n};\n\n// Prepare DHIS2 data model for create events\nfn(state => {\n state.encountersMapping = state.encounters.map(data => {\n const form = state.formMaps[data.form.uuid];\n const eventDate = data.encounterDatetime.replace('+0000', '');\n const { trackedEntity, enrollment } = state.TEIs[data.patient.uuid];\n\n const event = {\n program: 'w9MSPn5oSqp',\n orgUnit: 'OPjuJMZFLop',\n trackedEntityInstance: trackedEntity,\n enrollment,\n eventDate,\n };\n if (form) {\n return {\n ...event,\n programStage: form.programStage,\n dataValues: dataValuesMapping(data, form.dataValueMap, state.optsMap),\n };\n }\n });\n\n console.log(\n 'dhis2 events to import:: ',\n JSON.stringify(state.encountersMapping, null, 2)\n );\n\n return state;\n});\n\n//Create events for each encounter\neach(\n '$.encountersMapping[*]',\n create('events', $.data, {\n params: {\n dataElementIdScheme: 'UID',\n },\n })\n);\n\n// Return only lastRunDateTime\nfn(({ lastRunDateTime }) => ({ lastRunDateTime }));\n", "adaptor": "@openfn/language-dhis2@5.0.1", "project_credential_id": "8a5ead9b-5f9e-49b1-9e9a-9dc3c4ccf72d" }, @@ -212,64 +143,142 @@ "project_credential_id": null } }, + "deleted_at": null, + "lock_version": 168, + "triggers": { + "cron": { + "enabled": false, + "id": "51283b68-c07a-4d85-854c-c2e6e93af041", + "type": "cron", + "cron_expression": "0 0 * * *" + } + } + }, + "wf1-dhis2-omrs-migration": { + "id": "94e04fb5-d5ae-45ad-be31-98b902f36861", + "name": "wf1-dhis2-omrs-migration", "edges": { - "cron->Get-Patients": { + "cron->Get-Teis": { "enabled": true, - "id": "7d239f46-635e-4b7f-8706-6a3d08d473db", - "source_trigger_id": "51283b68-c07a-4d85-854c-c2e6e93af041", + "id": "f54f198a-5fa1-4ee0-803f-35316e32ab92", + "source_trigger_id": "0e7d525f-c24a-4969-8131-397cc94a6065", "condition_type": "always", - "target_job_id": "ab326112-9cdd-4449-8611-b5abc659d4ca" + "target_job_id": "be724c80-92c8-4fa9-8c3a-d28c5a298fd5" }, - "Upsert-TEIs->Get-Encounters": { + "Get-Teis->Get-Locations": { "enabled": true, - "id": "79ca3ec3-641f-4167-8fe3-a96c40cc9954", - "source_job_id": "6973c510-b36d-4c42-82f5-b26d8cd36a57", - "condition_expression": "state.patientUuids.length > 0 && !state.errors", + "id": "dd4d3b24-f3c2-4162-895e-970aea5a50dc", + "source_job_id": "be724c80-92c8-4fa9-8c3a-d28c5a298fd5", + "condition_expression": "state.trackedEntityInstances.length > 0", "condition_type": "js_expression", - "condition_label": "has-patient-uuids", - "target_job_id": "8fb577e5-d068-4d47-8172-81f08153ced9" + "condition_label": "has-teis", + "target_job_id": "2c1dc59e-c8c0-409d-813f-d0eb3f812a07" }, - "Get-Encounters->Get-Options-Map": { + "Get-Locations->Create-Patients": { "enabled": true, - "id": "e0c3565e-a875-429c-8ce3-138df39fdf4c", - "source_job_id": "8fb577e5-d068-4d47-8172-81f08153ced9", - "condition_expression": "state.encounters.length > 0", - "condition_type": "js_expression", - "condition_label": "has-encounters", - "target_job_id": "175ac575-ea3d-470e-8faf-61de514e222e" + "id": "e80f8963-3c31-48cc-8df4-6b6dd89fd616", + "source_job_id": "2c1dc59e-c8c0-409d-813f-d0eb3f812a07", + "condition_expression": "!state.errors && state.trackedEntityInstances.length > 0", + "condition_type": "on_job_success", + "target_job_id": "fd21a322-aca4-404f-8b5c-93f5f23336fc" }, - "Get-Options-Map->Get-TEIs": { + "Create-Patients->Update-Teis": { "enabled": true, - "id": "eb6bf369-19b8-4608-86a7-95935831ee6e", - "source_job_id": "175ac575-ea3d-470e-8faf-61de514e222e", - "condition_expression": "!state.errors && state.encounters.length > 0", + "id": "eb140757-c73f-4f9f-83d6-0ac0c76cf4da", + "source_job_id": "fd21a322-aca4-404f-8b5c-93f5f23336fc", "condition_type": "on_job_success", - "target_job_id": "99e52cef-d4f2-4c5e-8718-e240bb3deab3" + "target_job_id": "eed2a687-7ef3-4a38-819e-d50319874d03" + } + }, + "concurrency": null, + "inserted_at": "2024-09-10T16:34:04Z", + "updated_at": "2024-10-01T07:13:00Z", + "jobs": { + "Get-Teis": { + "id": "be724c80-92c8-4fa9-8c3a-d28c5a298fd5", + "name": "Get Teis", + "body": "fn(state => {\n // const manualCursor = '2023-06-20T17:00:00.00';\n state.cursor = state.manualCursor || state.lastRunDateTime;\n console.log('Date cursor to filter TEI extract ::', state.cursor);\n\n return state;\n});\n\n// Get trackedEntityInstances that are \"active\" in the target program\nget(\n 'tracker/trackedEntities',\n {\n orgUnit: 'OPjuJMZFLop',\n program: 'w9MSPn5oSqp',\n programStatus: 'ACTIVE',\n },\n {},\n state => {\n const trackedEntityInstances = state.data.instances\n .filter(tei => tei.updatedAt >= state.cursor) //for testing\n //.filter(tei => tei.createdAt > state.cursor) //for prod\n //.slice(0, 1); //to limit 1 for testing\n const offset = 2; // GMT+2 (Geneva time)\n const currentDateTime = new Date();\n currentDateTime.setHours(currentDateTime.getHours() + offset);\n\n const lastRunDateTime = currentDateTime.toISOString().replace('Z', '');\n //console.log('TEI payload found before filter ::', JSON.stringify(state.data.instances, null, 2));\n console.log('# of TEIs found before filter ::', state.data.instances.length);\n //console.log('lastUpdated of TEI eWXRNHtmHB0 :: ', JSON.stringify(state.data.instances.filter(tei => tei.trackedEntity == 'eWXRNHtmHB0'), null, 2)); \n console.log('# of TEIs to migrate to OMRS ::', trackedEntityInstances.length);\n // console.log(\n // 'trackedEntityInstance IDs ::',\n // trackedEntityInstances.map(tei => tei.trackedEntityInstance)\n // );\n\n console.log('Next sync start date:', lastRunDateTime);\n return {\n ...state,\n // data: {},\n references: [],\n trackedEntityInstances,\n lastRunDateTime,\n };\n }\n);\n", + "adaptor": "@openfn/language-dhis2@latest", + "project_credential_id": "8a5ead9b-5f9e-49b1-9e9a-9dc3c4ccf72d" }, - "Get-TEIs->Create-Events": { + "Get-Locations": { + "id": "2c1dc59e-c8c0-409d-813f-d0eb3f812a07", + "name": "Get Locations", + "body": "get('optionGroups/kdef7pUey9f', {\n fields: 'id,displayName,options[id,displayName,code]',\n});\n\nfn(({ data, ...state }) => {\n state.locations = data;\n return state;\n});\n\nfn(state => {\n state.nationalityMap = {\n afghanistan: '84066564-253e-43d8-b141-76730cffa878',\n albania: 'db21f4f9-faf2-4358-8297-0ae76627b3b8',\n algeria: '5f6c017f-074c-46b3-92d0-d055e2094366',\n angola: '8a2e5a03-8a74-41ae-9a98-2310f9ce400d',\n anguilla: 'c911af8a-171c-4ee9-b1ff-934373e8a819',\n argentina: 'b83d24e8-34d8-4920-83c0-8ba014467ff4',\n armenia: '39f1652a-f2b7-4b65-a7e1-7097ac6cdef0',\n aruba: 'f3f1cba1-7c1e-4234-86a2-f27bb5964fee',\n azerbaijan: '29750013-0e35-47ca-8f77-9192a923fb07',\n bangladesh: 'a99de53c-ce76-4b1e-91b2-461094baf79e',\n belarus: '664baba4-c552-47b9-97c0-ff67dafd27d6',\n benin: 'cf863e31-bb38-48ed-90dd-f3dedcac304c',\n bhutan: 'd45a57c9-994f-4deb-8845-9b785860a2ec',\n bolivia: 'd8800d10-862b-42f1-8e22-cac1ce1bbcae',\n bosnia_and_herzegovina: '05d8f4ef-45eb-463d-b2f3-8a5a613ee6b9',\n botswana: '1304a0de-5b70-4d36-a873-e72a82963316',\n brazil: '353ff388-64e6-434c-b78f-ca9636390389',\n british_virgin_islands: 'b02c6d20-83a2-4947-8a7d-91d1f9c4d8a2',\n bulgaria: '91c85a62-2b02-483a-aefd-e29d368565fe',\n burkina_faso: '6c90c1ae-17a4-4e94-a267-4fba4c94efd8',\n burundi: '8a2ed0db-eaad-44bc-bf06-5cb1b2a3db0b',\n cambodia: '4fd14df8-8279-4dfa-bdd3-e1ab26bc0264',\n cameroon: '873552ac-9850-4cc1-ae09-17eb0fccf405',\n cape_verde: 'cfbc220a-1d6c-4469-bb6d-a8e3deb4f7e7',\n central_african_republic: '61a4c4a4-25c2-4459-a874-ec1d24f8323a',\n chad: '9e41e71c-f5d5-456c-a6f9-2129b8055bfc',\n chile: '05333883-44e9-4f57-836a-041391803007',\n china: '15016874-3e20-484a-baa8-9b94e1a3d358',\n colombia: 'a008dff8-ce96-4662-bf8a-372e43d424f0',\n comoros: '9d8738c8-40c2-4c66-aabb-ef176a20ffe8',\n costa_rica: 'fb52f8c9-40ec-4dc4-92a4-d465612de2ff',\n cote_divoire: '513cb36a-3f67-46ea-a789-fcdaca0e26f5',\n cuba: '147c2434-5d7e-420c-8053-ba623301f3f5',\n djibouti: 'cf5b334f-1c0f-41fc-ab54-53ff1e942830',\n dominica: 'f70e51e5-b76c-4c38-9bf2-ef8e1f308ce1',\n dominican_republic: 'ce72fc9b-619b-4c32-b865-600e888ad814',\n drc_congo: '8f6d3d2a-e09f-473b-99c9-e539f97ceab6',\n east_timor: '854f2f66-40e1-4a6a-9dee-09c832a52289',\n ecuador: 'f9810f9a-78a7-42a2-99e6-19c629642386',\n egypt: 'cc7343f8-9243-4d09-b378-58363850d624',\n el_salvador: '9a34935e-5a8a-45be-8ccd-cb23192e420f',\n equatorial_guinea: '7e591605-d723-4398-982a-8737af63a2dc',\n eritrea: 'c61f03c2-0d1f-444f-a974-0a61063aff71',\n ethiopia: '7478d375-014e-410e-a355-090143e88f5b',\n gabon: '9f46ae06-114a-47fa-8f8d-e9749f04da25',\n gambia: '5ec7ddd7-14a5-48ec-9e7c-8896d1010655',\n georgia: 'bc71788f-db69-4b6f-8d1c-57a74395bdd2',\n ghana: '2eb4ff46-d908-4148-9b0d-40ccfc1a655a',\n greece: 'b75d6bcc-fadf-4141-8d0f-2463154b89f7',\n guam: '51fa502b-98a3-4c42-b5fd-7b4d64489bb9',\n guatemala: '3725a4d2-b28f-466b-905a-bafeaeb75855',\n guinea: 'eeaff39c-8afd-43f7-b9a0-53729f5df1d8',\n guinea_bissau: '14e90203-9197-42ea-9222-acafd2fd6984',\n guyana: 'ba4dfa7e-f3cd-4e94-8ca7-6b96a93378a8',\n haiti: 'f76f7dcb-f82e-4257-a627-1685ff3f3586',\n honduras: 'cdd1336e-495b-4868-aace-57a84442d6fd',\n india: '378d0107-eb43-485d-930c-0704b4e5aa11',\n indonesia: '1cbe17e6-adc2-4680-bee0-54d94af75ebf',\n iran: 'b422270e-d8af-4a32-b523-742545a17a3f',\n iraq: '03aa7d6e-7656-48e4-8dc0-5e27706722c0',\n jordan: '842f963c-f84d-4076-a8db-337295fd9b91',\n kazakhstan: '6f6d0e78-2c81-411d-8d13-367e250dc110',\n kenya: 'ad351a33-8846-4cad-8195-b07b6041d4a5',\n kuwait: '4aee7a88-cda9-454e-9f25-4a6420270417',\n kyrgyzstan: 'ace3b851-042b-46a6-8fea-68aae042d614',\n laos: 'dfb01b39-c224-459e-b045-dd9461b9a1e5',\n lebanon: '7de78f22-f53e-48d2-923f-ae1e4d814f46',\n lesotho: 'b35b29c5-9bb7-4b40-ad33-29eecd28a9e6',\n liberia: 'a5fd61b4-fd27-433d-8428-7e88a7f27921',\n libya: '600c6af4-b767-423c-b942-7f06ca467258',\n macedonia: '5837cc40-9ab5-4088-91c8-ca6e4b57e903',\n madagascar: '3782bf3c-380e-4b60-b21a-38199073f112',\n malawi: 'e8b5f188-6a5c-43ae-b4a5-200abb13153e',\n malaysia: '3facca11-fbaa-4c40-8fac-4751d45c3f1b',\n mali: '3e844a47-526a-46f9-afea-1af9ff8690aa',\n martinique: '051ce04e-05e8-4430-8b75-3e499bbffbc8',\n mauritania: '8acb006b-8596-4a98-8177-acb4cb575956',\n mauritius: '17ced083-eb2a-4046-a713-26cabc7af95d',\n mayotte: '1af148fe-2698-4b89-bf7f-87e5c48b6848',\n mexico: '8381208f-01ca-4ed3-8f2c-f73ed1c316e3',\n moldova: 'f0e9c8b5-69b5-48df-8cb9-2d089ba04e46',\n mongolia: '9f341cb1-dcb5-4f6c-bd21-b57db01b4193',\n morocco: 'ef467a17-91e8-4124-a136-7ed8ff7c7d15',\n mozambique: '0916133b-4d93-4d60-9c20-e7ee3936f391',\n myanmar: 'e81ba700-f9fc-4ed0-b248-578a25717cdb',\n namibia: '0cb123dc-8810-4840-b6ab-6a527c5a79ef',\n nauru: '3386fe63-2158-4040-a502-9f65fd2079d3',\n nepal: 'fb01b01a-6775-423c-8012-7d43f587cb6c',\n new_caledonia: 'e67c072b-7707-491f-8c2e-13c914216b61',\n nicaragua: 'f6a9521c-596b-49f9-b914-67138e8c17e6',\n niger: '7561db90-a866-4443-93f4-95cac1d47e9c',\n nigeria: '4134651a-7f53-45fb-8bc6-7fed9cf36f51',\n north_korea: '4d3079e4-8568-48e6-9342-665896875a38',\n oman: '9b0af037-99d1-43b8-ac06-82137ec4b06d',\n other: 'Other',\n pakistan: 'f45d93c3-c9b0-4333-a5e6-299b7c425812',\n palestine: 'e2a19948-49aa-44c0-98ef-67ae1160ef43',\n panama: '1ef5a828-9d0d-4336-91ab-880d5dc0151c',\n papua_new_guinea: 'e1e6b451-d7fe-4954-b225-99b2de82a4c0',\n paraguay: 'd8412016-82f5-4801-a026-1bdc429850b7',\n peru: 'e74fa87f-8469-46b0-975f-6cb37c394564',\n philippines: 'bdbd5c9f-1f28-4f4d-a254-4a84f8bb2c8f',\n puerto_rico: '39fca1d0-d2e7-4b13-82bd-626fbec71252',\n republic_of_congo: '5db9afa5-b57e-4f45-8b1c-af766f14fc58',\n reunion: '1dae4b2d-50c9-4bf1-b25a-7063600a5e74',\n romania: '457e745e-ae97-463d-95a9-8d5689d3ca2b',\n rwanda: '6bc925a1-7699-496a-85b0-c290699381db',\n samoa: 'e03b381b-a7f4-40eb-964f-51571dc3c48c',\n sao_tome_and_principe: 'f66bbb42-684f-42d7-bfcd-95d586eb7dc9',\n saudi_arabia: 'fdf495a4-e60c-46f7-a8a2-61a216849086',\n senegal: 'ad948f1b-0733-4f8d-b049-d64289b43a10',\n serbia: 'd2e69cef-3bff-4220-ba91-a6a678fb606b',\n sierra_leone: 'ffba9caf-b6aa-4078-845e-578f7a7fd566',\n somalia: '99c8dccc-4dfa-4d30-86be-42a309ab431f',\n south_africa: '75882d62-1c55-480d-b411-8ca40c3307df',\n south_korea: '0603d6b9-334f-4443-ab60-7c5d457b95fc',\n south_sudan: 'f113e24e-2ea9-49a2-9b28-59241b9adb21',\n sri_lanka: 'b0031c01-d242-4410-b98b-cc1511590b85',\n sudan: '2f03a932-2b75-4e8b-9f44-0fcd83c75dc4',\n suriname: 'c65d3329-98d4-4dd7-89d3-141b70d00eb2',\n swaziland: '06a2703b-af17-4e44-83f5-6cc9a8a75320',\n switzerland: 'dcdcdc70-a006-4b0a-bac2-7de89b022b65',\n syria: '1e34ee55-ef9f-4386-bae6-6995555ded75',\n tajikistan: '34836c60-5449-48d6-b3c9-c0b3361b9f2c',\n tanzania: '050a8eb1-0d77-4f65-a2da-776a13bcd2a4',\n thailand: '289ac5bd-6434-4837-86bf-b54d22970ac8',\n togo: '6a583e64-869d-477d-a1c1-746320d45fc4',\n tonga: 'd381f06d-2365-4f40-948b-cfe90d8cb532',\n tunisia: '56be7864-fde6-4db3-8fa5-b9dd42cd9c53',\n turkey: '7429c779-1d3a-4aec-8256-d0b1637e1bd1',\n turkmenistan: '3ef17df5-299b-4385-9ea6-572df4b6f9ca',\n uganda: 'be3d11d3-446d-440c-a582-d01c7cbb0eda',\n ukraine: '38c99c8d-2b93-4848-a537-b1865a260bb2',\n unknown: 'Unknown',\n uruguay: 'c2e45baf-748b-4d7b-a391-ed6b802b6f94',\n uzbekistan: '60512350-d79b-41aa-aff0-1b28ca4aa5f1',\n venezuela: '557cea4a-0049-4b7a-b373-ed63f294a2a0',\n vietnam: '49509c5f-e533-48a8-bf06-86935e3376b2',\n western_sahara: '4086dfd2-f4f5-4107-93e8-07bee235af8f',\n yemen: '6a3214e0-f94b-414c-8148-968e24386671',\n zambia: '3ec0432d-ea37-4159-a658-29d6f07fe21a',\n zimbabwe: 'ce1b0d8d-0a2d-4f93-a6ed-64aca2fd0f45',\n };\n state.statusMap = {\n asylum_seeker: 'f921ffdd-72ca-4d58-a89b-1fa2e959d110',\n no_status: '2bacead2-f280-457c-9d28-e80e106f7d25',\n refugee: 'MSF-AAAAAA000000000000001929',\n single: '20b8524e-4c26-4fa0-81f0-fa23ebacc54d',\n married: 'MSF-AAAAAA000000000000001863',\n widowed: 'MSF-AAAAAA000000000000001864',\n divorced_separated: 'MSF-AAAAAA000000000000001865',\n concubine: '1060AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',\n not_applicable: 'MSF-AAAAAA000000000000001823',\n student: 'MSF-AAAAAA000000000000001871',\n permanent_employee: '4a18a820-f3a1-4bb7-9138-558a9ecc81da',\n occasional_employee: '2cb73bee-7f94-4695-89c7-c81187dbc90c',\n unemployed: 'MSF-AAAAAA000000000000001870',\n housewife: '9b14b4d4-b749-4acf-acfe-79c480f3c4b3',\n other: 'MSF-AAAAAA000000000000001329',\n unknown: '1067AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',\n idp: 'MSF-AAAAAA000000000000001930',\n internationally_displaced: '515c5abe-4172-4d0c-a991-0de2888228d7',\n non_displaced: 'bbdb287c-4ba1-4944-bd87-eb126c5f9d92',\n returnee: 'fc49acaa-ece2-4365-9dfb-70c2105de8b1',\n };\n return state;\n});\n", + "adaptor": "@openfn/language-dhis2@latest", + "project_credential_id": "8a5ead9b-5f9e-49b1-9e9a-9dc3c4ccf72d" + }, + "Create-Patients": { + "id": "fd21a322-aca4-404f-8b5c-93f5f23336fc", + "name": "Create Patients", + "body": "//Define gender options and prepare newPatientUuid and identifiers\nfn(state => {\n const genderOptions = {\n male: 'M',\n female: 'F',\n unknown: 'U',\n transgender_female: 'O',\n transgender_male: 'O',\n prefer_not_to_answer: 'O',\n gender_variant_non_conforming: 'O',\n };\n\n const identifiers = [];\n const newPatientUuid = [];\n\n const { trackedEntityInstances } = state;\n if (trackedEntityInstances.length > 0)\n console.log(\n '# of TEIs to send to OpenMRS: ',\n trackedEntityInstances.length\n );\n if (trackedEntityInstances.length === 0)\n console.log('No data fetched in step prior to sync.');\n\n return {\n ...state,\n genderOptions,\n newPatientUuid,\n identifiers,\n };\n});\n\n//First we generate a unique OpenMRS ID for each patient\neach(\n 'trackedEntityInstances[*]',\n post(\n 'idgen/identifiersource/8549f706-7e85-4c1d-9424-217d50a2988b/identifier',\n {}\n ).then(state => {\n state.identifiers.push(state.data.identifier);\n return state;\n })\n);\n\n// Then we map trackedEntityInstances to openMRS data model\nfn(state => {\n const {\n trackedEntityInstances,\n identifiers,\n genderOptions,\n nationalityMap,\n statusMap,\n locations,\n } = state;\n\n const getValueForCode = (attributes, code) => {\n const result = attributes.find(attribute => attribute.code === code);\n return result ? result.value : undefined;\n };\n\n const calculateDOB = age => {\n const currentDate = new Date();\n const currentYear = currentDate.getFullYear();\n const birthYear = currentYear - age;\n\n const birthday = new Date(\n birthYear,\n currentDate.getMonth(),\n currentDate.getDay()\n );\n\n return birthday.toISOString().replace(/\\.\\d+Z$/, '+0000');\n };\n\n state.patients = trackedEntityInstances.map((d, i) => {\n const patientNumber = getValueForCode(d.attributes, 'patient_number'); // Add random number for testing + Math.random()\n\n const nationality =\n nationalityMap[getValueForCode(d.attributes, 'origin_nationality')];\n const currentStatus =\n statusMap[getValueForCode(d.attributes, 'current_status')];\n const legalStatus =\n getValueForCode(d.attributes, 'legal_status') &&\n statusMap[getValueForCode(d.attributes, 'legal_status')];\n const maritalStatus =\n statusMap[getValueForCode(d.attributes, 'marital_status')];\n const employmentStatus =\n statusMap[getValueForCode(d.attributes, 'occupation')];\n\n const noOfChildren = d.attributes.find(\n a => a.attribute === 'SVoT2cVLd5O'\n )?.value;\n\n const lonlat = d.attributes.find(a => a.attribute === 'rBtrjV1Mqkz')?.value;\n const location = lonlat\n ? locations.options.find(o => o.code === lonlat)?.displayName\n : undefined;\n\n let countyDistrict, cityVillage;\n\n if (location) {\n const match = location.match(/^(.*?)\\s*\\((.*?)\\)/);\n if (match) {\n [, countyDistrict, cityVillage] = match;\n cityVillage = cityVillage.split('-')[0].trim(); // Remove country code and trim\n }\n }\n\n return {\n patientNumber,\n person: {\n age: getValueForCode(d.attributes, 'age'),\n gender: genderOptions[getValueForCode(d.attributes, 'sex')],\n birthdate:\n d.attributes.find(a => a.attribute === 'WDp4nVor9Z7')?.value ??\n calculateDOB(getValueForCode(d.attributes, 'age')),\n birthdateEstimated: d.attributes.find(\n a => a.attribute === 'WDp4nVor9Z7'\n )\n ? true\n : false,\n names: [\n {\n familyName:\n d.attributes.find(a => a.attribute === 'fa7uwpCKIwa')?.value ??\n 'unknown',\n givenName:\n d.attributes.find(a => a.attribute === 'Jt9BhFZkvP2')?.value ??\n 'unknown',\n },\n ],\n addresses: [\n {\n country: 'Iraq',\n stateProvince: 'Ninewa',\n countyDistrict,\n cityVillage,\n },\n ],\n attributes: [\n {\n attributeType: '24d1fa23-9778-4a8e-9f7b-93f694fc25e2',\n value: nationality,\n },\n {\n attributeType: 'e0b6ed99-72c4-4847-a442-e9929eac4a0f',\n value: currentStatus,\n },\n legalStatus && {\n attributeType: 'a9b2c642-097f-43f8-b96b-4d2f50ffd9b1',\n value: legalStatus,\n },\n {\n attributeType: '3884dc76-c271-4bcb-8df8-81c6fb897f53',\n value: maritalStatus,\n },\n employmentStatus && {\n attributeType: 'dd1f7f0f-ccea-4228-9aa8-a8c3b0ea4c3e',\n value: employmentStatus,\n },\n noOfChildren && {\n attributeType: 'e363161a-9d5c-4331-8463-238938f018ed',\n value: noOfChildren,\n },\n ].filter(i => i),\n },\n\n identifiers: [\n {\n identifier: identifiers[i], //map ID value from DHIS2 attribute\n identifierType: '05a29f94-c0ed-11e2-94be-8c13b969e334',\n location: 'cf6fa7d4-1f19-4c85-ac50-ff824805c51c', //default location old:44c3efb0-2583-4c80-a79e-1f756a03c0a1\n preferred: true,\n },\n {\n uuid: d.trackedEntity,\n identifier: patientNumber,\n identifierType: '8d79403a-c2cc-11de-8d13-0010c6dffd0f', //Old Identification number\n location: 'cf6fa7d4-1f19-4c85-ac50-ff824805c51c', //default location\n preferred: false, //default value for this identifiertype\n },\n ],\n };\n });\n\n return state;\n});\n\n// Creating patients in openMRS\neach(\n '$.patients[*]',\n upsert(\n 'patient',\n state => {\n return { q: state.data.patientNumber };\n },\n state => {\n const { patientNumber, ...patient } = state.data;\n console.log(\n 'Upserting patient record\\n',\n JSON.stringify(patient, null, 2)\n );\n return patient;\n },\n state => {\n state.newPatientUuid.push({\n patient_number: state.references.at(-1)?.patientNumber,\n uuid: state.data.uuid,\n });\n return state;\n }\n )\n);\n\n// Clean up state\nfn(({ data, references, ...state }) => state);\n", + "adaptor": "@openfn/language-openmrs@latest", + "project_credential_id": "3141d874-5456-4168-9680-ce04efb1089c" + }, + "Update-Teis": { + "id": "eed2a687-7ef3-4a38-819e-d50319874d03", + "name": "Update Teis", + "body": "fn(state => {\n if (state.newPatientUuid.length === 0) {\n console.log('No data fetched in step prior to sync.');\n }\n\n console.log(\n 'newPatientUuid ::',\n JSON.stringify(state.newPatientUuid, null, 2)\n );\n return state;\n});\n\n// Update TEI on DHIS2\neach(\n 'newPatientUuid[*]',\n upsert(\n 'trackedEntityInstances',\n state => ({\n ou: 'OPjuJMZFLop',\n program: 'w9MSPn5oSqp',\n filter: [`P4wdYGkldeG:Eq:${state.data.patient_number}`],\n }),\n {\n orgUnit: 'OPjuJMZFLop',\n program: 'w9MSPn5oSqp',\n trackedEntityType: 'cHlzCA2MuEF',\n attributes: [\n { attribute: 'P4wdYGkldeG', value: `${$.data.patient_number}` }, //DHIS2 patient number to use as lookup key\n { attribute: 'AYbfTPYMNJH', value: `${$.data.patient.uuid}` }, //OMRS patient uuid\n {\n attribute: 'ZBoxuExmxcZ',\n value: `${$.data.patient.identifier[0].identifier}`,\n }, //id generated in wf1-2 e.g., \"IQ146-24-000-027\"\n ],\n }\n )\n);\n", + "adaptor": "@openfn/language-dhis2@5.0.1", + "project_credential_id": "8a5ead9b-5f9e-49b1-9e9a-9dc3c4ccf72d" + } + }, + "deleted_at": null, + "lock_version": 41, + "triggers": { + "cron": { + "enabled": false, + "id": "0e7d525f-c24a-4969-8131-397cc94a6065", + "type": "cron", + "cron_expression": "0 0 * * *" + } + } + }, + "wf-3-generate-optsmap": { + "id": "29376a74-d299-4066-9e78-271ca1777734", + "name": "wf-3-generate-optsmap", + "edges": { + "webhook->Fetch-OptionSets-Metadata": { "enabled": true, - "id": "32b04529-a796-461c-8a0a-a5e543ef535e", - "source_job_id": "99e52cef-d4f2-4c5e-8718-e240bb3deab3", - "condition_expression": "state.TEIs && !state.errors", - "condition_type": "js_expression", - "condition_label": "has-teis", - "target_job_id": "932645d8-ddb8-4d00-841e-7fe7af214837" + "id": "0bbc2e2f-b56f-463e-85f6-fefb2c15bfe3", + "source_trigger_id": "f970fb25-0dd8-4a90-80ef-aa95b11d6277", + "condition_type": "always", + "target_job_id": "ad22c664-8138-4536-8e57-7c5d90139c62" }, - "Mappings->Upsert-TEIs": { + "Fetch-OptionSets-Metadata->Key-Value-Pair": { "enabled": true, - "id": "5619b87c-685d-45b7-b2b6-ef598018d360", - "source_job_id": "79b58ab5-cb0a-44a5-b230-776b4016464a", + "id": "1a95d2d5-7d2f-4608-80cc-ec0df2a0ffd7", + "source_job_id": "ad22c664-8138-4536-8e57-7c5d90139c62", "condition_type": "on_job_success", - "target_job_id": "6973c510-b36d-4c42-82f5-b26d8cd36a57" + "target_job_id": "ba19bc93-8f07-480f-80df-ee3f0b0d27e0" + } + }, + "concurrency": null, + "inserted_at": "2024-09-20T06:13:22Z", + "updated_at": "2024-10-01T10:40:51Z", + "jobs": { + "Fetch-OptionSets-Metadata": { + "id": "ad22c664-8138-4536-8e57-7c5d90139c62", + "name": "Fetch OptionSets Metadata", + "body": "\ngetValues('1OuR7laA7Oc2QnoiT8S3Thhf-HNh7uFY8ILLEu-idXuk', \n'optionsets_oct1')\n", + "adaptor": "@openfn/language-googlesheets@latest", + "project_credential_id": "1e8b261f-54f8-49d0-b504-d96fc8751665" }, - "Get-Patients->Mappings": { - "enabled": true, - "id": "65613153-275c-4897-a6ad-256ad818358c", - "source_job_id": "ab326112-9cdd-4449-8611-b5abc659d4ca", - "condition_expression": "state.patients.length > 0 && !state.errors", - "condition_type": "js_expression", - "condition_label": "has-patients", - "target_job_id": "79b58ab5-cb0a-44a5-b230-776b4016464a" + "Key-Value-Pair": { + "id": "ba19bc93-8f07-480f-80df-ee3f0b0d27e0", + "name": "Key Value Pair", + "body": "fn((state) => {\n const [keys, ...rows] = state.data.values;\n state.data = rows.map((item) => {\n const obj = item.reduce((acc, value, idx) => {\n acc[keys[idx]] = value;\n return acc;\n }, {});\n\n return obj;\n });\n\n return state;\n});\n\nfn((state) => {\n const isValidValue = value => value !== \"\" && value !== \"NA\";\n const optsMap = state.data.filter(o =>\n isValidValue(o[\"External ID\"]) && isValidValue(o[\"DHIS2 DE full name\"])\n )\n .map((o) => {\n return {\n \"value.display - Answers\": o[\"Answers\"],\n \"value.uuid - External ID\": o[\"External ID\"],\n \"DHIS2 DE full name\": o[\"DHIS2 DE full name\"],\n \"DHIS2 DE UID\": o[\"DHIS2 DE UID\"],\n \"OptionSet name\": o[\"OptionSet name\"],\n \"DHIS2 Option Set UID\": o[\"DHIS2 Option Set name\"],\n \"DHIS2 Option name\": o[\"DHIS2 Option name\"],\n \"DHIS2 Option UID\": o[\"DHIS2 Option UID\"],\n \"DHIS2 Option Code\": o[\"DHIS2 Option code\"],\n };\n })\n\n return { optsMap };\n});\n", + "adaptor": "@openfn/language-common@latest", + "project_credential_id": null + } + }, + "deleted_at": null, + "lock_version": 35, + "triggers": { + "webhook": { + "enabled": false, + "id": "f970fb25-0dd8-4a90-80ef-aa95b11d6277", + "type": "webhook" } } }