Kenya Disease Surveillance FHIR Implementation Guide.
0.1.0 - ci-build Kenya flag

Kenya Disease Surveillance FHIR Implementation Guide., published by Kenya National Public Health Institute. This guide is not an authorized publication; it is the continuous build for version 0.1.0 built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/IntelliSOFT-Consulting/Surveillance-FHIR-IG/ and changes regularly. See the Directory of published versions

StructureMap: AfpCaseReportMap

Official URL: http://example.org/StructureMap/AfpCaseReportMap Version: 0.1.0
Draft as of 2026-05-04 Computable Name: AfpCaseReportMap

AFP Case Report QuestionnaireResponse to FHIR resources Maps to: Patient, Encounter, Condition (AFP), Immunization (OPV), Specimen (stool)

map "http://example.org/StructureMap/AfpCaseReportMap" = "AfpCaseReportMap"

// AFP Case Report QuestionnaireResponse to FHIR resources
// Maps to: Patient, Encounter, Condition (AFP), Immunization (OPV), Specimen (stool)

uses "http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse" alias QuestionnaireResponse as source
uses "http://hl7.org/fhir/StructureDefinition/Bundle" alias Bundle as target
uses "http://hl7.org/fhir/StructureDefinition/Patient" alias Patient as target
uses "http://hl7.org/fhir/StructureDefinition/Encounter" alias Encounter as target
uses "http://hl7.org/fhir/StructureDefinition/Condition" alias Condition as target
uses "http://hl7.org/fhir/StructureDefinition/Immunization" alias Immunization as target
uses "http://hl7.org/fhir/StructureDefinition/Specimen" alias Specimen as target

group AfpCaseReportMap(source src : QuestionnaireResponse, target bundle : Bundle) {
  src -> bundle.id = uuid() "bundleId";
  src -> bundle.type = 'transaction' "bundleType";
  src -> bundle.entry as e then {
    src -> e.resource = create('Patient') as patient then MapAfpPatient(src, patient) "execPatient";
    src ->  e.request as req,  req.method = 'PUT',  req.url = ('Patient/' + %src.subject.reference) "patientReq";
  } "patientEntry";
  src -> bundle.entry as e then {
    src -> e.resource = create('Encounter') as encounter then MapAfpEncounter(src, encounter) "execEncounter";
    src ->  e.request as req,  req.method = 'POST',  req.url = 'Encounter' "encounterReq";
  } "encounterEntry";
  src -> bundle.entry as e then {
    src -> e.resource = create('Condition') as condition then MapAfpCondition(src, condition) "execCondition";
    src ->  e.request as req,  req.method = 'POST',  req.url = 'Condition' "conditionReq";
  } "conditionEntry";
  src -> bundle.entry as e then {
    src -> e.resource = create('Immunization') as immunization then MapAfpImmunization(src, immunization) "execImmunization";
    src ->  e.request as req,  req.method = 'POST',  req.url = 'Immunization' "immunizationReq";
  } "immunizationEntry";
  src -> bundle.entry as e then {
    src -> e.resource = create('Specimen') as specimen then MapAfpSpecimen(src, specimen) "execSpecimen";
    src ->  e.request as req,  req.method = 'POST',  req.url = 'Specimen' "specimenReq";
  } "specimenEntry";
}

group MapAfpPatient(source src : QuestionnaireResponse, target patient : Patient) {
  src -> patient.id = uuid() "patientId";
  src.item as demographics where linkId = '359809652429' then {
    // Given name
    demographics.item as item where linkId = '873240407472' then {
      item.answer first as ans ->  patient.name as name,  name.given = ans.valueString "givenName";
    } "firstName";
    // Middle name (appended to given)
    demographics.item as item where linkId = '246751846436' then {
      item.answer first as ans ->  patient.name as name,  name.given = ans.valueString "middleName";
    } "middleName";
    // Family name
    demographics.item as item where linkId = '486402457213' then {
      item.answer first as ans ->  patient.name as name,  name.family = ans.valueString "familyName";
    } "familyName";
    // Gender
    demographics.item as item where linkId = '929966324957' then {
      item.answer first as ans -> patient.gender = (ans.valueCoding.code) "gender";
    } "gender";
    // Date of birth
    demographics.item as item where linkId = '257830485990' then {
      item.answer first as ans -> patient.birthDate = ans.valueDate "birthDate";
    } "birthDate";
    // Parent / Guardian name as contact
    demographics.item as item where linkId = '856448027666' then {
      item.answer first as ans -> patient.contact as contact then {
        ans ->  contact.name as cname,  cname.text = ans.valueString "contactName";
      } "parentContact";
    } "parentName";
    // Parent / Guardian phone
    demographics.item as item where linkId = '576318206363' then {
      item.answer first as ans ->  patient.telecom as tel,  tel.system = 'phone',  tel.value = ans.valueString "phone";
    } "phone";
    // Residence address
    demographics.item as item where linkId = 'residence-details' then {
      item.answer first as ans ->  patient.address as addr,  addr.text = ans.valueString "address";
    } "address";
    // Neighborhood landmark
    demographics.item as item where linkId = '946232932304' then {
      item.answer first as ans ->  patient.address as addr,  addr.district = ans.valueString "landmark";
    } "landmark";
  } "demographics";
}

