avniproject / apfodishanutrition

GNU Affero General Public License v3.0
0 stars 0 forks source link

Rewrite High risk rule #311

Open sachsk opened 1 week ago

sachsk commented 1 week ago

Do this first on the UAT In ANC form High risk calculation present in the decision and the visit schedule rule so we have to rewrite these rules as its non maintainable.

Notes:

adamsanadi6 commented 5 days ago

Decision Rule Backup Script:

"use strict";
({params, imports}) => {
    const programEncounter = params.entity;
    const decisions = params.decisions;
    const moment = imports.moment;
    const _ = imports.lodash;
    const complicationsBuilder = new imports.rulesConfig.complicationsBuilder({
        programEncounter: programEncounter, complicationsConcept: "High risk condition"
    });

    const allClinicalHighRiskValues = ["Severe anemia", "Moderate anemia", "Mild anemia", "Inadequate Weight Gain during Pregnancy",
        "Hypertension", "Diabetes/ Gestational Diabetes", "Tuberculosis", "Asthma", "Pre-eclampsia", "Sickle cell anemia", "Thalassemia",
        "Heart conditions", "Hypothyroidism", "Syphillis", "Other pre-morbidity conditions"];

    let clinicalHighRiskValues = [];

    const isSevereAnemia = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("68bc6e51-eb49-4816-b78b-2427bbab8d92").lessThan(7).matches();
    const isModerateAnemia = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("68bc6e51-eb49-4816-b78b-2427bbab8d92").greaterThanOrEqualTo(7).and.when.valueInEncounter("68bc6e51-eb49-4816-b78b-2427bbab8d92").lessThan(10).matches();
    const isMideAnemia = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("68bc6e51-eb49-4816-b78b-2427bbab8d92").greaterThanOrEqualTo(10).and.when.valueInEncounter("68bc6e51-eb49-4816-b78b-2427bbab8d92").lessThan(11).matches();

    const isHypertension = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("12d99265-c769-4236-aff5-fcba73976396").containsAnswerConceptName("621462ed-23da-4b73-b590-4af8ccf34b45").matches();

    const isDiabetes = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("12d99265-c769-4236-aff5-fcba73976396").containsAnswerConceptName("9f6c206e-f04a-4a2a-b3ae-78edbffb0f62").matches();
    const isTuberculosis = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("12d99265-c769-4236-aff5-fcba73976396").containsAnswerConceptName("34f5f1a8-8a03-47d0-a91b-2a0fe959fc10").matches();
    const isAsthma = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("12d99265-c769-4236-aff5-fcba73976396").containsAnswerConceptName("11228d39-49f1-4a44-9bbf-6c673c208326").matches();
    const isPreeclampsia = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("12d99265-c769-4236-aff5-fcba73976396").containsAnswerConceptName("b95305a1-1831-49b7-a5a6-b4cb458a5d6f").matches();
    const isSickleCellAnemia = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("12d99265-c769-4236-aff5-fcba73976396").containsAnswerConceptName("4b0c2486-20ac-458b-b89a-28603715aeb2").matches();
    const isThalassemia = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("12d99265-c769-4236-aff5-fcba73976396").containsAnswerConceptName("83168c77-2a4d-4650-9ead-5c42f1c7f0c4").matches();
    const isHeartConditions = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("12d99265-c769-4236-aff5-fcba73976396").containsAnswerConceptName("dea0c584-32a3-493a-be95-66588e01181a").matches();
    const isHypothyroidism = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("12d99265-c769-4236-aff5-fcba73976396").containsAnswerConceptName("1e527e8b-76ef-426d-aee7-a9002dc031d0").matches();
    const isSyphillis = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("12d99265-c769-4236-aff5-fcba73976396").containsAnswerConceptName("d9414d88-e0cf-4ffe-9cba-151d6879b773").matches();
    const isOtherPremorbidity = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("12d99265-c769-4236-aff5-fcba73976396").containsAnswerConceptName("9f771423-6205-42db-8428-293ac0ad9b13").matches();

    let isInadequareWeightGain = false;

    const earliestDate = moment(programEncounter.earliestVisitDateTime);
    const ancPreviousEncounters = programEncounter.programEnrolment.getEncounters(true).filter((enc) => enc.encounterType.name === 'ANC' && enc.encounterDateTime && earliestDate.isAfter(moment(enc.earliestVisitDateTime)));

    if (ancPreviousEncounters.length > 0) {
        ancPreviousEncounters.sort((a, b) => moment(b.earliestVisitDateTime).diff(moment(a.earliestVisitDateTime)));
        const lastANCEncounter = ancPreviousEncounters[0];

        const currentWeight = programEncounter.getObservationReadableValue("3981ddb0-30a3-43d2-9564-16ae9cc0e25e");
        const lastMonthWeight = lastANCEncounter.getObservationReadableValue("3981ddb0-30a3-43d2-9564-16ae9cc0e25e");

        if (lastMonthWeight + 2 > currentWeight) {
            isInadequareWeightGain = true;
        }
    }

    let isGeographicalHighRiskCondition = false;
    const locationProperties = programEncounter.programEnrolment.individual.lowestAddressLevel.locationProperties;
    if (locationProperties.length > 0) {
        const locationProperty = locationProperties.filter(prop => prop.concept.name == 'Geographically hard to reach village');
        if (locationProperty.length == 1) {
            const valueJSON = locationProperty[0].valueJSON;
            const answer = JSON.parse(valueJSON).answer;
            if (answer == "8ebbf088-f292-483e-9084-7de919ce67b7") {
                isGeographicalHighRiskCondition = true;
            }
        }
    }

    const highRiskConditions = [{isTrue: isSevereAnemia, value: "Severe anemia"},
        {isTrue: isModerateAnemia, value: "Moderate anemia"},
        {isTrue: isMideAnemia, value: "Mild anemia"},
        {isTrue: isInadequareWeightGain, value: "Inadequate Weight Gain during Pregnancy"},

        {isTrue: isHypertension, value: "Hypertension"},
        {isTrue: isDiabetes, value: "Diabetes/ Gestational Diabetes"},
        {isTrue: isTuberculosis, value: "Tuberculosis"},
        {isTrue: isAsthma, value: "Asthma"},
        {isTrue: isPreeclampsia, value: "Pre-eclampsia"},
        {isTrue: isSickleCellAnemia, value: "Sickle cell anemia"},
        {isTrue: isThalassemia, value: "Thalassemia"},
        {isTrue: isHeartConditions, value: "Heart conditions"},
        {isTrue: isHypothyroidism, value: "Hypothyroidism"},
        {isTrue: isSyphillis, value: "Syphillis"},
        {isTrue: isOtherPremorbidity, value: "Other pre-morbidity conditions"}
        //{isTrue: isGeographicalHighRiskCondition, value: "Geographically high risk"}

    ];

    highRiskConditions.forEach(condition => {
        if (condition.isTrue) {
            clinicalHighRiskValues.push(condition.value);
        }
    });

    let existingHighRiskValues = programEncounter.programEnrolment.getObservationReadableValue('9a7f284b-251d-459b-97d9-929ed280b3d3') || [];

    if (existingHighRiskValues) {
        existingHighRiskValues = existingHighRiskValues.filter(value => !allClinicalHighRiskValues.includes(value));
        clinicalHighRiskValues = clinicalHighRiskValues.concat(existingHighRiskValues);
    }

    decisions.enrolmentDecisions.push({name: "High risk condition", value: clinicalHighRiskValues});
    decisions.encounterDecisions.push({name: "High risk condition", value: clinicalHighRiskValues});

    const isGeographicalHighRisk = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("96b167e1-2d98-40b9-af04-8e4f64f9999a").containsAnswerConceptName("8ebbf088-f292-483e-9084-7de919ce67b7").matches();

    const qrtCondition1 = new imports.rulesConfig.RuleCondition({programEncounter}).when.latestValueInEntireEnrolment("35f880ca-60b5-4240-97e1-813c0a7a78c4").containsAnswerConceptName("8ebbf088-f292-483e-9084-7de919ce67b7").matches();

    //programEncounter.getObservationReadableValue("Is there a medical facillity intervention required for treatment?") == 'Yes';
    const qrtCondition2 = programEncounter.getObservationReadableValue("Did the ANM recommend for a medical facility intervention?") == 'Yes';
    const qrtCondition3 = programEncounter.getObservationReadableValue('High risk condition');
    const condition3 = qrtCondition1 || qrtCondition2;
    const condition2 = !programEncounter.programEnrolment.hasCompletedEncounterOfType('Delivery');
    const condition0 = !programEncounter.programEnrolment.programExitDateTime;

    // const hasClinicalConditions = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("f7cc4fd5-5c66-4695-b5e3-1d83c3621f5d").defined.matches();
    const isClinicalHighRisk = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("f7cc4fd5-5c66-4695-b5e3-1d83c3621f5d").containsAnswerConceptName("8ebbf088-f292-483e-9084-7de919ce67b7").matches();

    const isDeliveryEncounterCompleted = programEncounter.programEnrolment.hasCompletedEncounterOfType("Delivery");
    const latest = programEncounter.programEnrolment.lastFulfilledEncounter("ANC", "Delivery");
    const toBeMonitoredByQRT = (isGeographicalHighRisk || isClinicalHighRisk) && !isDeliveryEncounterCompleted;

    if (latest === undefined || programEncounter.uuid === latest.uuid || moment(programEncounter.encounterDateTime).isAfter(moment(latest.encounterDateTime))) {
        const value = toBeMonitoredByQRT ? "Yes" : "No";
        if(condition0 && condition3 && condition2) {
            decisions.registrationDecisions.push({name: "To be monitored by QRT", value});
            decisions.enrolmentDecisions.push({name: "To be monitored by QRT", value});
            decisions.encounterDecisions.push({name: "To be monitored by QRT", value});
        }
        if (isGeographicalHighRisk) {
            decisions.enrolmentDecisions.push({name: "Pregnancy geographically high risk", value: "Yes"});
        }
        if (clinicalHighRiskValues.length > 0) {
            decisions.enrolmentDecisions.push({name: "Clinically high risk", value: "Yes"});
        }

    } else {
        const value = "No";
        decisions.encounterDecisions.push({name: "To be monitored by QRT", value});
    }

    return decisions;
};
adamsanadi6 commented 5 days ago

