diff --git a/datacapture/build.gradle.kts b/datacapture/build.gradle.kts index 53c8b4293d..a8c2ca79ce 100644 --- a/datacapture/build.gradle.kts +++ b/datacapture/build.gradle.kts @@ -45,7 +45,11 @@ android { configureJacocoTestOptions() - sourceSets { getByName("androidTest").apply { resources.setSrcDirs(listOf("sampledata")) } } + sourceSets { + getByName("androidTest").apply { resources.setSrcDirs(listOf("sampledata")) } + + getByName("test").apply { resources.setSrcDirs(listOf("sampledata")) } + } testOptions { animationsDisabled = true } kotlin { jvmToolchain(11) } @@ -105,6 +109,9 @@ dependencies { testImplementation(Dependencies.mockitoKotlin) testImplementation(Dependencies.robolectric) testImplementation(Dependencies.truth) + testImplementation(project(":knowledge")) { + exclude(group = Dependencies.androidFhirGroup, module = Dependencies.androidFhirEngineModule) + } constraints { Dependencies.hapiFhirConstraints().forEach { (libName, constraints) -> diff --git a/datacapture/sampledata/measles-outbreak/MeaslesQuestionnaireToResources.map b/datacapture/sampledata/measles-outbreak/MeaslesQuestionnaireToResources.map new file mode 100644 index 0000000000..8a4278285c --- /dev/null +++ b/datacapture/sampledata/measles-outbreak/MeaslesQuestionnaireToResources.map @@ -0,0 +1,14 @@ +map "http://worldhealthorganization.github.io/smart-ot/StructureMap/MeaslesQuestionnaireToResources" = "MeaslesQuestionnaireToResources" +uses "http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse" alias QuestionnaireResponse as source +uses "http://hl7.org/fhir/StructureDefinition/Bundle" alias MeaslesCIFBundle as target + +imports "http://worldhealthorganization.github.io/smart-ot/StructureMap/MeaslesLogicalModelToResources" +imports "http://worldhealthorganization.github.io/smart-ot/StructureMap/MeaslesQuestionnaireToLogicalModel" + + +group MeaslesQuestionnaireToResources(source qr : QuestionnaireResponse, target bundleCif : MeaslesCIFBundle) { + qr -> create ("http://worldhealthorganization.github.io/smart-ot/StructureDefinition/SOTMeasles") as model then { + qr -> model then MeaslesQuestionnaireToLogicalModel(qr,model) "QRtoLM"; + qr -> bundleCif then MeaslesLogicalModelToResources (model, bundleCif) "LMtoBundle"; + } "QRtoBundle"; +} diff --git a/datacapture/sampledata/measles-outbreak/package.r4.tgz b/datacapture/sampledata/measles-outbreak/package.r4.tgz new file mode 100644 index 0000000000..2e2b4e4333 Binary files /dev/null and b/datacapture/sampledata/measles-outbreak/package.r4.tgz differ diff --git a/datacapture/sampledata/measles-outbreak/package.tgz b/datacapture/sampledata/measles-outbreak/package.tgz new file mode 100644 index 0000000000..7dda7b6fdc Binary files /dev/null and b/datacapture/sampledata/measles-outbreak/package.tgz differ diff --git a/datacapture/sampledata/measles-outbreak/questionnaire_outbreak.json b/datacapture/sampledata/measles-outbreak/questionnaire_outbreak.json new file mode 100644 index 0000000000..f33ff92f82 --- /dev/null +++ b/datacapture/sampledata/measles-outbreak/questionnaire_outbreak.json @@ -0,0 +1,1019 @@ +{ + "resourceType" : "Questionnaire", + "id" : "Questionnaire-SOTMeasles", + "meta" : { + "profile" : ["http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-extr-smap"] + }, + "language" : "en", + "text" : { + "status" : "generated", + "div" : "
\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
LinkIdTextCardinalityTypeDescription & Constraints\"doco\"
\".\"\".\" Questionnaire-SOTMeaslesMeasles Case Investigation QuestionnaireQuestionnairehttp://worldhealthorganization.github.io/smart-ot/Questionnaire/Questionnaire-SOTMeasles#0.2.1
\".\"\".\"\".\" investigationFormInvestigation Form for Measles/Rubella0..1group
\".\"\".\"\".\"\".\" descriptionComplete this form for: Any person in whom a health care worker suspects measles or rubella infection or a patient with fever and rash. The health worker should attempt to collect epidemiological and clinical data , as well as a blood sample , on the first contact with the patient. This contact with the patient might be the only one.0..1display
\".\"\".\"\".\"\".\" reportingSourceSection I: Identification of the Reporting Institution0..1group
\".\"\".\"\".\"\".\"\".\" initialDiagnosisInitial Diagnosis0..1choiceValue Set: SOT Measles Initial Diagnosis
\".\"\".\"\".\"\".\"\".\" caseIDCase Number0..1string
\".\"\".\"\".\"\".\"\".\" reportingInstitutionReporting Institution0..1group
\".\"\".\"\".\"\".\"\".\"\".\" reportingFacilityHealth Service Name0..1string
\".\"\".\"\".\"\".\"\".\"\".\" telephoneHealth Service Telephone0..1string
\".\"\".\"\".\"\".\"\".\"\".\" countryCountry0..1string
\".\"\".\"\".\"\".\"\".\"\".\" municipalityMunicipality0..1string
\".\"\".\"\".\"\".\"\".\"\".\" stateProvince/State0..1string
\".\"\".\"\".\"\".\"\".\"\".\" localityLocality/Neighborhood0..1string
\".\"\".\"\".\"\".\"\".\" reportedByReported By0..1string
\".\"\".\"\".\"\".\"\".\" DateOfConsultationDate Of Consultation0..1date
\".\"\".\"\".\"\".\"\".\" DateOfHomeVisitDate Of Home Visit0..1date
\".\"\".\"\".\"\".\"\".\" dateReportedDate Reported - Local0..1date
\".\"\".\"\".\"\".\"\".\" DateReportedNationalDate Reported - National0..1date
\".\"\".\"\".\"\".\"\".\" DetectedByDetected By0..1choiceValue Set: SOT Measles Detected By
\".\"\".\"\".\"\".\"\".\" TypeOfProviderReportingType Of Provider Reporting0..1choiceValue Set: SOT Measles Provider Type
\".\"\".\"\".\"\".\"\".\" specifyotherSpecify0..1stringEnable When: TypeOfProviderReporting = Other (Type of Provider Code System#88)
\".\"\".\"\".\"\".\" demographicsSection II: Patient Information0..1group
\".\"\".\"\".\"\".\"\".\" namePatient’s first and last names0..1string
\".\"\".\"\".\"\".\"\".\" guardianName of the mother or guardian0..1string
\".\"\".\"\".\"\".\"\".\" addressAddress0..1string
\".\"\".\"\".\"\".\"\".\" telephoneTelephone0..1string
\".\"\".\"\".\"\".\"\".\" landmarkLandmarks to locate the house0..1string
\".\"\".\"\".\"\".\"\".\" occupationPatient’s Occupation0..1string
\".\"\".\"\".\"\".\"\".\" localityTypeType of locality0..1choiceValue Set: SOT Measles Locality Type
\".\"\".\"\".\"\".\"\".\" workAddressWork or school address0..1string
\".\"\".\"\".\"\".\"\".\" sexPatient’s sex0..1choiceValue Set: SOT Biological Sex
\".\"\".\"\".\"\".\"\".\" DoBPatient’s Date of Birth0..1date
\".\"\".\"\".\"\".\"\".\" ageOnsetIf date of birth is unknown, age0..1integer
\".\"\".\"\".\"\".\" vaccinationStatusSection III: Vaccination History0..*group
\".\"\".\"\".\"\".\"\".\" vaccineTypeType of Vaccine*0..1choiceValue Set: SOT Measles Vaccine Type
\".\"\".\"\".\"\".\"\".\" noOfDosesNumber of doses**0..1choiceValue Set: SOT Measles No Of Doses
\".\"\".\"\".\"\".\"\".\" lastDoseDateDate of last dose0..1date
\".\"\".\"\".\"\".\"\".\" sourceOfInformationSource of vaccination Information †0..1choiceValue Set: Vaccine Info Source
\".\"\".\"\".\"\".\" clinicalSection IV: Clinical Data; Follow-up & Treatment0..1group
\".\"\".\"\".\"\".\"\".\" feverFever?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" temperatureIf Yes, temperature (°)0..1decimalEnable When: fever = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" dateOfFeverOnsetDate of fever onset0..1dateEnable When: fever = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" rashRash?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" rashDurationIf Yes, duration of the rash(in days)0..1integerEnable When: rash = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" rashOnsetDateDate of rash onset0..1dateEnable When: rash = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" rashTypeType of rash0..1choiceEnable When: rash = Yes (Yes No Unknown#Yes)
Value Set: Rash Type
\".\"\".\"\".\"\".\"\".\" coughCough?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" conjunctivitisConjunctivitis?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" coryzaCoryza?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" koplikSpotsKoplik Spots?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" lymphadenopathyLymphadenopathy?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" jointPainArthralgia?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" pregnancyIs the patient pregnant?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" monthsPregnantWeeks of pregnancy (01-42)0..1integerEnable When: pregnancy = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" placeOfBirthIf Yes, Place where birth will likely take place0..1stringEnable When: pregnancy = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" admittedHospitalized?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" admittedHCFNameHospital name0..1stringEnable When: admitted = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" admissionDateIf Yes, Date of admission0..1dateEnable When: admitted = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" hospitalRecordNumberHospital record number0..1stringEnable When: admitted = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" outcomeDeath?0..1choiceValue Set: Patient Clinical Course Outcome
\".\"\".\"\".\"\".\"\".\" outcomeDateIf Yes, Date of death0..1dateEnable When: outcome = Death (Patient Clinical Course Outcome#Death)
\".\"\".\"\".\"\".\"\".\" primaryCauseOfDeathPrimary cause of death0..1stringEnable When: outcome = Death (Patient Clinical Course Outcome#Death)
\".\"\".\"\".\"\".\"\".\" diseaseAdditionalInfoComments0..1string
\".\"\".\"\".\"\".\" laboratoryResultsSection V: Specimens & Laboratory Testing0..1group
\".\"\".\"\".\"\".\"\".\" specimenNumberSpecimen number*0..1choiceValue Set: Specimen Number
\".\"\".\"\".\"\".\"\".\" sampleTypeType of specimen**0..1choiceValue Set: Sample Type
\".\"\".\"\".\"\".\"\".\" collectionDateDate specimen obtained0..1date
\".\"\".\"\".\"\".\"\".\" labNameLaboratory Name0..1string
\".\"\".\"\".\"\".\"\".\" specimenSentDateDate specimen was sent to lab0..1date
\".\"\".\"\".\"\".\"\".\" specimenReceivedDateDate Received0..1date
\".\"\".\"\".\"\".\"\".\" sampleId# specimen ID in lab.0..1string
\".\"\".\"\".\"\".\"\".\" testPerformedType of test0..1choiceValue Set: Test Performed
\".\"\".\"\".\"\".\"\".\" antigenAntigen0..1choiceValue Set: Antigen
\".\"\".\"\".\"\".\"\".\" resultResult0..1choiceValue Set: Result
\".\"\".\"\".\"\".\"\".\" resultDateDate of Results0..1date
\".\"\".\"\".\"\".\"\".\" specifyVirusIf virus was detected, specify viral genotype: (Measles: A, B1, B2, B3, C1, C2, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, E, F, G1, G2, G3, H1, H2. Rubella: 1a, 1B, 1C,\r\n1D, 1E, 1F, 1g, 2A, 2B, 2c)0..1string
\".\"\".\"\".\"\".\" contactTracingSection VI: Investigation0..1group
\".\"\".\"\".\"\".\"\".\" caseSearchConductedWere active case-searches conducted?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" noOfsuspectCasesIf Yes, Number of suspect cases detected during active case-search0..1integerEnable When: caseSearchConducted = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" pregnantContactWas the patient in contact with any pregnant woman?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" pregnantContactNamesIf Yes, Name(s)0..1stringEnable When: pregnantContact = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" localCasesPresentAre there other cases present in the case’s municipality of residence?0..1choiceValue Set: LocalCasesPresent
\".\"\".\"\".\"\".\"\".\" travelledOutsideDid the patient travel outside his/her province/state of residence 7-23 days before rash onset?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" travelDetailsIf Yes,:0..*groupEnable When: travelledOutside = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\"\".\" placeOfTravelCities/Countries0..1string
\".\"\".\"\".\"\".\"\".\"\".\" arrivalDateDate of arrival0..1date
\".\"\".\"\".\"\".\"\".\"\".\" departureDateDate of departure0..1date
\".\"\".\"\".\"\".\"\".\" infectionSettingSetting where infected?0..1choiceValue Set: InfectionSetting
\".\"\".\"\".\"\".\"\".\" specifyInfectionSettingSpecify0..1stringEnable When: infectionSetting = Others (InfectionSetting#88)
\".\"\".\"\".\"\".\" epiDataSection VII: Response Measures0..1group
\".\"\".\"\".\"\".\"\".\" ringVaccinationRing vaccination?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" dateStartedDate started0..1dateEnable When: ringVaccination = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" dateEndedDate Ended0..1dateEnable When: ringVaccination = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" noOfDosesRingVaccinationNumber of doses given during ring vaccination0..1integerEnable When: ringVaccination = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" rapidCoverageMonitioringWas rapid coverage monitoring done0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" percentVaccinatedIf yes, what % of vaccinated persons was found?0..1integerEnable When: rapidCoverageMonitioring = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" contactTracingDoneWere the contacts followed for up to 30 days after the date of the rash onset of the case?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" lastFollowUpIf yes, date of the last day of contact follow-up0..1dateEnable When: contactTracingDone = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\" classificationSection VIII: Classification0..1group
\".\"\".\"\".\"\".\"\".\" finalClassificationFinal Classification0..1choiceValue Set: FinalClassification
\".\"\".\"\".\"\".\"\".\" confirmationBasisBasis for confirmation0..1choiceValue Set: ConfirmationBasis
\".\"\".\"\".\"\".\"\".\" countryImportationIf Imported or Import-related, Country of importation0..1stringEnable When: confirmationBasis = Laboratory (Confirmation Basis#1)
\".\"\".\"\".\"\".\"\".\" discardingBasisBasis for discarding0..1choiceValue Set: DiscardingBasis
\".\"\".\"\".\"\".\"\".\" sourceOfInfectionFor confirmed cases, Source of infection0..1choiceValue Set: SourceOfInfection
\".\"\".\"\".\"\".\"\".\" contactContact of another case?0..1choiceValue Set: Yes No Unknown
\".\"\".\"\".\"\".\"\".\" contactCaseNoContact of (or epidemiologically-linked to) case number0..1stringEnable When: contact = Yes (Yes No Unknown#Yes)
\".\"\".\"\".\"\".\"\".\" classifiedByClassified by0..1string
\".\"\".\"\".\"\".\"\".\" classificationDateDate of final classification0..1date

\"doco\" Documentation for this format
" + }, + "contained" : [{ + "resourceType" : "ValueSet", + "id" : "InitDiag", + "url" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/InitDiag", + "version" : "0.2.1", + "name" : "InitDiag", + "title" : "SOT Measles Initial Diagnosis", + "status" : "draft", + "description" : "SOT Measles Initial Diagnosis", + "expansion" : { + "identifier" : "urn:uuid:c060c134-871f-43be-b1ee-5dfface2c18f", + "timestamp" : "2023-05-02T20:23:35+05:30", + "total" : 6, + "parameter" : [{ + "name" : "excludeNested", + "valueBoolean" : false + }, + { + "name" : "version", + "valueUri" : "http://worldhealthorganization.github.io/smart-ot/InitDiag|0.2.1" + }], + "contains" : [{ + "system" : "http://worldhealthorganization.github.io/smart-ot/InitDiag", + "code" : "1", + "display" : "Measles" + }, + { + "system" : "http://worldhealthorganization.github.io/smart-ot/InitDiag", + "code" : "2", + "display" : "Rubella" + }, + { + "system" : "http://worldhealthorganization.github.io/smart-ot/InitDiag", + "code" : "3", + "display" : "Dengue" + }, + { + "system" : "http://worldhealthorganization.github.io/smart-ot/InitDiag", + "code" : "4", + "display" : "Other Rash illness" + }, + { + "system" : "http://worldhealthorganization.github.io/smart-ot/InitDiag", + "code" : "8", + "display" : "Other Non-Rash illness" + }, + { + "system" : "http://worldhealthorganization.github.io/smart-ot/InitDiag", + "code" : "99", + "display" : "Unknown" + }] + } + }, + { + "resourceType" : "ValueSet", + "id" : "YesNoUnknown", + "url" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown", + "name" : "YesNoUnknown", + "title" : "Yes No Unknown", + "status" : "draft", + "description" : "Yes No Unknown", + "compose" : { + "include" : [{ + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown" + }] + } + }, + { + "resourceType" : "ValueSet", + "id" : "RashType", + "url" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/RashType", + "name" : "RashType", + "title" : "Rash Type", + "status" : "draft", + "description" : "Rash Type", + "compose" : { + "include" : [{ + "system" : "http://worldhealthorganization.github.io/smart-ot/RashType" + }] + } + }, + { + "resourceType" : "ValueSet", + "id" : "Antigen", + "url" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/Antigen", + "name" : "Antigen", + "title" : " Antigen", + "status" : "draft", + "description" : " Antigen", + "compose" : { + "include" : [{ + "system" : "http://worldhealthorganization.github.io/smart-ot/CodeSystem/AntigenCs" + }] + } + }, + { + "resourceType" : "ValueSet", + "id" : "Result", + "url" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/Result", + "name" : "Result", + "title" : " Result", + "status" : "draft", + "description" : " Result", + "compose" : { + "include" : [{ + "system" : "http://worldhealthorganization.github.io/smart-ot/Result" + }] + } + }], + "extension" : [{ + "url" : "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-targetStructureMap", + "valueCanonical" : "http://worldhealthorganization.github.io/smart-ot/StructureMap/MeaslesQuestionnaireToResources" + }], + "url" : "http://worldhealthorganization.github.io/smart-ot/Questionnaire/Questionnaire-SOTMeasles", + "version" : "0.2.1", + "name" : "Questionnaire-SOTMeasles", + "title" : "Measles Case Investigation Questionnaire", + "status" : "draft", + "subjectType" : ["Patient"], + "date" : "2023-10-25T15:37:05+02:00", + "publisher" : "WHO", + "contact" : [{ + "name" : "WHO", + "telecom" : [{ + "system" : "url", + "value" : "http://who.int" + }] + }], + "description" : "Measles Case Investigation Questionnaire", + "jurisdiction" : [{ + "coding" : [{ + "system" : "http://unstats.un.org/unsd/methods/m49/m49.htm", + "code" : "001" + }] + }], + "item" : [{ + "linkId" : "investigationForm", + "text" : "Investigation Form for Measles/Rubella", + "type" : "group", + "repeats" : false, + "item" : [{ + "linkId" : "description", + "text" : "Complete this form for: Any person in whom a health care worker suspects measles or rubella infection or a patient with fever and rash. The health worker should attempt to collect epidemiological and clinical data , as well as a blood sample , on the first contact with the patient. This contact with the patient might be the only one.", + "type" : "display", + "repeats" : false + }, + { + "linkId" : "reportingSource", + "text" : "Section I: Identification of the Reporting Institution", + "type" : "group", + "repeats" : false, + "item" : [{ + "linkId" : "initialDiagnosis", + "text" : "Initial Diagnosis", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/InitDiag" + }, + { + "linkId" : "caseID", + "text" : "Case Number", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "reportingInstitution", + "text" : "Reporting Institution", + "type" : "group", + "repeats" : false, + "item" : [{ + "linkId" : "reportingFacility", + "text" : "Health Service Name", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "telephone", + "text" : "Health Service Telephone", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "country", + "text" : "Country", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "municipality", + "text" : "Municipality", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "state", + "text" : "Province/State", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "locality", + "text" : "Locality/Neighborhood", + "type" : "string", + "repeats" : false + }] + }, + { + "linkId" : "reportedBy", + "text" : "Reported By", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "DateOfConsultation", + "text" : "Date Of Consultation", + "type" : "date", + "repeats" : false + }, + { + "linkId" : "DateOfHomeVisit", + "text" : "Date Of Home Visit", + "type" : "date", + "repeats" : false + }, + { + "linkId" : "dateReported", + "text" : "Date Reported - Local", + "type" : "date", + "repeats" : false + }, + { + "linkId" : "DateReportedNational", + "text" : "Date Reported - National", + "type" : "date", + "repeats" : false + }, + { + "linkId" : "DetectedBy", + "text" : "Detected By", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/DetectedBy" + }, + { + "linkId" : "TypeOfProviderReporting", + "text" : "Type Of Provider Reporting", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/ProvType" + }, + { + "linkId" : "specifyother", + "text" : "Specify", + "type" : "string", + "enableWhen" : [{ + "question" : "TypeOfProviderReporting", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/ProvType", + "code" : "88" + } + }], + "repeats" : false + }] + }, + { + "linkId" : "demographics", + "text" : "Section II: Patient Information", + "type" : "group", + "repeats" : false, + "item" : [{ + "linkId" : "name", + "text" : "Patient’s first and last names", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "guardian", + "text" : "Name of the mother or guardian", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "address", + "text" : "Address", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "telephone", + "text" : "Telephone", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "landmark", + "text" : "Landmarks to locate the house", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "occupation", + "text" : "Patient’s Occupation", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "localityType", + "text" : "Type of locality", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/LocType" + }, + { + "linkId" : "workAddress", + "text" : "Work or school address", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "sex", + "text" : "Patient’s sex", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/BiologicalSex" + }, + { + "linkId" : "DoB", + "text" : "Patient’s Date of Birth", + "type" : "date", + "repeats" : false + }, + { + "linkId" : "ageOnset", + "text" : "If date of birth is unknown, age", + "type" : "integer", + "repeats" : false + }] + }, + { + "linkId" : "vaccinationStatus", + "text" : "Section III: Vaccination History", + "type" : "group", + "repeats" : true, + "item" : [{ + "linkId" : "vaccineType", + "text" : "Type of Vaccine*", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/VaccineType" + }, + { + "linkId" : "noOfDoses", + "text" : "Number of doses**", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/NoOfDoses" + }, + { + "linkId" : "lastDoseDate", + "text" : "Date of last dose", + "type" : "date", + "repeats" : false + }, + { + "linkId" : "sourceOfInformation", + "text" : "Source of vaccination Information †", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/VaccineInfoSource" + }] + }, + { + "linkId" : "clinical", + "text" : "Section IV: Clinical Data; Follow-up & Treatment", + "type" : "group", + "repeats" : false, + "item" : [{ + "linkId" : "fever", + "text" : "Fever?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "temperature", + "text" : "If Yes, temperature (°)", + "type" : "decimal", + "enableWhen" : [{ + "question" : "fever", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "dateOfFeverOnset", + "text" : "Date of fever onset", + "type" : "date", + "enableWhen" : [{ + "question" : "fever", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "rash", + "text" : "Rash?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "rashDuration", + "text" : "If Yes, duration of the rash(in days)", + "type" : "integer", + "enableWhen" : [{ + "question" : "rash", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "rashOnsetDate", + "text" : "Date of rash onset", + "type" : "date", + "enableWhen" : [{ + "question" : "rash", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "rashType", + "text" : "Type of rash", + "type" : "choice", + "enableWhen" : [{ + "question" : "rash", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/RashType" + }, + { + "linkId" : "cough", + "text" : "Cough?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "conjunctivitis", + "text" : "Conjunctivitis?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "coryza", + "text" : "Coryza?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "koplikSpots", + "text" : "Koplik Spots?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "lymphadenopathy", + "text" : "Lymphadenopathy?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "jointPain", + "text" : "Arthralgia?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "pregnancy", + "text" : "Is the patient pregnant?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "monthsPregnant", + "text" : "Weeks of pregnancy (01-42)", + "type" : "integer", + "enableWhen" : [{ + "question" : "pregnancy", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "placeOfBirth", + "text" : "If Yes, Place where birth will likely take place", + "type" : "string", + "enableWhen" : [{ + "question" : "pregnancy", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "admitted", + "text" : "Hospitalized?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "admittedHCFName", + "text" : "Hospital name", + "type" : "string", + "enableWhen" : [{ + "question" : "admitted", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "admissionDate", + "text" : "If Yes, Date of admission", + "type" : "date", + "enableWhen" : [{ + "question" : "admitted", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "hospitalRecordNumber", + "text" : "Hospital record number", + "type" : "string", + "enableWhen" : [{ + "question" : "admitted", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "outcome", + "text" : "Death?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/PatientOutcome" + }, + { + "linkId" : "outcomeDate", + "text" : "If Yes, Date of death", + "type" : "date", + "enableWhen" : [{ + "question" : "outcome", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/PatientOutcome", + "code" : "Death" + } + }], + "repeats" : false + }, + { + "linkId" : "primaryCauseOfDeath", + "text" : "Primary cause of death", + "type" : "string", + "enableWhen" : [{ + "question" : "outcome", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/PatientOutcome", + "code" : "Death" + } + }], + "repeats" : false + }, + { + "linkId" : "diseaseAdditionalInfo", + "text" : "Comments", + "type" : "string", + "repeats" : false + }] + }, + { + "linkId" : "laboratoryResults", + "text" : "Section V: Specimens & Laboratory Testing", + "type" : "group", + "repeats" : false, + "item" : [{ + "linkId" : "specimenNumber", + "text" : "Specimen number*", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/SpecimenNumber" + }, + { + "linkId" : "sampleType", + "text" : "Type of specimen**", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/SampleType" + }, + { + "linkId" : "collectionDate", + "text" : "Date specimen obtained", + "type" : "date", + "repeats" : false + }, + { + "linkId" : "labName", + "text" : "Laboratory Name", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "specimenSentDate", + "text" : "Date specimen was sent to lab", + "type" : "date", + "repeats" : false + }, + { + "linkId" : "specimenReceivedDate", + "text" : "Date Received", + "type" : "date", + "repeats" : false + }, + { + "linkId" : "sampleId", + "text" : "# specimen ID in lab.", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "testPerformed", + "text" : "Type of test", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/TestPerformed" + }, + { + "linkId" : "antigen", + "text" : "Antigen", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/Antigen" + }, + { + "linkId" : "result", + "text" : "Result", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/Result" + }, + { + "linkId" : "resultDate", + "text" : "Date of Results", + "type" : "date", + "repeats" : false + }, + { + "linkId" : "specifyVirus", + "text" : "If virus was detected, specify viral genotype: (Measles: A, B1, B2, B3, C1, C2, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, E, F, G1, G2, G3, H1, H2. Rubella: 1a, 1B, 1C,\r\n1D, 1E, 1F, 1g, 2A, 2B, 2c)", + "type" : "string", + "repeats" : false + }] + }, + { + "linkId" : "contactTracing", + "text" : "Section VI: Investigation", + "type" : "group", + "repeats" : false, + "item" : [{ + "linkId" : "caseSearchConducted", + "text" : "Were active case-searches conducted?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "noOfsuspectCases", + "text" : "If Yes, Number of suspect cases detected during active case-search", + "type" : "integer", + "enableWhen" : [{ + "question" : "caseSearchConducted", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "pregnantContact", + "text" : "Was the patient in contact with any pregnant woman?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "pregnantContactNames", + "text" : "If Yes, Name(s)", + "type" : "string", + "enableWhen" : [{ + "question" : "pregnantContact", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "localCasesPresent", + "text" : "Are there other cases present in the case’s municipality of residence?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/LocalCasesPresent" + }, + { + "linkId" : "travelledOutside", + "text" : "Did the patient travel outside his/her province/state of residence 7-23 days before rash onset?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "travelDetails", + "text" : "If Yes,:", + "type" : "group", + "enableWhen" : [{ + "question" : "travelledOutside", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : true, + "item" : [{ + "linkId" : "placeOfTravel", + "text" : "Cities/Countries", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "arrivalDate", + "text" : "Date of arrival", + "type" : "date", + "repeats" : false + }, + { + "linkId" : "departureDate", + "text" : "Date of departure", + "type" : "date", + "repeats" : false + }] + }, + { + "linkId" : "infectionSetting", + "text" : "Setting where infected?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/InfectionSetting" + }, + { + "linkId" : "specifyInfectionSetting", + "text" : "Specify", + "type" : "string", + "enableWhen" : [{ + "question" : "infectionSetting", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/InfectionSetting", + "code" : "88" + } + }], + "repeats" : false + }] + }, + { + "linkId" : "epiData", + "text" : "Section VII: Response Measures", + "type" : "group", + "repeats" : false, + "item" : [{ + "linkId" : "ringVaccination", + "text" : "Ring vaccination?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "dateStarted", + "text" : "Date started", + "type" : "date", + "enableWhen" : [{ + "question" : "ringVaccination", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "dateEnded", + "text" : "Date Ended", + "type" : "date", + "enableWhen" : [{ + "question" : "ringVaccination", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "noOfDosesRingVaccination", + "text" : "Number of doses given during ring vaccination", + "type" : "integer", + "enableWhen" : [{ + "question" : "ringVaccination", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "rapidCoverageMonitioring", + "text" : "Was rapid coverage monitoring done", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "percentVaccinated", + "text" : "If yes, what % of vaccinated persons was found?", + "type" : "integer", + "enableWhen" : [{ + "question" : "rapidCoverageMonitioring", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "contactTracingDone", + "text" : "Were the contacts followed for up to 30 days after the date of the rash onset of the case?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "lastFollowUp", + "text" : "If yes, date of the last day of contact follow-up", + "type" : "date", + "enableWhen" : [{ + "question" : "contactTracingDone", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }] + }, + { + "linkId" : "classification", + "text" : "Section VIII: Classification", + "type" : "group", + "repeats" : false, + "item" : [{ + "linkId" : "finalClassification", + "text" : "Final Classification", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/FinalClassification" + }, + { + "linkId" : "confirmationBasis", + "text" : "Basis for confirmation", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/ConfirmationBasis" + }, + { + "linkId" : "countryImportation", + "text" : "If Imported or Import-related, Country of importation", + "type" : "string", + "enableWhen" : [{ + "question" : "confirmationBasis", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/ConfirmationBasis", + "code" : "1" + } + }], + "repeats" : false + }, + { + "linkId" : "discardingBasis", + "text" : "Basis for discarding", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/DiscardingBasis" + }, + { + "linkId" : "sourceOfInfection", + "text" : "For confirmed cases, Source of infection", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/SourceOfInfection" + }, + { + "linkId" : "contact", + "text" : "Contact of another case?", + "type" : "choice", + "repeats" : false, + "answerValueSet" : "http://worldhealthorganization.github.io/smart-ot/ValueSet/YesNoUnknown" + }, + { + "linkId" : "contactCaseNo", + "text" : "Contact of (or epidemiologically-linked to) case number", + "type" : "string", + "enableWhen" : [{ + "question" : "contact", + "operator" : "=", + "answerCoding" : { + "system" : "http://worldhealthorganization.github.io/smart-ot/YesNoUnknown", + "code" : "Yes" + } + }], + "repeats" : false + }, + { + "linkId" : "classifiedBy", + "text" : "Classified by", + "type" : "string", + "repeats" : false + }, + { + "linkId" : "classificationDate", + "text" : "Date of final classification", + "type" : "date", + "repeats" : false + }] + }] + }] +} \ No newline at end of file diff --git a/datacapture/sampledata/measles-outbreak/questionnaire_response_outbreak.json b/datacapture/sampledata/measles-outbreak/questionnaire_response_outbreak.json new file mode 100644 index 0000000000..cf9e787433 --- /dev/null +++ b/datacapture/sampledata/measles-outbreak/questionnaire_response_outbreak.json @@ -0,0 +1,1234 @@ +{ + "resourceType": "QuestionnaireResponse", + "id":"response1", + "meta": { + "profile": [ + "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaireresponse|2.7" + ], + "tag": [ + { + "code": "lformsVersion: 29.3.1" + } + ] + }, + "status": "completed", + "authored": "2023-08-12T03:00:53.426Z", + "item": [ + { + "linkId": "investigationForm", + "text": "Investigation Form for Measles/Rubella", + "item": [ + { + "linkId": "reportingSource", + "text": "Section I: Identification of the Reporting Institution", + "item": [ + { + "linkId": "initialDiagnosis", + "text": "Initial Diagnosis", + "answer": [ + { + "valueCoding": { + "system": "http://worldhealthorganization.github.io/smart-ot/InitDiag", + "code": "1", + "display": "Measles" + } + } + ] + }, + { + "linkId": "caseID", + "text": "Case Number", + "answer": [ + { + "valueString": "12345" + } + ] + }, + { + "linkId": "reportingInstitution", + "text": "Reporting Institution", + "item": [ + { + "linkId": "reportingFacility", + "text": "Health Service Name", + "answer": [ + { + "valueString": "hospital" + } + ] + }, + { + "linkId": "telephone", + "text": "Health Service Telephone", + "answer": [ + { + "valueString": "123-phone" + } + ] + }, + { + "linkId": "country", + "text": "Country", + "answer": [ + { + "valueString": "Utopia" + } + ] + }, + { + "linkId": "municipality", + "text": "Municipality", + "answer": [ + { + "valueString": "City" + } + ] + }, + { + "linkId": "state", + "text": "Province/State", + "answer": [ + { + "valueString": "State" + } + ] + }, + { + "linkId": "locality", + "text": "Locality/Neighborhood", + "answer": [ + { + "valueString": "Locality" + } + ] + } + ] + }, + { + "linkId": "reportedBy", + "text": "Reported By", + "answer": [ + { + "valueString": "reporter" + } + ] + }, + { + "linkId": "DateOfConsultation", + "text": "Date Of Consultation", + "answer": [ + { + "valueDate": "2023-08-11" + } + ] + }, + { + "linkId": "DateOfHomeVisit", + "text": "Date Of Home Visit", + "answer": [ + { + "valueDate": "2023-08-10" + } + ] + }, + { + "linkId": "dateReported", + "text": "Date Reported - Local", + "answer": [ + { + "valueDate": "2023-08-09" + } + ] + }, + { + "linkId": "DateReportedNational", + "text": "Date Reported - National", + "answer": [ + { + "valueDate": "2023-08-08" + } + ] + } + ] + }, + { + "linkId": "demographics", + "text": "Section II: Patient Information", + "item": [ + { + "linkId": "name", + "text": "Patient’s first and last names", + "answer": [ + { + "valueString": "John Doe" + } + ] + }, + { + "linkId": "guardian", + "text": "Name of the mother or guardian", + "answer": [ + { + "valueString": "Mother Doe" + } + ] + }, + { + "linkId": "sex", + "text": "Patient’s sex", + "answer": [ + { + "valueCoding": { + "system": "http://hl7.org/fhir/administrative-gender", + "code": "male", + "display": "Male" + } + } + ] + }, + { + "linkId": "address", + "text": "Address", + "answer": [ + { + "valueString": "Avenue" + } + ] + }, + { + "linkId": "telephone", + "text": "Telephone", + "answer": [ + { + "valueString": "234phone" + } + ] + }, + { + "linkId": "landmark", + "text": "Landmarks to locate the house", + "answer": [ + { + "valueString": "Next the spot" + } + ] + }, + { + "linkId": "occupation", + "text": "Patient’s Occupation", + "answer": [ + { + "valueString": "Busy" + } + ] + }, + { + "linkId": "workAddress", + "text": "Work or school address", + "answer": [ + { + "valueString": "Workaddress" + } + ] + }, + { + "linkId": "DoB", + "text": "Patient’s Date of Birth", + "answer": [ + { + "valueDate": "2014-08-07" + } + ] + } + ] + }, + { + "linkId": "vaccinationStatus", + "text": "Section III: Vaccination History", + "item": [ + { + "linkId": "lastDoseDate", + "text": "Date of last dose", + "answer": [ + { + "valueDate": "2023-09-04" + } + ] + } + ] + }, + { + "linkId": "vaccinationStatus", + "text": "Section III: Vaccination History", + "item": [ + { + "linkId": "sourceOfInformation", + "text": "Source of vaccination Information †", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/SourceOfInformation", + "code": "Vaccinationcard", + "display": "Vaccination card" + } + } + ] + }, + { + "linkId": "noOfDoses", + "text": "Number of doses**", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/NoOfDoses", + "code": "2", + "display": "Two dose" + } + } + ] + }, + { + "linkId": "vaccineType", + "text": "Type of Vaccine", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/VaccineType", + "code": "1", + "display": "Measles" + } + } + ] + } + ] + }, + { + "linkId": "vaccinationStatus", + "text": "Section III: Vaccination History", + "item": [ + { + "linkId": "lastDoseDate", + "text": "Date of last dose", + "answer": [ + { + "valueDate": "2023-09-04" + } + ] + }, + { + "linkId": "sourceOfInformation", + "text": "Source of vaccination Information †", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/SourceOfInformation", + "code": "HealthServices", + "display": "Health Services" + } + } + ] + }, + { + "linkId": "noOfDoses", + "text": "Number of doses**", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/NoOfDoses", + "code": "1", + "display": "One dose" + } + } + ] + }, + { + "linkId": "vaccineType", + "text": "Type of Vaccine", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/VaccineType", + "code": "2", + "display": "Rubella" + } + } + ] + } + ] + }, + { + "linkId": "clinical", + "text": "Section IV: Clinical Data; Follow-up & Treatment", + "item": [ + { + "linkId": "fever", + "text": "Fever?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "temperature", + "text": "If Yes, temperature (°)", + "answer": [ + { + "valueDecimal": 32 + } + ] + }, + { + "linkId": "dateOfFeverOnset", + "text": "Date of fever onset", + "answer": [ + { + "valueDate": "2023-09-04" + } + ] + }, + { + "linkId": "rash", + "text": "Rash?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "rashDuration", + "text": "If Yes, duration of the rash(in days)", + "answer": [ + { + "valueInteger": 4 + } + ] + }, + { + "linkId": "rashOnsetDate", + "text": "Date of rash onset", + "answer": [ + { + "valueDate": "2023-09-04" + } + ] + }, + { + "linkId": "rashType", + "text": "Type of rash", + "answer": [ + { + "valueCoding": { + "system": "http://worldhealthorganization.github.io/smart-ot/RashType", + "code": "Haemorrhagic", + "display": "Haemorrhagic" + } + } + ] + }, + { + "linkId": "cough", + "text": "Cough?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "conjunctivitis", + "text": "Conjunctivitis?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "coryza", + "text": "Coryza?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "koplikSpots", + "text": "Koplik Spots?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "lymphadenopathy", + "text": "Lymphadenopathy?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "jointPain", + "text": "Arthralgia?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "pregnancy", + "text": "Is the patient pregnant?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "monthsPregnant", + "text": "Weeks of pregnancy (01-42)", + "answer": [ + { + "valueInteger": 42 + } + ] + }, + { + "linkId": "placeOfBirth", + "text": "If Yes, Place where birth will likely take place", + "answer": [ + { + "valueString": "sdsdd" + } + ] + }, + { + "linkId": "admitted", + "text": "Hospitalized?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "admittedHCFName", + "text": "Hospital name", + "answer": [ + { + "valueString": "test" + } + ] + }, + { + "linkId": "admissionDate", + "text": "If Yes, Date of admission", + "answer": [ + { + "valueDate": "2023-09-04" + } + ] + }, + { + "linkId": "hospitalRecordNumber", + "text": "Hospital record number", + "answer": [ + { + "valueString": "2435" + } + ] + }, + { + "linkId": "outcome", + "text": "Death?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/PatientOutcome", + "code": "Sick", + "display": "Still sick" + } + } + ] + }, + { + "linkId": "diseaseAdditionalInfo", + "text": "Comments", + "answer": [ + { + "valueString": "bard" + } + ] + } + ] + }, + { + "linkId": "classification", + "text": "Section VIII: Classification", + "item": [ + { + "linkId": "finalClassification", + "text": "Final Classification", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/FinalClassification", + "code": "1", + "display": "Measles" + } + } + ] + }, + { + "linkId": "confirmationBasis", + "text": "Basis for confirmation", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/ConfirmationBasis", + "code": "1", + "display": "Laboratory" + } + } + ] + }, + { + "linkId": "countryImportation", + "text": "If Imported or Import-related, Country of importation", + "answer": [ + { + "valueString": "tqdas" + } + ] + }, + { + "linkId": "discardingBasis", + "text": "Basis for discarding", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/DiscardingBasis", + "code": "1", + "display": "Measles/Rubella IgM-neg" + } + } + ] + }, + { + "linkId": "sourceOfInfection", + "text": "For confirmed cases, Source of infection", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/SourceOfInfection", + "code": "1", + "display": "Imported" + } + } + ] + }, + { + "linkId": "contact", + "text": "Contact of another case?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "contactCaseNo", + "text": "Contact of (or epidemiologically-linked to) case number", + "answer": [ + { + "valueString": "354w" + } + ] + }, + { + "linkId": "classifiedBy", + "text": "Classified by", + "answer": [ + { + "valueString": "ritika" + } + ] + }, + { + "linkId": "classificationDate", + "text": "Date of final classification", + "answer": [ + { + "valueDate": "2023-09-08" + } + ] + } + ] + }, + { + "linkId": "epiData", + "text": "Section VII: Response Measures", + "item": [ + { + "linkId": "ringVaccination", + "text": "Ring vaccination?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "dateStarted", + "text": "Date started", + "answer": [ + { + "valueDate": "2023-08-27" + } + ] + }, + { + "linkId": "dateEnded", + "text": "Date Ended", + "answer": [ + { + "valueDate": "2023-09-19" + } + ] + }, + { + "linkId": "noOfDosesRingVaccination", + "text": "Number of doses given during ring vaccination", + "answer": [ + { + "valueInteger": 5 + } + ] + }, + { + "linkId": "rapidCoverageMonitioring", + "text": "Was rapid coverage monitoring done", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "percentVaccinated", + "text": "If yes, what % of vaccinated persons was found?", + "answer": [ + { + "valueInteger": 65 + } + ] + }, + { + "linkId": "contactTracingDone", + "text": "Were the contacts followed for up to 30 days after the date of the rash onset of the case?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "lastFollowUp", + "text": "If yes, date of the last day of contact follow-up", + "answer": [ + { + "valueDate": "2023-09-26" + } + ] + } + ] + }, + { + "linkId": "contactTracing", + "text": "Section VI: Investigation", + "item": [ + { + "linkId": "caseSearchConducted", + "text": "Were active case-searches conducted?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "noOfsuspectCases", + "text": "If Yes, Number of suspect cases detected during active case-search", + "answer": [ + { + "valueInteger": 4 + } + ] + }, + { + "linkId": "pregnantContact", + "text": "Was the patient in contact with any pregnant woman?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "pregnantContactNames", + "text": "If Yes, Name(s)", + "answer": [ + { + "valueString": "Ritika Rawlani" + } + ] + }, + { + "linkId": "localCasesPresent", + "text": "Are there other cases present in the case’s municipality of residence?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/LocalCasesPresent", + "code": "1", + "display": "Yes, with measles" + } + } + ] + }, + { + "linkId": "travelledOutside", + "text": "Did the patient travel outside his/her province/state of residence 7-23 days before rash onset?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/YesNoUnknown", + "code": "Yes", + "display": "Yes" + } + } + ] + }, + { + "linkId": "travelDetails", + "text": "If Yes,:", + "item": [ + { + "linkId": "placeOfTravel", + "text": "Cities/Countries", + "answer": [ + { + "valueString": "India" + } + ] + }, + { + "linkId": "arrivalDate", + "text": "Date of arrival", + "answer": [ + { + "valueDate": "2023-09-03" + } + ] + }, + { + "linkId": "departureDate", + "text": "Date of departure", + "answer": [ + { + "valueDate": "2023-09-08" + } + ] + } + ] + }, + { + "linkId": "travelDetails", + "text": "If Yes,:", + "item": [ + { + "linkId": "placeOfTravel", + "text": "Cities/Countries", + "answer": [ + { + "valueString": "malaysia" + } + ] + }, + { + "linkId": "arrivalDate", + "text": "Date of arrival", + "answer": [ + { + "valueDate": "2023-08-28" + } + ] + }, + { + "linkId": "departureDate", + "text": "Date of departure", + "answer": [ + { + "valueDate": "2023-08-30" + } + ] + } + ] + }, + { + "linkId": "infectionSetting", + "text": "Setting where infected?", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/InfectionSetting", + "code": "1", + "display": "Household contact" + } + } + ] + } + ] + }, + { + "linkId": "laboratoryResults", + "text": "Section V: Specimens & Laboratory Testing", + "item": [ + { + "linkId": "specimenNumber", + "text": "Specimen number*", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/SpecimenNumber", + "code": "1", + "display": "First Sample" + } + } + ] + }, + { + "linkId": "sampleType", + "text": "Type of specimen**", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/SampleType", + "code": "2", + "display": "Nasopharyngeal aspirate/swab" + } + } + ] + }, + { + "linkId": "collectionDate", + "text": "Date specimen obtained", + "answer": [ + { + "valueDate": "2023-08-29" + } + ] + }, + { + "linkId": "labName", + "text": "Laboratory Name", + "answer": [ + { + "valueString": "Lab name" + } + ] + }, + { + "linkId": "specimenSentDate", + "text": "Date specimen was sent to lab", + "answer": [ + { + "valueDate": "2023-09-25" + } + ] + }, + { + "linkId": "specimenReceivedDate", + "text": "Date Received", + "answer": [ + { + "valueDate": "2023-09-25" + } + ] + }, + { + "linkId": "sampleId", + "text": "# specimen ID in lab.", + "answer": [ + { + "valueString": "3456666" + } + ] + }, + { + "linkId": "testPerformed", + "text": "Type of test", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/TestPerformed", + "code": "1", + "display": "IgM EIA/Indirect" + } + } + ] + }, + { + "linkId": "antigen", + "text": "Antigen", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/Antigen", + "code": "1", + "display": "Measles" + } + } + ] + }, + { + "linkId": "result", + "text": "Result", + "answer": [ + { + "valueCoding": { + "system": "http://ritikarawlani.github.io/smart-outbreak-measles/Result", + "code": "0", + "display": "Negative" + } + } + ] + }, + { + "linkId": "resultDate", + "text": "Date of Results", + "answer": [ + { + "valueDate": "2023-09-26" + } + ] + }, + { + "linkId": "specifyVirus", + "text": "If virus was detected, specify viral genotype: (Measles: A, B1, B2, B3, C1, C2, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, E, F, G1, G2, G3, H1, H2. Rubella: 1a, 1B, 1C,\n1D, 1E, 1F, 1g, 2A, 2B, 2c)", + "answer": [ + { + "valueString": "B1" + } + ] + } + ] + } , + { + "linkId": "laboratoryResults", + "text": "Section V: Specimens & Laboratory Testing", + "item": [ + { + "linkId": "specimenNumber", + "text": "Specimen number*", + "answer": [ + { + "valueCoding": { + "system": "http://worldhealthorganization.github.io/smart-ot/SpecimenNumber", + "code": "2", + "display": "Second Sample" + } + } + ] + }, + { + "linkId": "sampleType", + "text": "Type of specimen**", + "answer": [ + { + "valueCoding": { + "system": "http://worldhealthorganization.github.io/smart-ot/SampleType", + "code": "1", + "display": "Serum" + } + } + ] + }, + { + "linkId": "collectionDate", + "text": "Date specimen obtained", + "answer": [ + { + "valueDate": "2023-10-10" + } + ] + }, + { + "linkId": "labName", + "text": "Laboratory Name", + "answer": [ + { + "valueString": "dr pathlabs" + } + ] + }, + { + "linkId": "specimenSentDate", + "text": "Date specimen was sent to lab", + "answer": [ + { + "valueDate": "2023-10-10" + } + ] + }, + { + "linkId": "specimenReceivedDate", + "text": "Date Received", + "answer": [ + { + "valueDate": "2023-10-10" + } + ] + }, + { + "linkId": "sampleId", + "text": "# specimen ID in lab.", + "answer": [ + { + "valueString": "232456" + } + ] + }, + { + "linkId": "testPerformed", + "text": "Type of test", + "answer": [ + { + "valueCoding": { + "system": "http://worldhealthorganization.github.io/smart-ot/TestPerformed", + "code": "1", + "display": "IgM EIA/Indirect" + } + } + ] + }, + { + "linkId": "antigen", + "text": "Antigen", + "answer": [ + { + "valueCoding": { + "system": "http://worldhealthorganization.github.io/smart-ot/Antigen", + "code": "1", + "display": "Measles" + } + } + ] + }, + { + "linkId": "result", + "text": "Result", + "answer": [ + { + "valueCoding": { + "system": "http://worldhealthorganization.github.io/smart-ot/Result", + "code": "0", + "display": "Negative" + } + } + ] + }, + { + "linkId": "resultDate", + "text": "Date of Results", + "answer": [ + { + "valueDate": "2023-10-24" + } + ] + }, + { + "linkId": "specifyVirus", + "text": "If virus was detected, specify viral genotype: (Measles: A, B1, B2, B3, C1, C2, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, E, F, G1, G2, G3, H1, H2. Rubella: 1a, 1B, 1C,\n1D, 1E, 1F, 1g, 2A, 2B, 2c)", + "answer": [ + { + "valueString": "dq" + } + ] + } + ] + } + + ]}], + "questionnaire": "http://worldhealthorganization.github.io/smart-ot/Questionnaire/Questionnaire-SOTMeasles" +} \ No newline at end of file diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt index 8ac61a19c0..34208ad29b 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/DataCaptureConfig.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Google LLC + * Copyright 2022-2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,11 +21,8 @@ import android.graphics.Bitmap import com.google.android.fhir.datacapture.DataCaptureConfig.Provider import com.google.android.fhir.datacapture.QuestionnaireFragment.QuestionnaireItemViewHolderFactoryMatcher import com.google.android.fhir.datacapture.QuestionnaireFragment.QuestionnaireItemViewHolderFactoryMatchersProvider -import org.hl7.fhir.r4.context.SimpleWorkerContext import org.hl7.fhir.r4.model.Coding import org.hl7.fhir.r4.model.Resource -import org.hl7.fhir.r4.model.StructureMap -import org.hl7.fhir.utilities.npm.NpmPackage /** * The App developers may provide the [DataCaptureConfig] for the DataCapture library by @@ -42,15 +39,6 @@ data class DataCaptureConfig( */ var valueSetResolverExternal: ExternalAnswerValueSetResolver? = null, - /** - * A [NpmPackage] may be set by the client for Structure-Map based Resource Extraction. - * - * The loading and extraction of a [NpmPackage] may take multiple seconds, so the client app - * should try to include the smallest [NpmPackage] possible that contains only the resources - * needed by [StructureMap]s used by the client app. - */ - var npmPackage: NpmPackage? = null, - /** * A [XFhirQueryResolver] may be set by the client to resolve x-fhir-query for the library. See * https://build.fhir.org/ig/HL7/sdc/expressions.html#fhirquery for more details. @@ -70,10 +58,6 @@ data class DataCaptureConfig( null, ) { - internal val simpleWorkerContext: SimpleWorkerContext by lazy { - if (npmPackage == null) SimpleWorkerContext() else SimpleWorkerContext.fromPackage(npmPackage) - } - /** * A class that can provide the [DataCaptureConfig] for the Structured Data Capture Library. To do * this, implement the [DataCaptureConfig.Provider] interface on your [Application] class. You diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/mapping/ResourceMapper.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/mapping/ResourceMapper.kt index fd9f52d43a..f1f47495e9 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/mapping/ResourceMapper.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/mapping/ResourceMapper.kt @@ -16,7 +16,6 @@ package com.google.android.fhir.datacapture.mapping -import com.google.android.fhir.datacapture.DataCapture import com.google.android.fhir.datacapture.extensions.createQuestionnaireResponseItem import com.google.android.fhir.datacapture.extensions.filterByCodeInNameExtension import com.google.android.fhir.datacapture.extensions.initialExpression @@ -199,18 +198,16 @@ object ResourceMapper { structureMapExtractionContext: StructureMapExtractionContext, ): Bundle { val structureMapProvider = structureMapExtractionContext.structureMapProvider - val simpleWorkerContext = - DataCapture.getConfiguration(structureMapExtractionContext.context) - .simpleWorkerContext - .apply { setExpansionProfile(Parameters()) } - val structureMap = structureMapProvider(questionnaire.targetStructureMap!!, simpleWorkerContext) + val iWorkerContext = + structureMapExtractionContext.workerContext.apply { setExpansionProfile(Parameters()) } + val structureMap = structureMapProvider(questionnaire.targetStructureMap!!, iWorkerContext) return Bundle().apply { StructureMapUtilities( - simpleWorkerContext, + iWorkerContext, structureMapExtractionContext.transformSupportServices, ) - .transform(simpleWorkerContext, questionnaireResponse, structureMap, this) + .transform(iWorkerContext, questionnaireResponse, structureMap, this) } } diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/mapping/StructureMapExtractionContext.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/mapping/StructureMapExtractionContext.kt index 19b2512b0f..2509a5d753 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/mapping/StructureMapExtractionContext.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/mapping/StructureMapExtractionContext.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Google LLC + * Copyright 2022-2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,24 @@ package com.google.android.fhir.datacapture.mapping -import android.content.Context import org.hl7.fhir.r4.context.IWorkerContext +import org.hl7.fhir.r4.context.SimpleWorkerContext import org.hl7.fhir.r4.model.StructureMap import org.hl7.fhir.r4.utils.StructureMapUtilities /** Data used during StructureMap-based extraction. */ data class StructureMapExtractionContext( - /** The application context. */ - val context: Context, /** * Optionally pass a custom version of [StructureMapUtilities.ITransformerServices] to support * specific use cases. */ val transformSupportServices: StructureMapUtilities.ITransformerServices? = null, + /** + * Optionally pass a custom version of [IWorkerContext]. + * + * @default [SimpleWorkerContext] + */ + val workerContext: IWorkerContext = SimpleWorkerContext(), /** * A lambda function which returns a [StructureMap]. Depending on your app this could be * hard-coded or use the [String] parameter to fetch the appropriate structure map. diff --git a/datacapture/src/test/java/com/google/android/fhir/datacapture/mapping/ResourceMapperTest.kt b/datacapture/src/test/java/com/google/android/fhir/datacapture/mapping/ResourceMapperTest.kt index b8bb271973..52d29f390e 100644 --- a/datacapture/src/test/java/com/google/android/fhir/datacapture/mapping/ResourceMapperTest.kt +++ b/datacapture/src/test/java/com/google/android/fhir/datacapture/mapping/ResourceMapperTest.kt @@ -26,6 +26,7 @@ import com.google.android.fhir.datacapture.extensions.CODE_SYSTEM_LAUNCH_CONTEXT import com.google.android.fhir.datacapture.extensions.EXTENSION_SDC_QUESTIONNAIRE_LAUNCH_CONTEXT import com.google.android.fhir.datacapture.extensions.ITEM_INITIAL_EXPRESSION_URL import com.google.android.fhir.datacapture.views.factories.localDate +import com.google.android.fhir.knowledge.KnowledgeManager import com.google.common.truth.Truth.assertThat import java.math.BigDecimal import java.text.SimpleDateFormat @@ -34,6 +35,9 @@ import java.util.UUID import kotlin.test.assertFailsWith import kotlinx.coroutines.runBlocking import org.hl7.fhir.exceptions.FHIRException +import org.hl7.fhir.r4.context.IWorkerContext +import org.hl7.fhir.r4.context.SimpleWorkerContext +import org.hl7.fhir.r4.elementmodel.Manager import org.hl7.fhir.r4.model.Address import org.hl7.fhir.r4.model.Base import org.hl7.fhir.r4.model.BooleanType @@ -52,11 +56,15 @@ import org.hl7.fhir.r4.model.Patient import org.hl7.fhir.r4.model.Questionnaire import org.hl7.fhir.r4.model.QuestionnaireResponse import org.hl7.fhir.r4.model.Reference +import org.hl7.fhir.r4.model.Resource import org.hl7.fhir.r4.model.ResourceFactory +import org.hl7.fhir.r4.model.ResourceType import org.hl7.fhir.r4.model.StringType +import org.hl7.fhir.r4.model.StructureDefinition import org.hl7.fhir.r4.model.codesystems.AdministrativeGender import org.hl7.fhir.r4.terminologies.ConceptMapEngine import org.hl7.fhir.r4.utils.StructureMapUtilities +import org.hl7.fhir.utilities.npm.NpmPackage import org.intellij.lang.annotations.Language import org.junit.Test import org.junit.runner.RunWith @@ -69,6 +77,8 @@ class ResourceMapperTest { private val context = ApplicationProvider.getApplicationContext() private val iParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() + private val knowledgeManager = KnowledgeManager.create(context, inMemory = true) + @Test fun `extract() should perform definition-based extraction`() = runBlocking { // https://developer.commure.com/docs/apis/sdc/examples#definition-based-extraction @@ -2340,7 +2350,7 @@ class ResourceMapperTest { ResourceMapper.extract( uriTestQuestionnaire, uriTestQuestionnaireResponse, - StructureMapExtractionContext(context = context) { _, worker -> + StructureMapExtractionContext { _, worker -> StructureMapUtilities(worker).parse(mapping, "") }, ) @@ -2431,7 +2441,7 @@ class ResourceMapperTest { ResourceMapper.extract( uriTestQuestionnaire, uriTestQuestionnaireResponse, - StructureMapExtractionContext(context, transformSupportServices) { _, worker -> + StructureMapExtractionContext(transformSupportServices) { _, worker -> StructureMapUtilities(worker).parse(mapping, "") }, ) @@ -3051,6 +3061,56 @@ class ResourceMapperTest { .containsExactly("TestName-First", "TestName-Middle") } + @Test + fun `extract() should perform StructureMap-based extraction using workerContext from knowledge-manager`(): + Unit = runBlocking { + val questionnaireString = + readFileFromResourcesAsString("/measles-outbreak/questionnaire_outbreak.json") + val questionnaire = + iParser.parseResource(Questionnaire::class.java, questionnaireString) as Questionnaire + + val questionnaireResponseString = + readFileFromResourcesAsString("/measles-outbreak/questionnaire_response_outbreak.json") + + val questionnaireResponse = + iParser.parseResource(QuestionnaireResponse::class.java, questionnaireResponseString) + as QuestionnaireResponse + val structureMap = + readFileFromResourcesAsString("/measles-outbreak/MeaslesQuestionnaireToResources.map") + + val measlesOutbreakPackage = + NpmPackage.fromPackage(readFileFromResources("/measles-outbreak/package.r4.tgz")) + val basePackage = NpmPackage.fromPackage(readFileFromResources("/measles-outbreak/package.tgz")) + + val workerContext = knowledgeManager.loadWorkerContext(measlesOutbreakPackage, basePackage) + val transformSupportServices = + TransformSupportServicesLogicalModel(workerContext, mutableListOf()) + + val bundle = + ResourceMapper.extract( + questionnaire, + questionnaireResponse, + StructureMapExtractionContext( + transformSupportServices, + workerContext = workerContext, + ) { _, worker -> + StructureMapUtilities(worker).parse(structureMap, "MeaslesQuestionnaireToResources") + }, + ) + + assertThat(bundle).isNotNull() + assertThat(bundle.entry).isNotEmpty() + + val patient = + bundle.entry.find { it.resource.resourceType == ResourceType.Patient }?.resource as Patient + assertThat(patient.name.first().family).isEqualTo("John Doe") + } + + private fun readFileFromResourcesAsString(filename: String) = + readFileFromResources(filename).bufferedReader().use { it.readText() } + + private fun readFileFromResources(filename: String) = javaClass.getResourceAsStream(filename)!! + private fun String.toDateFromFormatYyyyMmDd(): Date? = SimpleDateFormat("yyyy-MM-dd").parse(this) class TransformSupportServices(private val outputs: MutableList) : @@ -3090,4 +3150,75 @@ class ResourceMapperTest { throw FHIRException("performSearch is not supported yet") } } + + /** + * Class providing transformer services for a specific context, utilizing a worker context and + * managing outputs. + * + * This class helps the two step structure map extraction. QuestionnaireResponse -> Logical Model + * Logical Model -> Resource's + * + * This was referred through + * [matchbox](https://github.com/ahdis/matchbox/blob/main/matchbox-engine/src/main/java/ch/ahdis/matchbox/mappinglanguage/TransformSupportServices.java) + * implementation. + * + * @param workerContext The worker context for managing resources and operations. + * @param outputs The list to which output resources are added. + */ + class TransformSupportServicesLogicalModel( + private val workerContext: IWorkerContext, + private val outputs: MutableList, + ) : StructureMapUtilities.ITransformerServices { + + override fun createType(appInfo: Any, name: String): Base { + return try { + ResourceFactory.createResourceOrType(name) + } catch (fhirException: FHIRException) { + Manager.build( + workerContext, + workerContext.fetchResource( + StructureDefinition::class.java, + name, + ), + ) + } + } + + override fun createResource(appInfo: Any, res: Base, atRootofTransform: Boolean): Base { + if (atRootofTransform) outputs.add(res) + return try { + val fhirType = Enumerations.FHIRAllTypes.fromCode(res.fhirType()) + val constructor = + Class.forName( + "org.hl7.fhir.r4.model." + fhirType.display, + ) + .getConstructor() + constructor.newInstance() as Base + } catch (e: Exception) { + res + } + } + + override fun translate(appInfo: Any, source: Coding, conceptMapUrl: String): Coding? { + val conceptMapEngine = ConceptMapEngine(workerContext as SimpleWorkerContext) + return conceptMapEngine.translate(source, conceptMapUrl) + } + + override fun resolveReference( + appContext: Any, + url: String, + ): Base { + return workerContext.fetchResource( + Resource::class.java, + url, + ) + } + + @Throws(FHIRException::class) + override fun performSearch(appContext: Any, url: String): List { + throw FHIRException("performSearch is not supported yet") + } + + override fun log(message: String) {} + } } diff --git a/knowledge/src/main/java/com/google/android/fhir/knowledge/KnowledgeManager.kt b/knowledge/src/main/java/com/google/android/fhir/knowledge/KnowledgeManager.kt index 83c3d95990..194d080819 100644 --- a/knowledge/src/main/java/com/google/android/fhir/knowledge/KnowledgeManager.kt +++ b/knowledge/src/main/java/com/google/android/fhir/knowledge/KnowledgeManager.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023 Google LLC + * Copyright 2023-2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,10 +32,13 @@ import java.io.FileOutputStream import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.hl7.fhir.instance.model.api.IBaseResource +import org.hl7.fhir.r4.context.IWorkerContext +import org.hl7.fhir.r4.context.SimpleWorkerContext import org.hl7.fhir.r4.model.IdType import org.hl7.fhir.r4.model.MetadataResource import org.hl7.fhir.r4.model.Resource import org.hl7.fhir.r4.model.ResourceType +import org.hl7.fhir.utilities.npm.NpmPackage import timber.log.Timber /** @@ -189,6 +192,34 @@ internal constructor( return knowledgeDao.insertResource(igId, res) } + /** + * Loads and initializes a worker context with the specified npm packages. + * + * This + * [sample](https://github.com/google/android-fhir/blob/385dc32f2706ad5520c121bf39478a105a5d46eb/datacapture/src/test/java/com/google/android/fhir/datacapture/mapping/ResourceMapperTest.kt#L3065) + * test demonstrates how to use `loadWorkerContext` API. + * + * @param npmPackages The npm packages to be loaded into the worker context. + * @param allowLoadingDuplicates Flag indicating whether loading duplicate packages is allowed. + * Default is true. + * @param loader Custom resource loader for the worker context. Default is null, meaning the + * default loader will be used. + * @return An initialized instance of [IWorkerContext]. + */ + suspend fun loadWorkerContext( + vararg npmPackages: NpmPackage, + allowLoadingDuplicates: Boolean = true, + loader: SimpleWorkerContext.IContextResourceLoader? = null, + ): IWorkerContext { + return withContext(Dispatchers.IO) { + val simpleWorkerContext = SimpleWorkerContext() + simpleWorkerContext.apply { + isAllowLoadingDuplicates = allowLoadingDuplicates + npmPackages.forEach { npmPackage -> loadFromPackage(npmPackage, loader) } + } + } + } + private fun loadResource(resourceEntity: ResourceMetadataEntity): IBaseResource { return jsonParser.parseResource(FileInputStream(resourceEntity.resourceFile)) }