group MapAfpEncounter(source src : QuestionnaireResponse, target encounter : Encounter) {
  src -> encounter.id = uuid() "encounterId";
  src -> encounter.status = 'finished' "status";
  src -> encounter.class as cls then {
    src -> cls.system = 'http://terminology.hl7.org/CodeSystem/v3-ActCode' "clsSys";
    src -> cls.code = 'AMB' "clsCode";
  } "class";
  // Subject reference
  src.subject as subj ->  encounter.subject as ref,  ref.reference = ('Patient/' + subj.reference);
  // Reporting site page
  src.item as reportSite where linkId = '151479012557' then {
    // EPID No as identifier
    reportSite.item as item where linkId = '992818778559' then {
      item.answer first as ans -> encounter.identifier as id then {
        ans -> id.system = 'http://example.org/identifier/epid' "epidSys";
        ans -> id.value = ans.valueString "epidValue";
      } "epidId";
    } "epidNo";
  } "reportSite";
  // Case information page
  src.item as caseInfo where linkId = '451840456960' then {
    // Date of investigation as period start
    caseInfo.item as item where linkId = '502488184403' then {
      item.answer first as ans ->  encounter.period as period,  period.start = ans.valueDate "periodStart";
    } "investigationDate";
    // Date of notification extension
    caseInfo.item as item where linkId = '426321975477' then {
      item.answer first as ans -> encounter.extension as ext then {
        ans -> ext.url = 'http://example.org/StructureDefinition/notificationDate' "extUrl";
        ans -> ext.valueDate = ans.valueDate "extValue";
      } "notificationExt";
    } "notificationDate";
    // Notified by
    caseInfo.item as item where linkId = '171292274939' then {
      item.answer first as ans -> encounter.extension as ext then {
        ans -> ext.url = 'http://example.org/StructureDefinition/notifiedBy' "extUrl";
        ans -> ext.valueString = (ans.valueCoding.display) "extValue";
      } "notifiedByExt";
    } "notifiedBy";
    // Admission date
    caseInfo.item as item where linkId = '507199621281' then {
      item.answer first as ans -> encounter.hospitalization as hosp then {
        ans ->  hosp.admitSource as src,  src.coding as cod then {
          ans -> cod.system = 'http://terminology.hl7.org/CodeSystem/admit-source' "admitSys";
          ans -> cod.code = 'hosp-trans' "admitCode";
        } "admitSource";
      } "hospitalization";
      item.answer first as ans ->  encounter.period as period,  period.start = ans.valueDate "admitDate";
    } "admissionDate";
    // IP/OP number
    caseInfo.item as item where linkId = '525996604810' then {
      item.answer first as ans -> encounter.identifier as id then {
        ans -> id.system = 'http://example.org/identifier/ip-op' "ipopSys";
        ans -> id.value = ans.valueString "ipopValue";
      } "ipopId";
    } "ipopNo";
  } "caseInfo";
}

group MapAfpCondition(source src : QuestionnaireResponse, target condition : Condition) {
  src -> condition.id = uuid() "conditionId";
  // AFP SNOMED code
  src -> condition.code as code then {
    src -> code.coding as coding then {
      src -> coding.system = 'http://snomed.info/sct' "snomedSys";
      src -> coding.code = '398102009' "afpCode";
      src -> coding.display = 'Acute flaccid paralysis' "afpDisplay";
    } "afpCoding";
    src -> code.text = 'Acute Flaccid Paralysis (AFP)' "afpText";
  } "afpCodeBlock";
  src.subject as subj ->  condition.subject as ref,  ref.reference = ('Patient/' + subj.reference);
  src.item as clinicalInfo where linkId = '735342695013' then {
    // Date of onset of paralysis
    clinicalInfo.item as item where linkId = '728034137219' then {
      item.answer first as ans -> condition.onset = ans.valueDate "onsetDate";
    } "onsetDate";
    // Outcome → clinical status
    clinicalInfo.item as item where linkId = '212304573462' then {
      item.answer first as ans -> condition.clinicalStatus as status then {
        ans.valueCoding as val where code = 'dead' ->  status.coding as cod,  cod.system = 'http://terminology.hl7.org/CodeSystem/condition-clinical',  cod.code = 'inactive' "deadStatus";
        ans.valueCoding as val where code = 'alive' ->  status.coding as cod,  cod.system = 'http://terminology.hl7.org/CodeSystem/condition-clinical',  cod.code = 'active' "aliveStatus";
      } "clinicalStatus";
    } "outcome";
    // Fever at onset as note
    clinicalInfo.item as item where linkId = '932108244312' then {
      item.answer first as ans ->  condition.note as note,  note.text = (iif(ans.valueCoding.code = 'yes', 'Fever at onset: Yes', 'Fever at onset: No')) "feverNote";
    } "fever";
    // Site of paralysis as body site
    clinicalInfo.item as item where linkId = '828001350323' then {
      item.answer as ans -> condition.bodySite as bodySite then {
        ans ->  bodySite.coding as cod,  cod.system = 'http://snomed.info/sct',  cod.display = (ans.valueCoding.display) "bodySiteCoding";
      } "paralysisBodySite";
    } "paralysisBodySites";
    // True AFP confirmation
    clinicalInfo.item as item where linkId = '564450145870' then {
      item.answer first as ans -> condition.verificationStatus as vs then {
        ans.valueCoding as val where code = 'yes' ->  vs.coding as cod,  cod.system = 'http://terminology.hl7.org/CodeSystem/condition-ver-status',  cod.code = 'confirmed' "confirmed";
        ans.valueCoding as val where code = 'no' ->  vs.coding as cod,  cod.system = 'http://terminology.hl7.org/CodeSystem/condition-ver-status',  cod.code = 'refuted' "refuted";
      } "verificationStatus";
    } "trueAfp";
  } "clinicalInfo";
}

