opensrp / fhircore

FHIR Core / OpenSRP 2 is a Kotlin application for delivering offline-capable, mobile-first healthcare project implementations from local community to national and international scale using FHIR and WHO Smart Guidelines on Android.
https://smartregister.org
Apache License 2.0
50 stars 41 forks source link

[Bug šŸ› ] Failing FHIRPath expression evaluation #3081

Closed f-odhiambo closed 4 months ago

f-odhiambo commented 5 months ago

Unable to evaluate FHIRPath expression on some of the Questionnaires on the main branch

Issues

  1. Evaluate Date to Age in intergers
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "calc-age",
        "language": "text/fhirpath",
        "expression": "(((%calc-year * 365.25) + (%calc-month * 365.25 / 12)) / 365.25).toString().replaceMatches('[.]+[0-9]+', '').toInteger()"
      }
    }
  1. Prepopolute data based on previously collected data from a given resource
 {
      "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerExpression",
      "valueExpression": {
        "name": "prev-vaccine",
        "language": "application/x-fhir-query",
        "expression": "Immunization?patient=Patient/adef6a88-346c-45fa-a00d-aa23d702785f&reason-code=840534001&_sort=-date&_count=1"
      }
    },

Sample Questionnaires

  1. https://github.com/onaio/fhir-resources/blob/main/zeir_zambia/questionnaire/patient/patient_registration.json
  2. https://github.com/onaio/fhir-resources/blob/main/zeir_zambia/questionnaire/immunization/covid-19.fhir.json
maimoonak commented 5 months ago

Covid 19 vaccine SM output has 2 issues

1- Task.for has invalid reference

  1. The Task.reasonReference Questionnanire does not exists select * from resourceentity where resourceId = 'e8572c86-065d-11ee-be56-0242ac120002'
[{"resourceType":"Task","id":"6ecc513f-ff15-48e8-860b-e0a5fa967d43","identifier":[{"use":"official","value":"ca8e561b-1e8a-41aa-bcf9-c60182ae5e09"}],"basedOn":[{"reference":"CarePlan/341ea420-a1d0-4c32-b169-49e5ce5e1ad3"}],"status":"requested","intent":"plan","priority":"routine","code":{"coding":[{"system":"http://snomed.info/sct","code":"840534001","display":"SARS-CoV-2 vaccination"}]},"description":"AstraZeneca 2 at 70 d","for":{"reference":"Patient/Patient/19f81214-8d70-4866-9e29-1eb29f262b79"},"executionPeriod":{"start":"2024-03-11T00:00:00+05:00"},"authoredOn":"2024-02-20T17:48:22+05:00","requester":{"reference":"Practitioner/6e744577-cf1c-4876-a122-2d0e9c5e0f23"},"owner":{"reference":"Practitioner/6e744577-cf1c-4876-a122-2d0e9c5e0f23"},"reasonCode":{"coding":[{"system":"https://icd.who.int/","code":"XM4YL8","display":"AstraZeneca"}],"text":"AstraZeneca"},"reasonReference":{"reference":"Questionnaire/e8572c86-065d-11ee-be56-0242ac120002"},"input":[{"valueString":"AstraZeneca 2"}]},{"resourceType":"Task","id":"3db08dd4-1af2-4b99-9ebd-b4ca89a5ae69","identifier":[{"use":"official","value":"13116108-ee9a-4fa2-85ab-24494ee2154e"}],"basedOn":[{"reference":"CarePlan/341ea420-a1d0-4c32-b169-49e5ce5e1ad3"}],"status":"requested","intent":"plan","priority":"routine","code":{"coding":[{"system":"http://snomed.info/sct","code":"840534001","display":"SARS-CoV-2 vaccination"}]},"description":"AstraZeneca Booster at 180 d","for":{"reference":"Patient/Patient/19f81214-8d70-4866-9e29-1eb29f262b79"},"executionPeriod":{"start":"2024-06-29T00:00:00+05:00"},"authoredOn":"2024-02-20T17:48:22+05:00","requester":{"reference":"Practitioner/6e744577-cf1c-4876-a122-2d0e9c5e0f23"},"owner":{"reference":"Practitioner/6e744577-cf1c-4876-a122-2d0e9c5e0f23"},"reasonCode":{"coding":[{"system":"https://icd.who.int/","code":"XM4YL8","display":"AstraZeneca"}],"text":"AstraZeneca"},"reasonReference":{"reference":"Questionnaire/e8572c86-065d-11ee-be56-0242ac120002"},"input":[{"valueString":"AstraZeneca 9999"}]}],

"instantiatesCanonical":["PlanDefinition/11533"],"status":"active","intent":"plan","title":"Immunization","description":"This scheduled will be used to track the Adult's Covid 19 immunization.","subject":{"reference":"Patient/Patient/19f81214-8d70-4866-9e29-1eb29f262b79"},"period":{"start":"2024-01-01"},"created":"2024-02-20T17:48:22+05:00","author":{"reference":"Practitioner/6e744577-cf1c-4876-a122-2d0e9c5e0f23"},"activity":[{"outcomeReference":[{"reference":"Task/6ecc513f-ff15-48e8-860b-e0a5fa967d43"},{"reference":"Task/3db08dd4-1af2-4b99-9ebd-b4ca89a5ae69"}],"detail":{"kind":"Task","status":"in-progress","performer":[{"reference":"Practitioner/6e744577-cf1c-4876-a122-2d0e9c5e0f23"}],"description":"This action will assess careplan on registration to init careplan"}}]}
maimoonak commented 5 months ago