Visit Schedule Rule Backup Script:

//SAMPLE RULE EXAMPLE
"use strict";
({params, imports}) => {
    const programEncounter = params.entity;
    const scheduleBuilder = new imports.rulesConfig.VisitScheduleBuilder({
        programEncounter
    });
    const moment = imports.moment;
    const _ = imports.lodash;

  const condition0 = ! programEncounter.programEnrolment.programExitDateTime;

  const scheduledOrCompletedEncountersOfType = (type,nextVisitDate) => {
      const nextDateMonth = moment(nextVisitDate).month();
      const nextDateYear = moment(nextVisitDate).year();          
      const data = programEncounter.programEnrolment.encounters.filter((enc)=> enc.encounterType.name === type && enc.voided == false && enc.cancelDateTime == null && moment(enc.earliestVisitDateTime).year()==nextDateYear  && moment(enc.earliestVisitDateTime).month()==nextDateMonth )
      return data;
  }

  function lastfilledEncounter(encounterType) {
        const lastVisitEncounters = programEncounter.programEnrolment.getEncountersOfType(encounterType, false);
        const latestEncounter = _.chain(lastVisitEncounters)
            .filter((encounter) => encounter.encounterDateTime && encounter.voided == false)
            .maxBy((encounter) => encounter.encounterDateTime)
            .value();
        return latestEncounter;
    }

  let nextDate = moment(programEncounter.earliestVisitDateTime).add(1,'M').startOf('month').toDate();

  const condition1 = scheduledOrCompletedEncountersOfType("ANC",nextDate).length == 0;
  const condition2 = ! programEncounter.programEnrolment.hasCompletedEncounterOfType('Delivery');

  const qrtCondition1 = new imports.rulesConfig.RuleCondition({programEncounter}).when.latestValueInEntireEnrolment("35f880ca-60b5-4240-97e1-813c0a7a78c4").containsAnswerConceptName("8ebbf088-f292-483e-9084-7de919ce67b7").matches();

  //programEncounter.getObservationReadableValue("Is there a medical facillity intervention required for treatment?") == 'Yes';
  const qrtCondition2 = programEncounter.getObservationReadableValue("Did the ANM recommend for a medical facility intervention?") == 'Yes';
  const qrtCondition3 = programEncounter.getObservationReadableValue('High risk condition');    

  if(condition0 && condition1 && condition2){
      scheduleBuilder.add({
            name: 'ANC',
            encounterType: 'ANC',
            earliestDate: nextDate,
            maxDate: moment(nextDate).add(7, 'days').toDate()
        });
  }

  const qrtDate = moment(programEncounter.encounterDateTime).toDate();
  const qrtCondition = scheduledOrCompletedEncountersOfType("QRT PW", qrtDate).length == 0;

  const isSevereAnemic = new imports.rulesConfig.RuleCondition({programEncounter}).when.valueInEncounter("68bc6e51-eb49-4816-b78b-2427bbab8d92").lessThan(7).matches();

  const condition3 = isSevereAnemic || qrtCondition1 || qrtCondition2 ;

  const ancEncounter = lastfilledEncounter('ANC');
  const isEditScenario = ancEncounter ? ancEncounter.uuid === programEncounter.uuid : false;

  if(condition0 && qrtCondition && condition3 && condition2){
    scheduleBuilder.add({
            name: 'QRT PW',
            encounterType: 'QRT PW',
            earliestDate:qrtDate,
            maxDate: moment(qrtDate).add(30, 'days').toDate()
      });
  }else if (!isEditScenario && qrtCondition3 && !qrtCondition1 && !qrtCondition2 && condition2){
  nextDate = moment(programEncounter.earliestVisitDateTime).add(1,'M').startOf('month').toDate();
  scheduleBuilder
            .add({
                name: "PW Home Visit",
                encounterType: "PW Home Visit",
                earliestDate: nextDate,
                maxDate: moment(nextDate).add(7, 'days').toDate()
            });
  }

    return scheduleBuilder.getAll();
};