group MapAfpImmunization(source src : QuestionnaireResponse, target immunization : Immunization) {
  src -> immunization.id = uuid() "immunizationId";
  src -> immunization.status = 'completed' "status";
  // OPV vaccine code
  src -> immunization.vaccineCode as code then {
    src -> code.coding as coding then {
      src -> coding.system = 'http://hl7.org/fhir/sid/cvx' "cvxSys";
      src -> coding.code = '02' "opvCode";
      src -> coding.display = 'Oral Poliovirus Vaccine (OPV)' "opvDisplay";
    } "opvCoding";
  } "vaccineCode";
  src.subject as subj ->  immunization.patient as ref,  ref.reference = ('Patient/' + subj.reference) "patient";
  src.item as vaccination where linkId = '446305443608' then {
    // Vaccination status
    vaccination.item as item where linkId = '970455623029' then {
      item.answer first as ans where valueCoding.code = 'no' -> immunization.status = 'not-done' "notVaccinated";
      item.answer first as ans where valueCoding.code = 'unknown' ->  immunization.statusReason as reason,  reason.text = 'Unknown vaccination status' "unknownStatus";
    } "vaccinationStatus";
    // Number of doses
    vaccination.item as item where linkId = '886125589225' then {
      item.answer first as ans -> immunization.protocolApplied as protocol then {
        ans -> protocol.doseNumber = ans.valueInteger "doseNumber";
      } "protocol";
    } "doses";
    // Date of OPV at birth
    vaccination.item as item where linkId = '413372430071' then {
      item.answer first as ans -> immunization.occurrenceDateTime = ans.valueDate "opvBirthDate";
    } "opvBirth";
    // Date of last OPV dose through SIA
    vaccination.item as item where linkId = '910678978959' then {
      item.answer first as ans -> immunization.extension as ext then {
        ans -> ext.url = 'http://example.org/StructureDefinition/lastSIADate' "extUrl";
        ans -> ext.valueDate = ans.valueDate "extValue";
      } "lastSIADate";
    } "siaDate";
    // Source of vaccination information
    vaccination.item as item where linkId = '650080600932' then {
      item.answer first as ans -> immunization.reportOrigin as origin then {
        ans ->  origin.coding as cod,  cod.system = 'http://example.org/CodeSystem/vaccination-info-source',  cod.code = (ans.valueCoding.code),  cod.display = (ans.valueCoding.display) "origin";
      } "reportOrigin";
    } "infoSource";
  } "vaccination";
}

group MapAfpSpecimen(source src : QuestionnaireResponse, target specimen : Specimen) {
  src -> specimen.id = uuid() "specimenId";
  // Stool specimen type
  src -> specimen.type as type then {
    src -> type.coding as coding then {
      src -> coding.system = 'http://snomed.info/sct' "snomedSys";
      src -> coding.code = '119339001' "stoolCode";
      src -> coding.display = 'Stool specimen' "stoolDisplay";
    } "stoolCoding";
  } "specimenType";
  src.subject as subj ->  specimen.subject as ref,  ref.reference = ('Patient/' + subj.reference);
  src.item as stoolCollection where linkId = '350784256533' then {
    // Date of first specimen collection
    stoolCollection.item as item where linkId = '737703942433' then {
      item.answer first as ans ->  specimen.collection as coll,  coll.collectedDateTime = ans.valueDate "firstSpecimen";
    } "firstSpecimenDate";
    // Date of second specimen (as processing step)
    stoolCollection.item as item where linkId = '711388438654' then {
      item.answer first as ans -> specimen.processing as proc then {
        ans -> proc.description = '2nd specimen collected' "procDesc";
        ans -> proc.timeDateTime = ans.valueDate "procTime";
      } "secondSpecimen";
    } "secondSpecimenDate";
    // Date sent to national level
    stoolCollection.item as item where linkId = '808177332790' then {
      item.answer first as ans -> specimen.processing as proc then {
        ans -> proc.description = 'Specimen sent to national level' "procDesc";
        ans -> proc.timeDateTime = ans.valueDate "procTime";
      } "sentToNational";
    } "sentToNationalDate";
  } "stoolCollection";
}