diff --git a/.github/workflows/migrate-prod.yml b/.github/workflows/migrate-prod.yml index e812f87..bd3ac5e 100644 --- a/.github/workflows/migrate-prod.yml +++ b/.github/workflows/migrate-prod.yml @@ -11,6 +11,7 @@ on: options: - staging - production + - qa event: description: 'The event to process (birth or death)' required: true @@ -34,7 +35,30 @@ jobs: with: ref: ${{ github.ref }} - # ADD VPN SETUP STEPS HERE + - name: Update apt + run: sudo apt update + + - name: Install openconnect + run: sudo apt install -y openconnect + + - name: Install virtualenv + run: | + sudo apt install virtualenvwrapper + sudo apt install virtualenv + virtualenv vpn-slice + source vpn-slice/bin/activate + pip3 install https://github.com/dlenski/vpn-slice/archive/master.zip + + - name: Connect to VPN + run: | + echo "${{ secrets.VPN_PWD }}" | sudo openconnect --syslog -u ${{ secrets.VPN_USER }} --passwd-on-stdin --protocol=${{ secrets.VPN_PROTOCOL }} ${{ secrets.VPN_HOST }}:${{ secrets.VPN_PORT }} --servercert ${{ secrets.VPN_SERVERCERT }} --background -v --no-dtls -s 'vpn-slice/bin/vpn-slice 10.17.0.0/24' + sleep 3 + ip_addr=$(ip -f inet addr show tun0 |sed -En -e 's/.*inet ([0-9.]+).*/\1/p') + sudo ip route add 10.17.30.0/24 via $ip_addr dev tun0 + + - name: Test VPN connection + run: | + ping -c4 ${{ vars.SSH_HOST || secrets.SSH_HOST }} - name: Install dependencies run: | diff --git a/v1-to-v2-data-migration/countryData/addressMappings.ts b/v1-to-v2-data-migration/countryData/addressMappings.ts index c7ad672..bca6da2 100644 --- a/v1-to-v2-data-migration/countryData/addressMappings.ts +++ b/v1-to-v2-data-migration/countryData/addressMappings.ts @@ -20,7 +20,7 @@ export const ADDRESS_MAPPINGS: Record = { 'child.birthLocation.privateHome': { administrativeArea: data }, }), 'birth.child.cityPlaceofbirth': (data: string) => ({ - 'child.birthLocation.privateHome': { streetLevelDetails: { town: data } }, + 'child.birthLocation.privateHome': { streetLevelDetails: { city: data } }, }), 'birth.child.addressLine1Placeofbirth': (data: string) => ({ 'child.birthLocation.privateHome': { @@ -40,39 +40,9 @@ export const ADDRESS_MAPPINGS: Record = { streetLevelDetails: { zipCode: data }, }, }), - 'birth.child.internationalStatePlaceofbirth': (data: string) => ({ - 'child.birthLocation.privateHome': { - streetLevelDetails: { state: data }, - }, - }), - 'birth.child.internationalDistrictPlaceofbirth': (data: string) => ({ - 'child.birthLocation.privateHome': { - streetLevelDetails: { district2: data }, - }, - }), 'birth.child.internationalCityPlaceofbirth': (data: string) => ({ 'child.birthLocation.privateHome': { - streetLevelDetails: { cityOrTown: data }, - }, - }), - 'birth.child.internationalAddressLine1Placeofbirth': (data: string) => ({ - 'child.birthLocation.privateHome': { - streetLevelDetails: { addressLine1: data }, - }, - }), - 'birth.child.internationalAddressLine2Placeofbirth': (data: string) => ({ - 'child.birthLocation.privateHome': { - streetLevelDetails: { addressLine2: data }, - }, - }), - 'birth.child.internationalAddressLine3Placeofbirth': (data: string) => ({ - 'child.birthLocation.privateHome': { - streetLevelDetails: { addressLine3: data }, - }, - }), - 'birth.child.internationalPostalCodePlaceofbirth': (data: string) => ({ - 'child.birthLocation.privateHome': { - streetLevelDetails: { postcodeOrZip: data }, + streetLevelDetails: { internationalCity: data }, }, }), @@ -96,18 +66,53 @@ export const ADDRESS_MAPPINGS: Record = { }, }), + // Birth - Child Address + 'birth.child.child-view-group.countryPrimaryChild': (data: string) => ({ + 'child.address': { country: data }, + }), + 'birth.child.child-view-group.statePrimaryChild': (data: string) => ({ + 'child.address': { + /* Ignore: Only map leaf level */ + }, + }), + 'birth.child.child-view-group.districtPrimaryChild': (data: string) => ({ + 'child.address': { administrativeArea: data }, + }), + 'birth.child.child-view-group.cityPrimaryChild': (data: string) => ({ + 'child.address': { streetLevelDetails: { city: data } }, + }), + 'birth.child.child-view-group.addressLine1PrimaryChild': (data: string) => ({ + 'child.address': { streetLevelDetails: { city: data } }, + }), + 'birth.child.child-view-group.addressLine2PrimaryChild': (data: string) => ({ + 'child.address': { streetLevelDetails: { number: data } }, + }), + 'birth.child.child-view-group.addressLine3PrimaryChild': (data: string) => ({ + 'child.address': { streetLevelDetails: { residentialArea: data } }, + }), + 'birth.child.child-view-group.postalCodePrimaryChild': (data: string) => ({ + 'child.address': { streetLevelDetails: { zipCode: data } }, + }), + 'birth.child.child-view-group.internationalCityPrimaryChild': ( + data: string + ) => ({ + 'child.address': { streetLevelDetails: { internationalCity: data } }, + }), + // Birth - Informant Address 'birth.informant.countryPrimaryInformant': (data: string) => ({ 'informant.address': { country: data }, }), 'birth.informant.statePrimaryInformant': (data: string) => ({ - 'informant.address': { streetLevelDetails: { state: data } }, + 'informant.address': { + /* Ignore: Only map leaf level */ + }, }), 'birth.informant.districtPrimaryInformant': (data: string) => ({ 'informant.address': { administrativeArea: data }, }), 'birth.informant.cityPrimaryInformant': (data: string) => ({ - 'informant.address': { streetLevelDetails: { town: data } }, + 'informant.address': { streetLevelDetails: { city: data } }, }), 'birth.informant.addressLine1PrimaryInformant': (data: string) => ({ 'informant.address': { streetLevelDetails: { residentialArea: data } }, @@ -123,36 +128,8 @@ export const ADDRESS_MAPPINGS: Record = { 'birth.informant.postalCodePrimaryInformant': (data: string) => ({ 'informant.address': { streetLevelDetails: { zipCode: data } }, }), - 'birth.informant.internationalStatePrimaryInformant': (data: string) => ({ - 'informant.address': { - streetLevelDetails: { state: data }, - }, - }), - 'birth.informant.internationalDistrictPrimaryInformant': (data: string) => ({ - 'informant.address': { streetLevelDetails: { district2: data } }, - }), 'birth.informant.internationalCityPrimaryInformant': (data: string) => ({ - 'informant.address': { streetLevelDetails: { cityOrTown: data } }, - }), - 'birth.informant.internationalAddressLine1PrimaryInformant': ( - data: string - ) => ({ - 'informant.address': { streetLevelDetails: { addressLine1: data } }, - }), - 'birth.informant.internationalAddressLine2PrimaryInformant': ( - data: string - ) => ({ - 'informant.address': { streetLevelDetails: { addressLine2: data } }, - }), - 'birth.informant.internationalAddressLine3PrimaryInformant': ( - data: string - ) => ({ - 'informant.address': { streetLevelDetails: { addressLine3: data } }, - }), - 'birth.informant.internationalPostalCodePrimaryInformant': ( - data: string - ) => ({ - 'informant.address': { streetLevelDetails: { postcodeOrZip: data } }, + 'informant.address': { streetLevelDetails: { internationalCity: data } }, }), // Birth - Informant Address (Urban/Rural Options) @@ -192,7 +169,7 @@ export const ADDRESS_MAPPINGS: Record = { 'mother.address': { administrativeArea: data }, }), 'birth.mother.cityPrimaryMother': (data: string) => ({ - 'mother.address': { streetLevelDetails: { town: data } }, + 'mother.address': { streetLevelDetails: { city: data } }, }), 'birth.mother.addressLine1PrimaryMother': (data: string) => ({ 'mother.address': { streetLevelDetails: { residentialArea: data } }, @@ -208,28 +185,8 @@ export const ADDRESS_MAPPINGS: Record = { 'birth.mother.postalCodePrimaryMother': (data: string) => ({ 'mother.address': { streetLevelDetails: { zipCode: data } }, }), - 'birth.mother.internationalStatePrimaryMother': (data: string) => ({ - 'mother.address': { - streetLevelDetails: { state: data }, - }, - }), - 'birth.mother.internationalDistrictPrimaryMother': (data: string) => ({ - 'mother.address': { streetLevelDetails: { district2: data } }, - }), 'birth.mother.internationalCityPrimaryMother': (data: string) => ({ - 'mother.address': { streetLevelDetails: { cityOrTown: data } }, - }), - 'birth.mother.internationalAddressLine1PrimaryMother': (data: string) => ({ - 'mother.address': { streetLevelDetails: { addressLine1: data } }, - }), - 'birth.mother.internationalAddressLine2PrimaryMother': (data: string) => ({ - 'mother.address': { streetLevelDetails: { addressLine2: data } }, - }), - 'birth.mother.internationalAddressLine3PrimaryMother': (data: string) => ({ - 'mother.address': { streetLevelDetails: { addressLine3: data } }, - }), - 'birth.mother.internationalPostalCodePrimaryMother': (data: string) => ({ - 'mother.address': { streetLevelDetails: { postcodeOrZip: data } }, + 'mother.address': { streetLevelDetails: { internationalCity: data } }, }), // Birth - Mother Address (Urban/Rural Options) @@ -261,7 +218,7 @@ export const ADDRESS_MAPPINGS: Record = { 'father.address': { administrativeArea: data }, }), 'birth.father.cityPrimaryFather': (data: string) => ({ - 'father.address': { streetLevelDetails: { town: data } }, + 'father.address': { streetLevelDetails: { city: data } }, }), 'birth.father.addressLine1PrimaryFather': (data: string) => ({ 'father.address': { streetLevelDetails: { residentialArea: data } }, @@ -277,28 +234,8 @@ export const ADDRESS_MAPPINGS: Record = { 'birth.father.postalCodePrimaryFather': (data: string) => ({ 'father.address': { streetLevelDetails: { zipCode: data } }, }), - 'birth.father.internationalStatePrimaryFather': (data: string) => ({ - 'father.address': { - streetLevelDetails: { state: data }, - }, - }), - 'birth.father.internationalDistrictPrimaryFather': (data: string) => ({ - 'father.address': { streetLevelDetails: { district2: data } }, - }), 'birth.father.internationalCityPrimaryFather': (data: string) => ({ - 'father.address': { streetLevelDetails: { cityOrTown: data } }, - }), - 'birth.father.internationalAddressLine1PrimaryFather': (data: string) => ({ - 'father.address': { streetLevelDetails: { addressLine1: data } }, - }), - 'birth.father.internationalAddressLine2PrimaryFather': (data: string) => ({ - 'father.address': { streetLevelDetails: { addressLine2: data } }, - }), - 'birth.father.internationalAddressLine3PrimaryFather': (data: string) => ({ - 'father.address': { streetLevelDetails: { addressLine3: data } }, - }), - 'birth.father.internationalPostalCodePrimaryFather': (data: string) => ({ - 'father.address': { streetLevelDetails: { postcodeOrZip: data } }, + 'father.address': { streetLevelDetails: { internationalCity: data } }, }), // Birth - Father Address (Urban/Rural Options) @@ -330,7 +267,7 @@ export const ADDRESS_MAPPINGS: Record = { 'deceased.address': { administrativeArea: data }, }), 'death.deceased.cityPrimaryDeceased': (data: string) => ({ - 'deceased.address': { streetLevelDetails: { town: data } }, + 'deceased.address': { streetLevelDetails: { city: data } }, }), 'death.deceased.addressLine1PrimaryDeceased': (data: string) => ({ 'deceased.address': { streetLevelDetails: { residentialArea: data } }, @@ -346,34 +283,8 @@ export const ADDRESS_MAPPINGS: Record = { 'death.deceased.postalCodePrimaryDeceased': (data: string) => ({ 'deceased.address': { streetLevelDetails: { zipCode: data } }, }), - 'death.deceased.internationalStatePrimaryDeceased': (data: string) => ({ - 'deceased.address': { - streetLevelDetails: { state: data }, - }, - }), - 'death.deceased.internationalDistrictPrimaryDeceased': (data: string) => ({ - 'deceased.address': { streetLevelDetails: { district2: data } }, - }), 'death.deceased.internationalCityPrimaryDeceased': (data: string) => ({ - 'deceased.address': { streetLevelDetails: { cityOrTown: data } }, - }), - 'death.deceased.internationalAddressLine1PrimaryDeceased': ( - data: string - ) => ({ - 'deceased.address': { streetLevelDetails: { addressLine1: data } }, - }), - 'death.deceased.internationalAddressLine2PrimaryDeceased': ( - data: string - ) => ({ - 'deceased.address': { streetLevelDetails: { addressLine2: data } }, - }), - 'death.deceased.internationalAddressLine3PrimaryDeceased': ( - data: string - ) => ({ - 'deceased.address': { streetLevelDetails: { addressLine3: data } }, - }), - 'death.deceased.internationalPostalCodePrimaryDeceased': (data: string) => ({ - 'deceased.address': { streetLevelDetails: { postcodeOrZip: data } }, + 'deceased.address': { streetLevelDetails: { internationalCity: data } }, }), // Death - Deceased Address (Urban/Rural Options) @@ -397,13 +308,15 @@ export const ADDRESS_MAPPINGS: Record = { 'eventDetails.deathLocationOther': { country: data }, }), 'death.deathEvent.statePlaceofdeath': (data: string) => ({ - 'eventDetails.deathLocationOther': { streetLevelDetails: { state: data } }, + 'eventDetails.deathLocationOther': { + /* Ignore: Only map leaf level */ + }, }), 'death.deathEvent.districtPlaceofdeath': (data: string) => ({ 'eventDetails.deathLocationOther': { administrativeArea: data }, }), 'death.deathEvent.cityPlaceofdeath': (data: string) => ({ - 'eventDetails.deathLocationOther': { streetLevelDetails: { town: data } }, + 'eventDetails.deathLocationOther': { streetLevelDetails: { city: data } }, }), 'death.deathEvent.addressLine1Placeofdeath': (data: string) => ({ 'eventDetails.deathLocationOther': { @@ -424,39 +337,9 @@ export const ADDRESS_MAPPINGS: Record = { streetLevelDetails: { zipCode: data }, }, }), - 'death.deathEvent.internationalStatePlaceofdeath': (data: string) => ({ - 'eventDetails.deathLocationOther': { - streetLevelDetails: { state: data }, - }, - }), - 'death.deathEvent.internationalDistrictPlaceofdeath': (data: string) => ({ - 'eventDetails.deathLocationOther': { - streetLevelDetails: { district2: data }, - }, - }), 'death.deathEvent.internationalCityPlaceofdeath': (data: string) => ({ 'eventDetails.deathLocationOther': { - streetLevelDetails: { cityOrTown: data }, - }, - }), - 'death.deathEvent.internationalAddressLine1Placeofdeath': (data: string) => ({ - 'eventDetails.deathLocationOther': { - streetLevelDetails: { addressLine1: data }, - }, - }), - 'death.deathEvent.internationalAddressLine2Placeofdeath': (data: string) => ({ - 'eventDetails.deathLocationOther': { - streetLevelDetails: { addressLine2: data }, - }, - }), - 'death.deathEvent.internationalAddressLine3Placeofdeath': (data: string) => ({ - 'eventDetails.deathLocationOther': { - streetLevelDetails: { addressLine3: data }, - }, - }), - 'death.deathEvent.internationalPostalCodePlaceofdeath': (data: string) => ({ - 'eventDetails.deathLocationOther': { - streetLevelDetails: { postcodeOrZip: data }, + streetLevelDetails: { internationalCity: data }, }, }), @@ -485,13 +368,15 @@ export const ADDRESS_MAPPINGS: Record = { 'informant.address': { country: data }, }), 'death.informant.statePrimaryInformant': (data: string) => ({ - 'informant.address': { streetLevelDetails: { state: data } }, + 'informant.address': { + /* Ignore: Only map leaf level */ + }, }), 'death.informant.districtPrimaryInformant': (data: string) => ({ 'informant.address': { administrativeArea: data }, }), 'death.informant.cityPrimaryInformant': (data: string) => ({ - 'informant.address': { streetLevelDetails: { town: data } }, + 'informant.address': { streetLevelDetails: { city: data } }, }), 'death.informant.addressLine1PrimaryInformant': (data: string) => ({ 'informant.address': { streetLevelDetails: { residentialArea: data } }, @@ -507,36 +392,8 @@ export const ADDRESS_MAPPINGS: Record = { 'death.informant.postalCodePrimaryInformant': (data: string) => ({ 'informant.address': { streetLevelDetails: { zipCode: data } }, }), - 'death.informant.internationalStatePrimaryInformant': (data: string) => ({ - 'informant.address': { - streetLevelDetails: { state: data }, - }, - }), - 'death.informant.internationalDistrictPrimaryInformant': (data: string) => ({ - 'informant.address': { streetLevelDetails: { district2: data } }, - }), 'death.informant.internationalCityPrimaryInformant': (data: string) => ({ - 'informant.address': { streetLevelDetails: { cityOrTown: data } }, - }), - 'death.informant.internationalAddressLine1PrimaryInformant': ( - data: string - ) => ({ - 'informant.address': { streetLevelDetails: { addressLine1: data } }, - }), - 'death.informant.internationalAddressLine2PrimaryInformant': ( - data: string - ) => ({ - 'informant.address': { streetLevelDetails: { addressLine2: data } }, - }), - 'death.informant.internationalAddressLine3PrimaryInformant': ( - data: string - ) => ({ - 'informant.address': { streetLevelDetails: { addressLine3: data } }, - }), - 'death.informant.internationalPostalCodePrimaryInformant': ( - data: string - ) => ({ - 'informant.address': { streetLevelDetails: { postcodeOrZip: data } }, + 'informant.address': { streetLevelDetails: { internationalCity: data } }, }), // Death - Informant Address (Urban/Rural Options) @@ -568,13 +425,15 @@ export const ADDRESS_MAPPINGS: Record = { 'spouse.address': { country: data }, }), 'death.spouse.statePrimarySpouse': (data: string) => ({ - 'spouse.address': { streetLevelDetails: { state: data } }, + 'spouse.address': { + /* Ignore: Only map leaf level */ + }, }), 'death.spouse.districtPrimarySpouse': (data: string) => ({ 'spouse.address': { administrativeArea: data }, }), 'death.spouse.cityPrimarySpouse': (data: string) => ({ - 'spouse.address': { streetLevelDetails: { town: data } }, + 'spouse.address': { streetLevelDetails: { city: data } }, }), 'death.spouse.addressLine1PrimarySpouse': (data: string) => ({ 'spouse.address': { streetLevelDetails: { residentialArea: data } }, @@ -590,28 +449,8 @@ export const ADDRESS_MAPPINGS: Record = { 'death.spouse.postalCodePrimarySpouse': (data: string) => ({ 'spouse.address': { streetLevelDetails: { zipCode: data } }, }), - 'death.spouse.internationalStatePrimarySpouse': (data: string) => ({ - 'spouse.address': { - streetLevelDetails: { state: data }, - }, - }), - 'death.spouse.internationalDistrictPrimarySpouse': (data: string) => ({ - 'spouse.address': { streetLevelDetails: { district2: data } }, - }), 'death.spouse.internationalCityPrimarySpouse': (data: string) => ({ - 'spouse.address': { streetLevelDetails: { cityOrTown: data } }, - }), - 'death.spouse.internationalAddressLine1PrimarySpouse': (data: string) => ({ - 'spouse.address': { streetLevelDetails: { addressLine1: data } }, - }), - 'death.spouse.internationalAddressLine2PrimarySpouse': (data: string) => ({ - 'spouse.address': { streetLevelDetails: { addressLine2: data } }, - }), - 'death.spouse.internationalAddressLine3PrimarySpouse': (data: string) => ({ - 'spouse.address': { streetLevelDetails: { addressLine3: data } }, - }), - 'death.spouse.internationalPostalCodePrimarySpouse': (data: string) => ({ - 'spouse.address': { streetLevelDetails: { postcodeOrZip: data } }, + 'spouse.address': { streetLevelDetails: { internationalCity: data } }, }), // Death - Spouse Address (Urban/Rural Options) diff --git a/v1-to-v2-data-migration/countryData/addressResolver.ts b/v1-to-v2-data-migration/countryData/addressResolver.ts index d0e60ec..c726872 100644 --- a/v1-to-v2-data-migration/countryData/addressResolver.ts +++ b/v1-to-v2-data-migration/countryData/addressResolver.ts @@ -1,7 +1,7 @@ import { AddressLine, EventRegistration } from '../helpers/types.ts' -export const COUNTRY_CODE = 'FAR' //Replace with actual country code -export const COUNTRY_PHONE_CODE = '+260' //Replace with actual country phone code +export const COUNTRY_CODE = 'SOM' //Replace with actual country code +export const COUNTRY_PHONE_CODE = '+252' //Replace with actual country phone code // Required to handle 2:1 mapping of birth location fields in corrections export const BIRTH_LOCATION_PRIVATE_HOME_KEY = 'birth.birthLocation.privateHome' @@ -9,26 +9,20 @@ export const BIRTH_LOCATION_OTHER_HOME_KEY = 'birth.birthLocation.otherHome' // Set up street level details as they are in your country config // src/form/street-address-configuration.ts -export interface Address { - addressType: 'INTERNATIONAL' | 'DOMESTIC' - country: string - administrativeArea?: string - streetLevelDetails: StreetLevelDetails -} - -export interface StreetLevelDetails { - state?: string - district2?: string - cityOrTown?: string - addressLine1?: string - addressLine2?: string - addressLine3?: string - postcodeOrZip?: string - town?: string +export type StreetLevelDetails = { + city?: string number?: string street?: string residentialArea?: string zipCode?: string + internationalCity?: string +} + +export interface Address { + addressType?: 'INTERNATIONAL' | 'DOMESTIC' + country?: string + administrativeArea?: string + streetLevelDetails?: StreetLevelDetails } export function resolveAddress( @@ -47,16 +41,7 @@ export function resolveAddress( addressType: 'INTERNATIONAL', country: address.country, streetLevelDetails: { - state: address.state, - district2: address.district, - cityOrTown: address.city, - addressLine1: lines[0], - addressLine2: lines[1], - addressLine3: lines.slice(2).join(', '), - postcodeOrZip: address.postalCode, - /* For potential custom field - kebele: getCustomField(data, 'birth.child.address.kebele'), - */ + internationalCity: address.city || '', }, } } @@ -66,11 +51,11 @@ export function resolveAddress( country: address.country, administrativeArea: address.district, streetLevelDetails: { - town: address.city, - number: lines[0], - street: lines[1], - residentialArea: lines[2], - zipCode: address.postalCode, + city: address.city || '', + number: address.line.filter(Boolean)[0] || '', + street: address.line.filter(Boolean)[1] || '', + residentialArea: address.line.filter(Boolean)[2] || '', + zipCode: address.postalCode || '', }, } } diff --git a/v1-to-v2-data-migration/countryData/countryMappings.ts b/v1-to-v2-data-migration/countryData/countryMappings.ts index d56484d..94e8d2b 100644 --- a/v1-to-v2-data-migration/countryData/countryMappings.ts +++ b/v1-to-v2-data-migration/countryData/countryMappings.ts @@ -6,4 +6,21 @@ {v1Field.customQuestionMappingId}: {v2Field.id} */ -export const COUNTRY_FIELD_MAPPINGS = {} +export const COUNTRY_FIELD_MAPPINGS = { + 'birth.child.iD': 'child.nid', + 'birth.child.child-view-group.birthAttendantName': 'child.attendantName', + 'birth.child.child-view-group.birthAttendantId': 'child.attedantAtBirthId', + 'birth.informant.informantID': 'informant.nid', + 'birth.mother.iD': 'mother.nid', + 'birth.father.iD': 'father.nid', + 'birth.documents.uploadDocOther': 'documents.proofOther', + 'death.deceased.deceased-view-group.placeOfBirth': 'deceased.placeOfBirth', + 'death.deceased.deceased-view-group.birthRegNo': 'deceased.brn', + 'death.deceased.deceasedID': 'deceased.nid', + 'death.deceased.deceased-view-group.occupation': 'deceased.occupation', + 'death.deathEvent.death-event-details.timeOfDeath': + 'eventDetails.timeOfDeath', + 'death.informant.informantID': 'informant.nid', + 'death.informant.informantType': 'informant.relation', + 'death.documents.uploadDocForInformant': 'documents.proofOfInformant', +} diff --git a/v1-to-v2-data-migration/countryData/countryResolvers.ts b/v1-to-v2-data-migration/countryData/countryResolvers.ts index a804799..0f60f59 100644 --- a/v1-to-v2-data-migration/countryData/countryResolvers.ts +++ b/v1-to-v2-data-migration/countryData/countryResolvers.ts @@ -1,6 +1,80 @@ -export const countryResolver = {} +import { getCustomField, getIdentifier } from '../helpers/resolverUtils.ts' +import { EventRegistration } from '../helpers/types.ts' +import { Address, COUNTRY_CODE, resolveAddress } from './addressResolver.ts' // The V1 response will populate both the informant and special informant fields // so we need to check if the informant is a special informant to avoid duplication export const birthSpecialInformants = ['MOTHER', 'FATHER'] -export const deathSpecialInformants = ['SPOUSE'] +export const deathSpecialInformants = [] + +const convertChildAddress = (data: EventRegistration): Address => { + const country = getCustomField( + data, + 'birth.child.child-view-group.countryPrimaryChild' + ) + + return { + addressType: country === COUNTRY_CODE ? 'DOMESTIC' : 'INTERNATIONAL', + country: country, + administrativeArea: getCustomField( + data, + 'birth.child.child-view-group.districtPrimaryChild' + ), + streetLevelDetails: { + city: getCustomField( + data, + 'birth.child.child-view-group.cityPrimaryChild' + ), + number: getCustomField( + data, + 'birth.child.child-view-group.addressLine1PrimaryChild' + ), + street: getCustomField( + data, + 'birth.child.child-view-group.addressLine2PrimaryChild' + ), + residentialArea: getCustomField( + data, + 'birth.child.child-view-group.addressLine3PrimaryChild' + ), + zipCode: getCustomField( + data, + 'birth.child.child-view-group.postalCodePrimaryChild' + ), + internationalCity: getCustomField( + data, + 'birth.child.child-view-group.internationalCityPrimaryChild' + ), + }, + } +} + +export const countryResolver = { + 'child.nid': (data: EventRegistration) => + getIdentifier(data.child, 'NATIONAL_ID'), + 'child.address': (data: EventRegistration) => convertChildAddress(data), + 'child.attendantName': (data: EventRegistration) => + getCustomField(data, 'birth.child.child-view-group.birthAttendantName'), + 'child.attedantAtBirthId': (data: EventRegistration) => + getCustomField(data, 'birth.child.child-view-group.birthAttendantId'), + 'child.birthLocation.privateHome': (data: EventRegistration) => + data.eventLocation?.type === 'PRIVATE_HOME' + ? resolveAddress(data, data.eventLocation?.address) + : null, + 'child.birthLocation.other': (data: EventRegistration) => + data.eventLocation?.type === 'OTHER' + ? resolveAddress(data, data.eventLocation?.address) + : null, + 'deceased.placeOfBirth': (data: EventRegistration) => + getCustomField(data, 'death.deceased.deceased-view-group.placeOfBirth'), + 'deceased.occupation': (data: EventRegistration) => + getCustomField(data, 'death.deceased.deceased-view-group.occupation'), + 'eventDetails.timeOfDeath': (data: EventRegistration) => + getCustomField(data, 'death.deathEvent.death-event-details.timeOfDeath'), + 'informant.relation': (data: EventRegistration) => + data.informant?.relationship, + 'eventDetails.date': (data: EventRegistration) => + data.deceased?.deceased?.deathDate, + 'deceased.brn': (data: EventRegistration) => + getCustomField(data, 'death.deceased.deceased-view-group.birthRegNo'), +} diff --git a/v1-to-v2-data-migration/helpers/defaultResolvers.ts b/v1-to-v2-data-migration/helpers/defaultResolvers.ts index 9f86282..60beee0 100644 --- a/v1-to-v2-data-migration/helpers/defaultResolvers.ts +++ b/v1-to-v2-data-migration/helpers/defaultResolvers.ts @@ -13,6 +13,17 @@ import { EventRegistration, ResolverMap } from './types.ts' import { resolveName } from '../countryData/nameResolver.ts' import { getCustomFieldVerificationStatus } from '../countryData/verificationResolver.ts' +function mapMannerOfDeath(mannerOfDeath: string | undefined): any { + const mannerMap = { + NATURAL_CAUSES: 'MANNER_NATURAL', + ACCIDENT: 'MANNER_ACCIDENT', + HOMICIDE: 'MANNER_HOMICIDE', + SUICIDE: 'MANNER_SUICIDE', + MANNER_UNDETERMINED: 'MANNER_UNDETERMINED', + } + return mannerMap[mannerOfDeath as keyof typeof mannerMap] +} + const informantResolver: ResolverMap = { 'informant.dob': (data: EventRegistration, eventType: 'birth' | 'death') => !isSpecialInformant(data.informant, eventType) @@ -114,17 +125,6 @@ const documentsResolver: ResolverMap = { getDocuments(data, 'DECEASED_DEATH_CAUSE_PROOF'), } -function mapMannerOfDeath(mannerOfDeath: string | undefined): any { - const mannerMap = { - NATURAL_CAUSES: 'MANNER_NATURAL', - ACCIDENT: 'MANNER_ACCIDENT', - HOMICIDE: 'MANNER_HOMICIDE', - SUICIDE: 'MANNER_SUICIDE', - MANNER_UNDETERMINED: 'MANNER_UNDETERMINED', - } - return mannerMap[mannerOfDeath as keyof typeof mannerMap] -} - export const defaultDeathResolver: ResolverMap = { 'deceased.name': (data: EventRegistration) => resolveName(data, data.deceased?.name?.[0]), diff --git a/v1-to-v2-data-migration/tests/SOM/address.test.ts b/v1-to-v2-data-migration/tests/SOM/address.test.ts new file mode 100644 index 0000000..e447d0b --- /dev/null +++ b/v1-to-v2-data-migration/tests/SOM/address.test.ts @@ -0,0 +1,350 @@ +import { transform } from '../../helpers/transform.ts' +import { assertEquals } from 'https://deno.land/std@0.210.0/assert/mod.ts' +import { + buildBirthResolver, + buildBirthEventRegistration, + buildDeathResolver, + buildDeathEventRegistration, +} from '../utils/testHelpers.ts' + +// Construct resolvers as in migrate.ipynb +const birthResolver = buildBirthResolver() +const deathResolver = buildDeathResolver() + +Deno.test('SOM address tests - birth events', async (t) => { + await t.step( + 'should resolve child.birthLocation.privateHome for PRIVATE_HOME', + () => { + const registration = buildBirthEventRegistration({ + eventLocation: { + type: 'PRIVATE_HOME', + address: { + line: ['123', 'Main St', 'City', '', '', 'URBAN'], + district: 'District1', + state: 'State1', + city: 'City1', + country: 'SOM', + postalCode: '12345', + }, + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['child.birthLocation.privateHome'] + ?.administrativeArea, + 'District1' + ) + assertEquals( + declareAction?.declaration['child.birthLocation.privateHome']?.country, + 'SOM' + ) + } + ) + + await t.step('should resolve child.birthLocation.other for OTHER', () => { + const registration = buildBirthEventRegistration({ + eventLocation: { + type: 'OTHER', + address: { + line: ['456', 'Other St', 'Town'], + district: 'District2', + state: 'State2', + city: 'City2', + country: 'SOM', + postalCode: '54321', + }, + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['child.birthLocation.other'] + ?.administrativeArea, + 'District2' + ) + }) + + await t.step('should resolve mother.address', () => { + const registration = buildBirthEventRegistration({ + mother: { + address: [ + { + type: 'PRIMARY_ADDRESS', + line: ['10', 'Mother St', 'City', '', '', 'URBAN'], + country: 'SOM', + district: 'District1', + state: 'State1', + city: 'City1', + postalCode: '11111', + }, + ], + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['mother.address']?.country, 'SOM') + assertEquals( + declareAction?.declaration['mother.address']?.administrativeArea, + 'District1' + ) + }) + + await t.step('should resolve father.address', () => { + const registration = buildBirthEventRegistration({ + father: { + address: [ + { + type: 'PRIMARY_ADDRESS', + line: ['20', 'Father Ave', 'Town'], + country: 'SOM', + district: 'District2', + state: 'State2', + city: 'City2', + postalCode: '22222', + }, + ], + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['father.address']?.country, 'SOM') + assertEquals( + declareAction?.declaration['father.address']?.administrativeArea, + 'District2' + ) + }) + + await t.step( + 'should resolve father.addressSameAs when addresses match', + () => { + const sameAddress = { + type: 'PRIMARY_ADDRESS' as const, + line: ['10', 'Same St', 'City'], + country: 'SOM', + district: 'District1', + state: 'State1', + city: 'City1', + postalCode: '11111', + } + + const registration = buildBirthEventRegistration({ + mother: { address: [sameAddress] }, + father: { address: [sameAddress] }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['father.addressSameAs'], 'YES') + } + ) + + await t.step( + 'should resolve father.addressSameAs when addresses differ', + () => { + const registration = buildBirthEventRegistration({ + mother: { + address: [ + { + type: 'PRIMARY_ADDRESS', + line: ['10', 'Mother St'], + country: 'SOM', + district: 'District1', + }, + ], + }, + father: { + address: [ + { + type: 'PRIMARY_ADDRESS', + line: ['20', 'Father Ave'], + country: 'SOM', + district: 'District2', + }, + ], + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['father.addressSameAs'], 'NO') + } + ) + + await t.step( + 'should resolve informant.address for non-special informant', + () => { + const registration = buildBirthEventRegistration({ + informant: { + relationship: 'GRANDFATHER', + address: [ + { + type: 'PRIMARY_ADDRESS', + line: ['30', 'Informant Rd'], + country: 'SOM', + district: 'District3', + state: 'State3', + city: 'City3', + postalCode: '33333', + }, + ], + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['informant.address']?.administrativeArea, + 'District3' + ) + } + ) +}) + +Deno.test('SOM address tests - death events', async (t) => { + await t.step('should resolve deceased.address', () => { + const data = buildDeathEventRegistration() + const result = transform(data, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['deceased.address']?.country, 'SOM') + assertEquals( + declareAction?.declaration['deceased.address']?.administrativeArea, + 'District1' + ) + }) + + await t.step( + 'should resolve eventDetails.deathLocationOther for OTHER', + () => { + const data = buildDeathEventRegistration({ + eventLocation: { + id: 'other-location', + type: 'OTHER', + address: { + line: ['999 Death St'], + district: 'DistrictX', + state: 'StateX', + country: 'SOM', + }, + }, + }) + const result = transform(data, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['eventDetails.deathLocationOther']?.country, + 'SOM' + ) + } + ) + + await t.step( + 'should resolve informant.addressSameAs when addresses match', + () => { + const sharedAddress = { + type: 'PRIMARY_ADDRESS', + line: ['Same St'], + district: 'District1', + state: 'State1', + country: 'SOM', + } + const data = buildDeathEventRegistration({ + deceased: { + ...buildDeathEventRegistration().deceased!, + address: [sharedAddress], + }, + informant: { + ...buildDeathEventRegistration().informant!, + address: [sharedAddress], + }, + }) + const result = transform(data, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['informant.addressSameAs'], 'YES') + } + ) + + await t.step( + 'should resolve informant.addressSameAs when addresses differ', + () => { + const data = buildDeathEventRegistration() + const result = transform(data, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['informant.addressSameAs'], 'NO') + } + ) + + await t.step( + 'should resolve informant.address for non-special informant', + () => { + const data = buildDeathEventRegistration() + const result = transform(data, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['informant.address']?.country, + 'SOM' + ) + } + ) + + await t.step('should resolve spouse.address', () => { + const data = buildDeathEventRegistration() + const result = transform(data, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['spouse.address']?.country, 'SOM') + }) + + await t.step( + 'should resolve spouse.addressSameAs when addresses match', + () => { + const sharedAddress = { + type: 'PRIMARY_ADDRESS', + line: ['Same St'], + district: 'District1', + state: 'State1', + country: 'SOM', + } + const data = buildDeathEventRegistration({ + deceased: { + ...buildDeathEventRegistration().deceased!, + address: [sharedAddress], + }, + spouse: { + ...buildDeathEventRegistration().spouse!, + address: [sharedAddress], + }, + }) + const result = transform(data, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['spouse.addressSameAs'], 'YES') + } + ) + + await t.step( + 'should resolve spouse.addressSameAs when addresses differ', + () => { + const data = buildDeathEventRegistration() + const result = transform(data, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['spouse.addressSameAs'], 'NO') + } + ) +}) diff --git a/v1-to-v2-data-migration/tests/SOM/childFields.test.ts b/v1-to-v2-data-migration/tests/SOM/childFields.test.ts new file mode 100644 index 0000000..c95ad12 --- /dev/null +++ b/v1-to-v2-data-migration/tests/SOM/childFields.test.ts @@ -0,0 +1,314 @@ +import { transform } from '../../helpers/transform.ts' +import { assertEquals } from 'https://deno.land/std@0.210.0/assert/mod.ts' +import { + buildBirthResolver, + buildBirthEventRegistration, +} from '../utils/testHelpers.ts' + +// Construct resolver as in migrate.ipynb +const birthResolver = buildBirthResolver() + +Deno.test('SOM child fields tests', async (t) => { + await t.step('should resolve child.nid when NATIONAL_ID is present', () => { + const registration = buildBirthEventRegistration({ + child: { + identifier: [ + { + type: 'NATIONAL_ID', + id: 'NID123456', + }, + ], + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['child.nid'], 'NID123456') + }) + + await t.step('should not resolve child.nid when no NATIONAL_ID', () => { + const registration = buildBirthEventRegistration({ + child: { + identifier: [ + { + type: 'BIRTH_REGISTRATION_NUMBER', + id: 'BRN123456', + }, + ], + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['child.nid'], undefined) + }) + + await t.step('should resolve child.attendantName', () => { + const registration = buildBirthEventRegistration({ + questionnaire: [ + { + fieldId: 'birth.child.child-view-group.birthAttendantName', + value: 'Dr. Smith Attendant', + }, + ], + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['child.attendantName'], + 'Dr. Smith Attendant' + ) + }) + + await t.step('should resolve child.attedantAtBirthId', () => { + const registration = buildBirthEventRegistration({ + questionnaire: [ + { + fieldId: 'birth.child.child-view-group.birthAttendantId', + value: 'ATTENDANT12345', + }, + ], + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['child.attedantAtBirthId'], + 'ATTENDANT12345' + ) + }) + + await t.step('should resolve custom child address for domestic', () => { + const registration = buildBirthEventRegistration({ + questionnaire: [ + { + fieldId: 'birth.child.child-view-group.countryPrimaryChild', + value: 'SOM', + }, + { + fieldId: 'birth.child.child-view-group.districtPrimaryChild', + value: 'Banadir', + }, + { + fieldId: 'birth.child.child-view-group.cityPrimaryChild', + value: 'Mogadishu', + }, + { + fieldId: 'birth.child.child-view-group.addressLine1PrimaryChild', + value: '123', + }, + { + fieldId: 'birth.child.child-view-group.addressLine2PrimaryChild', + value: 'Main St', + }, + { + fieldId: 'birth.child.child-view-group.addressLine3PrimaryChild', + value: 'Residential Area', + }, + { + fieldId: 'birth.child.child-view-group.postalCodePrimaryChild', + value: '12345', + }, + ], + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['child.address']?.addressType, + 'DOMESTIC' + ) + assertEquals(declareAction?.declaration['child.address']?.country, 'SOM') + assertEquals( + declareAction?.declaration['child.address']?.administrativeArea, + 'Banadir' + ) + assertEquals( + declareAction?.declaration['child.address']?.streetLevelDetails?.city, + 'Mogadishu' + ) + assertEquals( + declareAction?.declaration['child.address']?.streetLevelDetails?.number, + '123' + ) + assertEquals( + declareAction?.declaration['child.address']?.streetLevelDetails?.street, + 'Main St' + ) + assertEquals( + declareAction?.declaration['child.address']?.streetLevelDetails + ?.residentialArea, + 'Residential Area' + ) + assertEquals( + declareAction?.declaration['child.address']?.streetLevelDetails?.zipCode, + '12345' + ) + }) + + await t.step('should resolve custom child address for international', () => { + const registration = buildBirthEventRegistration({ + questionnaire: [ + { + fieldId: 'birth.child.child-view-group.countryPrimaryChild', + value: 'KEN', + }, + { + fieldId: 'birth.child.child-view-group.districtPrimaryChild', + value: 'Nairobi', + }, + { + fieldId: 'birth.child.child-view-group.internationalCityPrimaryChild', + value: 'Nairobi City', + }, + ], + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['child.address']?.addressType, + 'INTERNATIONAL' + ) + assertEquals(declareAction?.declaration['child.address']?.country, 'KEN') + assertEquals( + declareAction?.declaration['child.address']?.administrativeArea, + 'Nairobi' + ) + assertEquals( + declareAction?.declaration['child.address']?.streetLevelDetails + ?.internationalCity, + 'Nairobi City' + ) + }) + + await t.step( + 'should resolve child.birthLocation.privateHome for PRIVATE_HOME', + () => { + const registration = buildBirthEventRegistration({ + eventLocation: { + type: 'PRIVATE_HOME', + address: { + line: ['123', 'Main St', 'Residential Area', '', '', 'URBAN'], + district: 'Banadir', + state: 'Banadir', + city: 'Mogadishu', + country: 'SOM', + postalCode: '12345', + }, + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['child.birthLocation.privateHome'] + ?.addressType, + 'DOMESTIC' + ) + assertEquals( + declareAction?.declaration['child.birthLocation.privateHome']?.country, + 'SOM' + ) + assertEquals( + declareAction?.declaration['child.birthLocation.privateHome'] + ?.administrativeArea, + 'Banadir' + ) + assertEquals( + declareAction?.declaration['child.birthLocation.privateHome'] + ?.streetLevelDetails?.city, + 'Mogadishu' + ) + } + ) + + await t.step( + 'should not resolve child.birthLocation.privateHome for non-PRIVATE_HOME', + () => { + const registration = buildBirthEventRegistration({ + eventLocation: { + type: 'HEALTH_FACILITY', + address: { + line: ['456 Hospital Rd'], + district: 'Banadir', + country: 'SOM', + }, + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['child.birthLocation.privateHome'], + undefined + ) + } + ) + + await t.step('should resolve child.birthLocation.other for OTHER', () => { + const registration = buildBirthEventRegistration({ + eventLocation: { + type: 'OTHER', + address: { + line: ['789', 'Other St', 'Area'], + district: 'Lower Shabelle', + state: 'Lower Shabelle', + city: 'Afgooye', + country: 'SOM', + postalCode: '54321', + }, + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['child.birthLocation.other']?.addressType, + 'DOMESTIC' + ) + assertEquals( + declareAction?.declaration['child.birthLocation.other']?.country, + 'SOM' + ) + assertEquals( + declareAction?.declaration['child.birthLocation.other'] + ?.administrativeArea, + 'Lower Shabelle' + ) + }) + + await t.step( + 'should not resolve child.birthLocation.other for non-OTHER', + () => { + const registration = buildBirthEventRegistration({ + eventLocation: { + type: 'HEALTH_FACILITY', + address: { + line: ['456 Hospital Rd'], + district: 'Banadir', + country: 'SOM', + }, + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['child.birthLocation.other'], + undefined + ) + } + ) +}) diff --git a/v1-to-v2-data-migration/tests/SOM/corrections.test.ts b/v1-to-v2-data-migration/tests/SOM/corrections.test.ts new file mode 100644 index 0000000..96386ea --- /dev/null +++ b/v1-to-v2-data-migration/tests/SOM/corrections.test.ts @@ -0,0 +1,307 @@ +import { transform } from '../../helpers/transform.ts' +import { + buildBirthResolver, + buildDeathResolver, + buildBirthEventRegistration, + buildDeathEventRegistration, +} from '../utils/testHelpers.ts' +import { assertEquals } from 'https://deno.land/std@0.210.0/assert/mod.ts' + +Deno.test('SOM Corrections - Address Fields', async (t) => { + const birthResolver = buildBirthResolver() + const deathResolver = buildDeathResolver() + + await t.step('should transform address field corrections in birth', () => { + const registration = buildBirthEventRegistration({ + history: [ + { + date: '2024-01-01T10:00:00Z', + regStatus: 'DECLARED', + user: { id: 'user1', role: { id: 'FIELD_AGENT' } }, + office: { id: 'office1' }, + }, + { + date: '2024-01-02T12:00:00Z', + action: 'REQUESTED_CORRECTION', + user: { id: 'user2', role: { id: 'REGISTRATION_AGENT' } }, + office: { id: 'office1' }, + input: [ + { + valueCode: 'mother', + valueId: 'internationalCityPrimaryMother', + value: 'OldInternationalCity', + }, + { + valueCode: 'mother', + valueId: 'cityPrimaryMother', + value: 'OldCity', + }, + ], + output: [ + { + valueCode: 'mother', + valueId: 'internationalCityPrimaryMother', + value: 'NewInternationalCity', + }, + { + valueCode: 'mother', + valueId: 'cityPrimaryMother', + value: 'NewCity', + }, + { + valueCode: 'mother', + valueId: 'addressLine1PrimaryMother', + value: 'ResidentialArea', + }, + ], + }, + ], + }) + + const result = transform(registration, birthResolver, 'birth') + const correctionAction = result.actions.find( + (a) => a.type === 'REQUEST_CORRECTION' + ) + + assertEquals( + correctionAction?.declaration?.['mother.address']?.streetLevelDetails + ?.internationalCity, + 'NewInternationalCity' + ) + assertEquals( + correctionAction?.declaration?.['mother.address']?.streetLevelDetails + ?.city, + 'NewCity' + ) + assertEquals( + correctionAction?.declaration?.['mother.address']?.streetLevelDetails + ?.residentialArea, + 'ResidentialArea' + ) + assertEquals( + correctionAction?.annotation?.['mother.address']?.streetLevelDetails + ?.internationalCity, + 'OldInternationalCity' + ) + assertEquals( + correctionAction?.annotation?.['mother.address']?.streetLevelDetails + ?.city, + 'OldCity' + ) + }) + + await t.step('should transform death location address corrections', () => { + const registration = buildDeathEventRegistration({ + history: [ + { + date: '2024-01-01T10:00:00Z', + regStatus: 'DECLARED', + user: { id: 'user1', role: { id: 'FIELD_AGENT' } }, + office: { id: 'office1' }, + }, + { + date: '2024-01-02T12:00:00Z', + action: 'REQUESTED_CORRECTION', + user: { id: 'user2', role: { id: 'REGISTRATION_AGENT' } }, + office: { id: 'office1' }, + input: [ + { + valueCode: 'deathEvent', + valueId: 'internationalCityPlaceofdeath', + value: 'OldInternationalCity', + }, + { + valueCode: 'deathEvent', + valueId: 'cityPlaceofdeath', + value: 'OldCity', + }, + ], + output: [ + { + valueCode: 'deathEvent', + valueId: 'internationalCityPlaceofdeath', + value: 'NewInternationalCity', + }, + { + valueCode: 'deathEvent', + valueId: 'cityPlaceofdeath', + value: 'NewCity', + }, + ], + }, + ], + }) + + const result = transform(registration, deathResolver, 'death') + const correctionAction = result.actions.find( + (a) => a.type === 'REQUEST_CORRECTION' + ) + + assertEquals( + correctionAction?.declaration?.['eventDetails.deathLocationOther'] + ?.streetLevelDetails?.internationalCity, + 'NewInternationalCity' + ) + assertEquals( + correctionAction?.declaration?.['eventDetails.deathLocationOther'] + ?.streetLevelDetails?.city, + 'NewCity' + ) + assertEquals( + correctionAction?.annotation?.['eventDetails.deathLocationOther'] + ?.streetLevelDetails?.internationalCity, + 'OldInternationalCity' + ) + assertEquals( + correctionAction?.annotation?.['eventDetails.deathLocationOther'] + ?.streetLevelDetails?.city, + 'OldCity' + ) + }) + + await t.step( + 'should transform informant address corrections in death', + () => { + const registration = buildDeathEventRegistration({ + history: [ + { + date: '2024-01-01T10:00:00Z', + regStatus: 'DECLARED', + user: { id: 'user1', role: { id: 'FIELD_AGENT' } }, + office: { id: 'office1' }, + }, + { + date: '2024-01-02T12:00:00Z', + action: 'REQUESTED_CORRECTION', + user: { id: 'user2', role: { id: 'REGISTRATION_AGENT' } }, + office: { id: 'office1' }, + input: [ + { + valueCode: 'informant', + valueId: 'internationalCityPrimaryInformant', + value: 'OldInternationalCity', + }, + { + valueCode: 'informant', + valueId: 'cityPrimaryInformant', + value: 'OldCity', + }, + { + valueCode: 'informant', + valueId: 'postalCodePrimaryInformant', + value: '12345', + }, + ], + output: [ + { + valueCode: 'informant', + valueId: 'internationalCityPrimaryInformant', + value: 'NewInternationalCity', + }, + { + valueCode: 'informant', + valueId: 'cityPrimaryInformant', + value: 'NewCity', + }, + { + valueCode: 'informant', + valueId: 'postalCodePrimaryInformant', + value: '54321', + }, + ], + }, + ], + }) + + const result = transform(registration, deathResolver, 'death') + const correctionAction = result.actions.find( + (a) => a.type === 'REQUEST_CORRECTION' + ) + + // Check individual fields to avoid default field interference + assertEquals( + correctionAction?.declaration?.['informant.address']?.streetLevelDetails + ?.internationalCity, + 'NewInternationalCity' + ) + assertEquals( + correctionAction?.declaration?.['informant.address']?.streetLevelDetails + ?.city, + 'NewCity' + ) + assertEquals( + correctionAction?.declaration?.['informant.address']?.streetLevelDetails + ?.zipCode, + '54321' + ) + assertEquals( + correctionAction?.annotation?.['informant.address']?.streetLevelDetails + ?.internationalCity, + 'OldInternationalCity' + ) + assertEquals( + correctionAction?.annotation?.['informant.address']?.streetLevelDetails + ?.city, + 'OldCity' + ) + assertEquals( + correctionAction?.annotation?.['informant.address']?.streetLevelDetails + ?.zipCode, + '12345' + ) + } + ) + + await t.step( + 'should preserve addressType when correcting address fields', + () => { + const registration = buildBirthEventRegistration({ + history: [ + { + date: '2024-01-01T10:00:00Z', + regStatus: 'DECLARED', + user: { id: 'user1', role: { id: 'FIELD_AGENT' } }, + office: { id: 'office1' }, + }, + { + date: '2024-01-02T12:00:00Z', + action: 'REQUESTED_CORRECTION', + user: { id: 'user2', role: { id: 'REGISTRATION_AGENT' } }, + office: { id: 'office1' }, + input: [ + { + valueCode: 'father', + valueId: 'internationalCityPrimaryFather', + value: 'OldInternationalCity', + }, + ], + output: [ + { + valueCode: 'father', + valueId: 'internationalCityPrimaryFather', + value: 'NewInternationalCity', + }, + ], + }, + ], + }) + + const result = transform(registration, birthResolver, 'birth') + const correctionAction = result.actions.find( + (a) => a.type === 'REQUEST_CORRECTION' + ) + + // Should have addressType set based on country/international fields + assertEquals( + correctionAction?.declaration?.['father.address']?.addressType !== + undefined, + true + ) + assertEquals( + correctionAction?.declaration?.['father.address']?.streetLevelDetails + ?.internationalCity, + 'NewInternationalCity' + ) + } + ) +}) diff --git a/v1-to-v2-data-migration/tests/SOM/deceasedFields.test.ts b/v1-to-v2-data-migration/tests/SOM/deceasedFields.test.ts new file mode 100644 index 0000000..3243ff7 --- /dev/null +++ b/v1-to-v2-data-migration/tests/SOM/deceasedFields.test.ts @@ -0,0 +1,171 @@ +import { transform } from '../../helpers/transform.ts' +import { assertEquals } from 'https://deno.land/std@0.210.0/assert/mod.ts' +import { + buildDeathResolver, + buildDeathEventRegistration, +} from '../utils/testHelpers.ts' + +// Construct resolver as in migrate.ipynb +const deathResolver = buildDeathResolver() + +Deno.test('SOM deceased fields tests', async (t) => { + await t.step( + 'should resolve deceased.placeOfBirth from questionnaire', + () => { + const registration = buildDeathEventRegistration({ + questionnaire: [ + { + fieldId: 'death.deceased.deceased-view-group.placeOfBirth', + value: 'Mogadishu, Somalia', + }, + ], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['deceased.placeOfBirth'], + 'Mogadishu, Somalia' + ) + } + ) + + await t.step('should resolve deceased.occupation from questionnaire', () => { + const registration = buildDeathEventRegistration({ + questionnaire: [ + { + fieldId: 'death.deceased.deceased-view-group.occupation', + value: 'Teacher', + }, + ], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['deceased.occupation'], 'Teacher') + }) + + await t.step('should resolve deceased.brn from questionnaire', () => { + const registration = buildDeathEventRegistration({ + questionnaire: [ + { + fieldId: 'death.deceased.deceased-view-group.birthRegNo', + value: 'B2020123456', + }, + ], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['deceased.brn'], 'B2020123456') + }) + + await t.step( + 'should resolve eventDetails.timeOfDeath from questionnaire', + () => { + const registration = buildDeathEventRegistration({ + questionnaire: [ + { + fieldId: 'death.deathEvent.death-event-details.timeOfDeath', + value: '14:30', + }, + ], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['eventDetails.timeOfDeath'], + '14:30' + ) + } + ) + + await t.step('should resolve informant.relation from relationship', () => { + const registration = buildDeathEventRegistration({ + informant: { + relationship: 'SON', + }, + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['informant.relation'], 'SON') + }) + + await t.step( + 'should resolve eventDetails.date from deceased.deathDate', + () => { + const registration = buildDeathEventRegistration({ + deceased: { + deceased: { + deathDate: '2023-12-15', + }, + }, + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['eventDetails.date'], + '2023-12-15' + ) + } + ) + + await t.step('should handle missing deceased.placeOfBirth gracefully', () => { + const registration = buildDeathEventRegistration({ + questionnaire: [], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['deceased.placeOfBirth'], undefined) + }) + + await t.step('should handle missing deceased.occupation gracefully', () => { + const registration = buildDeathEventRegistration({ + questionnaire: [], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['deceased.occupation'], undefined) + }) + + await t.step('should handle missing deceased.brn gracefully', () => { + const registration = buildDeathEventRegistration({ + questionnaire: [], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['deceased.brn'], undefined) + }) + + await t.step( + 'should handle missing eventDetails.timeOfDeath gracefully', + () => { + const registration = buildDeathEventRegistration({ + questionnaire: [], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['eventDetails.timeOfDeath'], + undefined + ) + } + ) +}) diff --git a/v1-to-v2-data-migration/tests/SOM/nameResolver.test.ts b/v1-to-v2-data-migration/tests/SOM/nameResolver.test.ts new file mode 100644 index 0000000..80c9e0c --- /dev/null +++ b/v1-to-v2-data-migration/tests/SOM/nameResolver.test.ts @@ -0,0 +1,272 @@ +import { transform } from '../../helpers/transform.ts' +import { assertEquals } from 'https://deno.land/std@0.210.0/assert/mod.ts' +import { + buildBirthResolver, + buildBirthEventRegistration, + buildDeathResolver, + buildDeathEventRegistration, +} from '../utils/testHelpers.ts' + +// Construct resolvers as in migrate.ipynb +const birthResolver = buildBirthResolver() +const deathResolver = buildDeathResolver() + +Deno.test('SOM name resolver tests - birth events', async (t) => { + await t.step('should resolve child.name with all fields', () => { + const registration = buildBirthEventRegistration({ + child: { + name: [ + { + firstNames: 'Ahmed', + middleName: 'Mohamed', + familyName: 'Hassan', + }, + ], + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['child.name'], { + firstname: 'Ahmed', + middleName: 'Mohamed', + surname: 'Hassan', + }) + }) + + await t.step('should resolve child.name without middleName', () => { + const registration = buildBirthEventRegistration({ + child: { + name: [ + { + firstNames: 'Fatima', + familyName: 'Ali', + }, + ], + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['child.name'], { + firstname: 'Fatima', + middleName: undefined, + surname: 'Ali', + }) + }) + + await t.step('should resolve mother.name with all fields', () => { + const registration = buildBirthEventRegistration({ + mother: { + name: [ + { + firstNames: 'Halima', + middleName: 'Abdi', + familyName: 'Omar', + }, + ], + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['mother.name'], { + firstname: 'Halima', + middleName: 'Abdi', + surname: 'Omar', + }) + }) + + await t.step('should resolve father.name with all fields', () => { + const registration = buildBirthEventRegistration({ + father: { + name: [ + { + firstNames: 'Ibrahim', + middleName: 'Yusuf', + familyName: 'Ahmed', + }, + ], + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['father.name'], { + firstname: 'Ibrahim', + middleName: 'Yusuf', + surname: 'Ahmed', + }) + }) + + await t.step( + 'should resolve informant.name for non-special informant', + () => { + const registration = buildBirthEventRegistration({ + informant: { + relationship: 'GRANDFATHER', + name: [ + { + firstNames: 'Osman', + middleName: 'Ali', + familyName: 'Hassan', + }, + ], + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['informant.name'], { + firstname: 'Osman', + middleName: 'Ali', + surname: 'Hassan', + }) + } + ) + + await t.step('should return null when name array is undefined', () => { + const registration = buildBirthEventRegistration({ + child: { + name: undefined, + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['child.name'], undefined) + }) + + await t.step('should handle empty name array', () => { + const registration = buildBirthEventRegistration({ + child: { + name: [], + }, + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['child.name'], undefined) + }) +}) + +Deno.test('SOM name resolver tests - death events', async (t) => { + await t.step('should resolve deceased.name with all fields', () => { + const registration = buildDeathEventRegistration({ + deceased: { + name: [ + { + firstNames: 'Abdi', + middleName: 'Mohamed', + familyName: 'Aden', + }, + ], + }, + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['deceased.name'], { + firstname: 'Abdi', + middleName: 'Mohamed', + surname: 'Aden', + }) + }) + + await t.step('should resolve informant.name for non-SPOUSE informant', () => { + const registration = buildDeathEventRegistration({ + informant: { + relationship: 'SON', + name: [ + { + firstNames: 'Hassan', + middleName: 'Abdi', + familyName: 'Aden', + }, + ], + }, + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['informant.name'], { + firstname: 'Hassan', + middleName: 'Abdi', + surname: 'Aden', + }) + }) + + await t.step('should not resolve informant.name for SPOUSE', () => { + const registration = buildDeathEventRegistration({ + informant: { + relationship: 'SPOUSE', + name: [ + { + firstNames: 'Amina', + familyName: 'Omar', + }, + ], + }, + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + // SPOUSE is a special informant, so informant.name should not be set + assertEquals(declareAction?.declaration['informant.name'], undefined) + }) + + await t.step('should resolve spouse.name', () => { + const registration = buildDeathEventRegistration({ + spouse: { + name: [ + { + firstNames: 'Khadija', + middleName: 'Ali', + familyName: 'Mohamed', + }, + ], + }, + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['spouse.name'], { + firstname: 'Khadija', + middleName: 'Ali', + surname: 'Mohamed', + }) + }) + + await t.step('should handle missing middleName in deceased', () => { + const registration = buildDeathEventRegistration({ + deceased: { + name: [ + { + firstNames: 'Yusuf', + familyName: 'Ibrahim', + }, + ], + }, + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['deceased.name'], { + firstname: 'Yusuf', + middleName: undefined, + surname: 'Ibrahim', + }) + }) +}) diff --git a/v1-to-v2-data-migration/tests/SOM/verificationStatus.test.ts b/v1-to-v2-data-migration/tests/SOM/verificationStatus.test.ts new file mode 100644 index 0000000..7922ba6 --- /dev/null +++ b/v1-to-v2-data-migration/tests/SOM/verificationStatus.test.ts @@ -0,0 +1,259 @@ +import { transform } from '../../helpers/transform.ts' +import { assertEquals } from 'https://deno.land/std@0.210.0/assert/mod.ts' +import { + buildBirthResolver, + buildBirthEventRegistration, + buildDeathResolver, + buildDeathEventRegistration, +} from '../utils/testHelpers.ts' + +// Construct resolvers as in migrate.ipynb +const birthResolver = buildBirthResolver() +const deathResolver = buildDeathResolver() + +Deno.test('SOM verification status tests - birth events', async (t) => { + await t.step('should map "authenticated" status for mother', () => { + const registration = buildBirthEventRegistration({ + questionnaire: [ + { + fieldId: 'birth.mother.mother-view-group.verified', + value: 'authenticated', + }, + ], + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['mother.verified'], 'authenticated') + }) + + await t.step('should map "verified" status for father', () => { + const registration = buildBirthEventRegistration({ + questionnaire: [ + { + fieldId: 'birth.father.father-view-group.verified', + value: 'verified', + }, + ], + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['father.verified'], 'verified') + }) + + await t.step('should map "failed" status for informant', () => { + const registration = buildBirthEventRegistration({ + questionnaire: [ + { + fieldId: 'birth.informant.informant-view-group.verified', + value: 'failed', + }, + ], + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['informant.verified'], 'failed') + }) + + await t.step('should map "pending" status', () => { + const registration = buildBirthEventRegistration({ + questionnaire: [ + { + fieldId: 'birth.mother.mother-view-group.verified', + value: 'pending', + }, + ], + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['mother.verified'], 'pending') + }) + + await t.step('should map "failedFetchIdDetails" to "failed"', () => { + const registration = buildBirthEventRegistration({ + questionnaire: [ + { + fieldId: 'birth.mother.mother-view-group.verified', + value: 'failedFetchIdDetails', + }, + ], + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['mother.verified'], 'failed') + }) + + await t.step('should handle undefined verification status', () => { + const registration = buildBirthEventRegistration({ + questionnaire: [], + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['mother.verified'], undefined) + }) + + await t.step('should handle multiple verification fields', () => { + const registration = buildBirthEventRegistration({ + questionnaire: [ + { + fieldId: 'birth.mother.mother-view-group.verified', + value: 'verified', + }, + { + fieldId: 'birth.father.father-view-group.verified', + value: 'authenticated', + }, + { + fieldId: 'birth.informant.informant-view-group.verified', + value: 'pending', + }, + ], + }) + + const result = transform(registration, birthResolver, 'birth') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['mother.verified'], 'verified') + assertEquals(declareAction?.declaration['father.verified'], 'authenticated') + assertEquals(declareAction?.declaration['informant.verified'], 'pending') + }) +}) + +Deno.test('SOM verification status tests - death events', async (t) => { + await t.step('should map "authenticated" status for deceased', () => { + const registration = buildDeathEventRegistration({ + questionnaire: [ + { + fieldId: 'death.deceased.deceased-view-group.verified', + value: 'authenticated', + }, + ], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals( + declareAction?.declaration['deceased.verified'], + 'authenticated' + ) + }) + + await t.step('should map "verified" status for informant', () => { + const registration = buildDeathEventRegistration({ + questionnaire: [ + { + fieldId: 'death.informant.informant-view-group.verified', + value: 'verified', + }, + ], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['informant.verified'], 'verified') + }) + + await t.step('should map "failed" status for spouse', () => { + const registration = buildDeathEventRegistration({ + questionnaire: [ + { + fieldId: 'death.spouse.spouse-view-group.verified', + value: 'failed', + }, + ], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['spouse.verified'], 'failed') + }) + + await t.step('should map "pending" status', () => { + const registration = buildDeathEventRegistration({ + questionnaire: [ + { + fieldId: 'death.deceased.deceased-view-group.verified', + value: 'pending', + }, + ], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['deceased.verified'], 'pending') + }) + + await t.step( + 'should map "failedFetchIdDetails" to "failed" for deceased', + () => { + const registration = buildDeathEventRegistration({ + questionnaire: [ + { + fieldId: 'death.deceased.deceased-view-group.verified', + value: 'failedFetchIdDetails', + }, + ], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['deceased.verified'], 'failed') + } + ) + + await t.step('should handle undefined verification status', () => { + const registration = buildDeathEventRegistration({ + questionnaire: [], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['deceased.verified'], undefined) + }) + + await t.step('should handle multiple verification fields', () => { + const registration = buildDeathEventRegistration({ + questionnaire: [ + { + fieldId: 'death.deceased.deceased-view-group.verified', + value: 'verified', + }, + { + fieldId: 'death.informant.informant-view-group.verified', + value: 'authenticated', + }, + { + fieldId: 'death.spouse.spouse-view-group.verified', + value: 'pending', + }, + ], + }) + + const result = transform(registration, deathResolver, 'death') + const declareAction = result.actions.find((a) => a.type === 'DECLARE') + + assertEquals(declareAction?.declaration['deceased.verified'], 'verified') + assertEquals( + declareAction?.declaration['informant.verified'], + 'authenticated' + ) + assertEquals(declareAction?.declaration['spouse.verified'], 'pending') + }) +})