So after debugging I was able to figure out a minor issue in date calculation for year and age. The .toString() was not used in cal-year and calc-age variable-expressions. The form although uses complex expressions which should be simplified and made readible like below

    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "calc-dob-year",
        "language": "text/fhirpath",
        "expression": "%resource.descendants().where(linkId='aa1ddb98-87a4-48a6-9d8c-4c80de1ec277').answer.value.toString().substring(0, 4).toInteger()"
      }
    },
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "calc-dob-month",
        "language": "text/fhirpath",
        "expression": "%resource.descendants().where(linkId='aa1ddb98-87a4-48a6-9d8c-4c80de1ec277').answer.value.toString().substring(5, 2).toInteger()"
      }
    },
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "calc-curr-year",
        "language": "text/fhirpath",
        "expression": "today().toString().substring(0, 4).toInteger()"
      }
    },
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "calc-curr-month",
        "language": "text/fhirpath",
        "expression": "today().toString().substring(5, 2).toInteger()"
      }
    },
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "calc-month",
        "language": "text/fhirpath",
        "expression": "%calc-dob-month"
      }
    },
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "calc-year",
        "language": "text/fhirpath",
        "expression": "iif(%calc-dob-month > %calc-curr-month, (%calc-curr-year - 1) - %calc-dob-year, %calc-curr-year - %calc-dob-year)"
      }
    },
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "calc-age",
        "language": "text/fhirpath",
        "expression": "(((%calc-year * 365.25) + (%calc-month * 365.25 / 12)) / 365.25).toString().replaceMatches('[.]+[0-9]+', '').toInteger()"
      }
    }
f-odhiambo commented 5 months ago

@maimoonak I have tested the above solution and it works as expected , so one more issue to go

maimoonak commented 5 months ago

There are few issues and missing freatures in SDK which creates problem in building this form with best possible way . answerOptionToggle just works on form load and does not change the state for subsequent changes in form . named expression can not be used which can help preserve data throughout session and help in getting data of one expression in other items . variable expression can not use x-fhir-query . initial expression does not work with x-fhir-query

The form contains some improvements which is use of %questionnaire, %qItem which helps in removing repeated answerOption for vaccine The form needs to have acknowledgement of previous vaccine from healthworker to use the calculation properly We can add prepopulate to sort out this issue

{
  "resourceType": "Questionnaire",
  "id": "11532",
  "meta": {
    "versionId": "10",
    "lastUpdated": "2023-07-31T15:29:52.606+00:00",
    "source": "#df51ab7e1bbb835d",
    "security": [
      {
        "system": "urn:oid:2.16.578.1.12.4.1.1.7618",
        "code": "3",
        "display": "Helsehjelp"
      }
    ]
  },
  "extension": [
    {
      "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-targetStructureMap",
      "valueCanonical": "https://fhir.zeir.smartregister.org/fhir/StructureMap/8301"
    },
    {
      "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-launchContext",
      "extension": [
        {
          "url": "name",
          "valueCoding": {
            "system": "http://hl7.org/fhir/uv/sdc/CodeSystem/launchContext",
            "code": "patient",
            "display": "Patient"
          }
        },
        {
          "url": "type",
          "valueCode": "Patient"
        }
      ]
    },
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "prev-vaccine",
        "language": "text/fhirpath",
        "expression": "%resource.descendants().where(linkId='previous_vaccine').answer.first().value"
      }
    },
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "prev-vaccine-name",
        "language": "text/fhirpath",
        "expression": "%prev-vaccine.display.replaceMatches('\\\\d+$', '').trim()"
      }
    },
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "current-dose",
        "language": "text/fhirpath",
        "expression": "%resource.descendants().where(linkId='dose_number').answer.first().value.code"
      }
    }
  ],
  "status": "draft",
  "subjectType": [
    "Patient"
  ],
  "item": [
    {
      "extension": [
        {
          "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerExpression",
          "valueExpression": {
            "language": "application/x-fhir-query",
            "expression": "Immunization?patient=Patient/P1&reason-code=840534001&_sort=-date&_count=1"
          }
        },
        {
          "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-choiceColumn",
          "extension": [
            {
              "url": "path",
              "valueString": "vaccineCode.text"
            },
            {
              "url": "forDisplay",
              "valueBoolean": true
            }
          ]
        },
        {
          "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden",
          "valueBoolean": false
        }
      ],
      "linkId": "previous_vaccine",
      "text": "Previous vaccine",
      "type": "reference"
    },
    {
      "extension": [
        {
          "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden",
          "valueBoolean": false
        }
      ],
      "linkId": "vaccine_selector_list",
      "text": "Vaccine name list",
      "type": "choice",
      "required": true,
      "readOnly": true,
      "answerOption": [
        {
          "valueCoding": {
            "system": "https://icd.who.int/",
            "code": "XM4YL8",
            "display": "AstraZeneca"
          }
        },
        {
          "valueCoding": {
            "system": "https://icd.who.int/",
            "code": "XM6QV1",
            "display": "Johnson & Johnson"
          }
        },
        {
          "valueCoding": {
            "system": "https://icd.who.int/",
            "code": "XM1AU2",
            "display": "Sinopharm"
          }
        },
        {
          "valueCoding": {
            "system": "https://icd.who.int/",
            "code": "XM8NQ0",
            "display": "Pfizer"
          }
        },
        {
          "valueCoding": {
            "system": "https://icd.who.int/",
            "code": "XM3DT5",
            "display": "Moderna"
          }
        }
      ]
    },
    {
      "extension": [
        {
          "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden",
          "valueBoolean": false
        },
        {
          "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression",
          "valueExpression": {
            "language": "text/fhirpath",
            "expression": "Patient.birthDate"
          }
        }
      ],
      "linkId": "patient_birthdate",
      "text": "Birthdate",
      "type": "date",
      "readOnly": true
    },
    {
      "extension": [
        {
          "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden",
          "valueBoolean": true
        }
      ],
      "linkId": "task-name",
      "type": "string",
      "readOnly": true
    },
    {
      "extension": [
        {
          "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden",
          "valueBoolean": true
        }
      ],
      "linkId": "task-code",
      "text": "task-code",
      "type": "string"
    },
    {
      "extension": [
        {
          "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression",
          "valueExpression": {
            "language": "text/fhirpath",
            "expression": "%resource.descendants().where(linkId='dose_number').answer.value.code='1' and %resource.descendants().where(linkId='patient_birthdate').answer.value >= today()-17 'years'"
          }
        }
      ],
      "linkId": "parent_consent",
      "text": "Has the parent or caregiver consented to this patient receiving the COVID-19 vaccination?",
      "type": "boolean",
      "required": true
    },
    {
      "extension": [
        {
          "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression",
          "valueExpression": {
            "language": "text/fhirpath",
            "expression": "%qItem.answerOption.value.where( iif(%prev-vaccine.empty(), code='1', iif(%prev-vaccine-name.contains('Johnson & Johnson') or %prev-vaccine.display.endsWith('1').not(), code='9999', code='2' ) ))"
          }
        }
      ],
      "linkId": "dose_number",
      "text": "Dose Number",
      "type": "choice",
      "required": true,
      "readOnly": true,
      "answerOption": [
        {
          "valueCoding": {
            "system": "https://smartregister.org/immunization/covid-vaccine-doses",
            "code": "1",
            "display": "1"
          }
        },
        {
          "valueCoding": {
            "system": "https://smartregister.org/immunization/covid-vaccine-doses",
            "code": "2",
            "display": "2"
          }
        },
        {
          "valueCoding": {
            "system": "https://smartregister.org/immunization/covid-vaccine-doses",
            "code": "9999",
            "display": "Booster"
          }
        }
      ]
    },
    {
      "extension": [
        {
          "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerExpression",
          "valueExpression": {
            "language": "text/fhirpath",
            "expression": "%questionnaire.descendants().where(linkId='vaccine_selector_list').answerOption.value.where(iif(%current-dose!='2', true, display=%prev-vaccine-name ))"
          }
        }
      ],
      "linkId": "current_vaccine",
      "text": "Current Vaccine",
      "type": "choice",
      "required": true,
      "readOnly": false
    },
    {
      "linkId": "education_material_used",
      "text": "IEC materials were used for this patient",
      "type": "boolean",
      "required": true
    },
    {
      "extension": [
        {
          "url": "http://hl7.org/fhir/StructureDefinition/maxValue",
          "_valueDate": {
            "extension": [
              {
                "url": "http://hl7.org/fhir/StructureDefinition/cqf-calculatedValue",
                "valueExpression": {
                  "language": "text/fhirpath",
                  "expression": "today()"
                }
              }
            ]
          }
        }
      ],
      "linkId": "vaccine_date",
      "text": "Date Vaccine is Given",
      "type": "date",
      "required": true
    },
    {
      "linkId": "batch_number",
      "text": "Batch Number",
      "type": "string",
      "required": true
    },
    {
      "extension": [
        {
          "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl",
          "valueCodeableConcept": {
            "coding": [
              {
                "system": "http://hl7.org/fhir/questionnaire-item-control",
                "code": "drop-down",
                "display": "Drop down"
              }
            ],
            "text": "Drop down"
          }
        }
      ],
      "linkId": "place",
      "text": "Place of Vaccination",
      "type": "choice",
      "required": true,
      "answerOption": [
        {
          "valueCoding": {
            "code": "static",
            "display": "Static"
          }
        },
        {
          "valueCoding": {
            "code": "outreach",
            "display": "Outreach"
          }
        }
      ]
    }
  ]
}
pld commented 4 months ago

no code needed, closed and moved to advisory here