From eb49d9379332fe775f7a9efa84b3cca0d3b959f1 Mon Sep 17 00:00:00 2001 From: himeshr Date: Wed, 22 Nov 2023 10:52:39 +0530 Subject: [PATCH] #1185 | WIP: allOverdueVisitsIn based on location filters --- .../ReportCardServiceIntegrationTest.js | 12 +- .../src/service/IndividualService.js | 108 ++++++++++-------- .../test/model/TestProgramFactory.js | 25 ++++ .../model/txn/TestProgramEncounterFactory.js | 34 ++++++ .../model/txn/TestProgramEnrolmentFactory.js | 35 ++++++ 5 files changed, 168 insertions(+), 46 deletions(-) create mode 100644 packages/openchs-android/test/model/TestProgramFactory.js create mode 100644 packages/openchs-android/test/model/txn/TestProgramEncounterFactory.js create mode 100644 packages/openchs-android/test/model/txn/TestProgramEnrolmentFactory.js diff --git a/packages/openchs-android/integrationTest/ReportCardServiceIntegrationTest.js b/packages/openchs-android/integrationTest/ReportCardServiceIntegrationTest.js index cd1985e8d..aed8b7468 100644 --- a/packages/openchs-android/integrationTest/ReportCardServiceIntegrationTest.js +++ b/packages/openchs-android/integrationTest/ReportCardServiceIntegrationTest.js @@ -17,7 +17,10 @@ import { Settings, SubjectType, CustomFilter, - ReportCard + ReportCard, + Program, + ProgramEnrolment, + ProgramEncounter } from "openchs-models"; import TestConceptFactory from "../test/model/TestConceptFactory"; import TestAddressLevelFactory from "../test/model/TestAddressLevelFactory"; @@ -43,6 +46,7 @@ import TestApprovalStatusFactory from "../test/model/approval/TestApprovalStatus import TestEncounterFactory from "../test/model/txn/TestEncounterFactory"; import TestEncounterTypeFactory from "../test/model/TestEncounterTypeFactory"; import moment from "moment"; +import TestProgramFactory from '../test/model/TestProgramFactory'; function getCount(test, card, reportFilters) { return test.reportCardService.getReportCardCount(card, reportFilters).primaryValue @@ -59,6 +63,8 @@ class ReportCardServiceIntegrationTest extends BaseIntegrationTest { db.create(Settings, TestSettingsFactory.createWithDefaults({})); this.subjectType = db.create(SubjectType, TestSubjectTypeFactory.createWithDefaults({type: SubjectType.types.Person, name: 'Beneficiary'})); + const program = db.create(Program, TestProgramFactory.create({name: 'Mother'})); + const programEncounterType = db.create(EncounterType, TestEncounterTypeFactory.create({name: "Delivery"})); const encounterType = db.create(EncounterType, TestEncounterTypeFactory.create({name: "Bar"})); const form = db.create(Form, TestFormFactory.createWithDefaults({formType: Form.formTypes.IndividualProfile})); const formElementGroup = db.create(FormElementGroup, TestFormElementGroupFactory.create({form: form})); @@ -78,6 +84,10 @@ class ReportCardServiceIntegrationTest extends BaseIntegrationTest { const encounterId1 = General.randomUUID(); const encounterId2 = General.randomUUID(); + //TODO add programEnrolment and programEncounters + // const programEncounterId1 = General.randomUUID(); + // const programEncounterId2 = General.randomUUID(); + const subjectEAS = db.create(EntityApprovalStatus, TestEntityApprovalStatusFactory.create({ entityType: EntityApprovalStatus.entityType.Subject, entityUUID: subjectId, diff --git a/packages/openchs-android/src/service/IndividualService.js b/packages/openchs-android/src/service/IndividualService.js index 1cd794df6..791fc810e 100644 --- a/packages/openchs-android/src/service/IndividualService.js +++ b/packages/openchs-android/src/service/IndividualService.js @@ -183,20 +183,20 @@ class IndividualService extends BaseService { let programEncounters = []; if (queryProgramEncounter) { programEncounters = this.db.objects(ProgramEncounter.schema.name) - .filtered('earliestVisitDateTime <= $0 ' + - 'AND maxVisitDateTime >= $1 ' + - 'AND encounterDateTime = null ' + - 'AND cancelDateTime = null ' + - 'AND programEnrolment.programExitDateTime = null ' + - 'AND programEnrolment.voided = false ' + - 'AND programEnrolment.individual.voided = false ' + - 'AND voided = false ', - dateMidnight, - dateMorning); - if (!_.isEmpty(programEncounterCriteria)) + .filtered('earliestVisitDateTime <= $0 ' + + 'AND maxVisitDateTime >= $1 ' + + 'AND encounterDateTime = null ' + + 'AND cancelDateTime = null ' + + 'AND programEnrolment.programExitDateTime = null ' + + 'AND programEnrolment.voided = false ' + + 'AND programEnrolment.individual.voided = false ' + + 'AND voided = false ', + dateMidnight, + dateMorning); + if (!_.isEmpty(programEncounterCriteria)) { programEncounters = programEncounters.filtered(`${programEncounterCriteria}`); - if (!_.isNil(addressFilter)) - programEncounters = RealmQueryService.filterBasedOnAddress(ProgramEncounter.schema.name, programEncounters, addressFilter); + } + programEncounters = RealmQueryService.filterBasedOnAddress(ProgramEncounter.schema.name, programEncounters, addressFilter); programEncounters = programEncounters.map((enc) => { const individual = enc.programEnrolment.individual; @@ -232,10 +232,10 @@ class IndividualService extends BaseService { 'AND voided = false ', dateMidnight, dateMorning); - if (!_.isEmpty(encounterCriteria)) + if (!_.isEmpty(encounterCriteria)) { encounters = encounters.filtered(`${encounterCriteria}`); - if (!_.isNil(addressFilter)) - encounters = RealmQueryService.filterBasedOnAddress(Encounter.schema.name, encounters, addressFilter); + } + encounters = RealmQueryService.filterBasedOnAddress(Encounter.schema.name, encounters, addressFilter); encounters = encounters.map((enc) => { const individual = enc.individual; @@ -294,17 +294,26 @@ class IndividualService extends BaseService { const performProgramVisitCriteria = `privilege.name = '${Privilege.privilegeName.performVisit}' AND privilege.entityType = '${Privilege.privilegeEntityType.encounter}'`; const allowedProgramEncounterTypeUuidsForPerformVisit = privilegeService.allowedEntityTypeUUIDListForCriteria(performProgramVisitCriteria, 'programEncounterTypeUuid'); const dateMorning = moment(date).startOf('day').toDate(); - const programEncounters = queryProgramEncounter ? this.db.objects(ProgramEncounter.schema.name) - .filtered('maxVisitDateTime < $0 ' + + const addressFilter = DashboardReportFilter.getAddressFilter(reportFilters); + + let programEncounters = []; + if (queryProgramEncounter) { + programEncounters = this.db.objects(ProgramEncounter.schema.name) + .filtered('maxVisitDateTime < $0 ' + 'AND cancelDateTime = null ' + 'AND encounterDateTime = null ' + 'AND programEnrolment.programExitDateTime = null ' + 'AND programEnrolment.voided = false ' + 'AND programEnrolment.individual.voided = false ' + 'AND voided = false ', - dateMorning) - .filtered((_.isEmpty(programEncounterCriteria) ? 'uuid != null' : `${programEncounterCriteria}`)) - .map((enc) => { + dateMorning); + + if (!_.isEmpty(programEncounterCriteria)) { + programEncounters = programEncounters.filtered(`${programEncounterCriteria}`); + } + programEncounters = RealmQueryService.filterBasedOnAddress(ProgramEncounter.schema.name, programEncounters, addressFilter); + + programEncounters = programEncounters.map((enc) => { const individual = enc.programEnrolment.individual; const visitName = enc.name || enc.encounterType.operationalEncounterTypeName; const programName = enc.programEnrolment.program.operationalProgramName || enc.programEnrolment.program.name; @@ -323,36 +332,45 @@ class IndividualService extends BaseService { allow: !privilegeService.hasEverSyncedGroupPrivileges() || privilegeService.hasAllPrivileges() || _.includes(allowedProgramEncounterTypeUuidsForPerformVisit, enc.encounterType.uuid) } }; - }) : []; + }); + } const allowedGeneralEncounterTypeUuidsForPerformVisit = privilegeService.allowedEntityTypeUUIDListForCriteria(performProgramVisitCriteria, 'encounterTypeUuid'); - const encounters = queryGeneralEncounter ? this.db.objects(Encounter.schema.name) - .filtered('maxVisitDateTime < $0 ' + + let encounters = []; + if(queryGeneralEncounter) { + encounters = this.db.objects(Encounter.schema.name) + .filtered('maxVisitDateTime < $0 ' + 'AND cancelDateTime = null ' + 'AND encounterDateTime = null ' + 'AND individual.voided = false ' + 'AND voided = false ', - dateMorning) - .filtered((_.isEmpty(encounterCriteria) ? 'uuid != null' : `${encounterCriteria}`)) - .map((enc) => { - const individual = enc.individual; - const visitName = enc.name || enc.encounterType.operationalEncounterTypeName; - const maxVisitDateTime = enc.maxVisitDateTime; - return { - individual, - visitInfo: { - uuid: individual.uuid, - visitName: [{ - visit: [visitName, General.formatDate(maxVisitDateTime)], - encounter: enc, - color: '#d0011b', - }], - groupingBy: General.formatDate(maxVisitDateTime), - sortingBy: maxVisitDateTime, - allow: !privilegeService.hasEverSyncedGroupPrivileges() || privilegeService.hasAllPrivileges() || _.includes(allowedGeneralEncounterTypeUuidsForPerformVisit, enc.encounterType.uuid) - } - }; - }) : []; + dateMorning); + + if(!_.isEmpty(encounterCriteria)) { + encounters = encounters.filtered(`${encounterCriteria}`); + } + encounters = RealmQueryService.filterBasedOnAddress(Encounter.schema.name, encounters, addressFilter); + + encounters = encounters.map((enc) => { + const individual = enc.individual; + const visitName = enc.name || enc.encounterType.operationalEncounterTypeName; + const maxVisitDateTime = enc.maxVisitDateTime; + return { + individual, + visitInfo: { + uuid: individual.uuid, + visitName: [{ + visit: [visitName, General.formatDate(maxVisitDateTime)], + encounter: enc, + color: '#d0011b', + }], + groupingBy: General.formatDate(maxVisitDateTime), + sortingBy: maxVisitDateTime, + allow: !privilegeService.hasEverSyncedGroupPrivileges() || privilegeService.hasAllPrivileges() || _.includes(allowedGeneralEncounterTypeUuidsForPerformVisit, enc.encounterType.uuid) + } + }; + }) + }; const allEncounters = [... [...programEncounters, ...encounters] .reduce(this._uniqIndividualWithVisitName, new Map()) diff --git a/packages/openchs-android/test/model/TestProgramFactory.js b/packages/openchs-android/test/model/TestProgramFactory.js new file mode 100644 index 000000000..d740b0657 --- /dev/null +++ b/packages/openchs-android/test/model/TestProgramFactory.js @@ -0,0 +1,25 @@ +import {Program} from "openchs-models"; +import General from "../../src/utility/General"; + +class TestProgramFactory { + static create({ + uuid = General.randomUUID(), + name, + colour = '#012345', + allowMultipleEnrolments = false, + manualEligibilityCheckRequired = false + }) { + const program = new Program(); + program.uuid = uuid; + program.name = name; + program.displayName = name; + program.programSubjectLabel = name; + program.operationalProgramName = name; + program.colour = colour; + program.allowMultipleEnrolments = allowMultipleEnrolments; + program.manualEligibilityCheckRequired = manualEligibilityCheckRequired; + return program; + } +} + +export default TestProgramFactory; diff --git a/packages/openchs-android/test/model/txn/TestProgramEncounterFactory.js b/packages/openchs-android/test/model/txn/TestProgramEncounterFactory.js new file mode 100644 index 000000000..87ea7fbe9 --- /dev/null +++ b/packages/openchs-android/test/model/txn/TestProgramEncounterFactory.js @@ -0,0 +1,34 @@ +import General from "../../src/utility/General"; +import {ProgramEncounter} from 'openchs-models'; + +class TestProgramEncounterFactory { + static create({ + uuid = General.randomUUID(), + name, + encounterType, + programEnrolment, + encounterDateTime, + earliestVisitDateTime, + maxVisitDateTime, + subject: subject, + observations = [], + approvalStatuses = [] + }) { + const programEncounter = new ProgramEncounter(); + programEncounter.uuid = uuid; + programEncounter.name = name; + programEncounter.displayName = name; + programEncounter.encounterType = encounterType; + programEncounter.programEnrolment = programEnrolment; + programEncounter.encounterDateTime = encounterDateTime; + programEncounter.individual = subject; + programEncounter.observations = observations; + programEncounter.approvalStatuses = approvalStatuses; + programEncounter.earliestVisitDateTime = earliestVisitDateTime; + programEncounter.maxVisitDateTime = maxVisitDateTime; + programEncounter.setLatestEntityApprovalStatus(programEncounter.latestEntityApprovalStatus); + return programEncounter; + } +} + +export default TestProgramEncounterFactory; diff --git a/packages/openchs-android/test/model/txn/TestProgramEnrolmentFactory.js b/packages/openchs-android/test/model/txn/TestProgramEnrolmentFactory.js new file mode 100644 index 000000000..cc378cd20 --- /dev/null +++ b/packages/openchs-android/test/model/txn/TestProgramEnrolmentFactory.js @@ -0,0 +1,35 @@ +import General from "../../src/utility/General"; +import {ProgramEnrolment} from 'openchs-models'; + +class TestProgramEnrolmentFactory { + static create({ + uuid = General.randomUUID(), + name, + program, + subject, + enrolmentDateTime, + encounters = [], + checklists = [], + observations = [], + approvalStatuses = [], + latestEntityApprovalStatus + }) { + const programEnrolment = new ProgramEnrolment(); + programEnrolment.uuid = uuid; + programEnrolment.name = name; + programEnrolment.program = program; + programEnrolment.individual = subject; + programEnrolment.displayName = name; + programEnrolment.operationalProgramName = name; + programEnrolment.encounters = encounters; + programEnrolment.checklists = checklists; + programEnrolment.observations = observations; + programEnrolment.enrolmentDateTime = enrolmentDateTime; + programEnrolment.approvalStatuses = approvalStatuses; + programEnrolment.setLatestEntityApprovalStatus(programEnrolment.latestEntityApprovalStatus); + + return programEnrolment; + } +} + +export default TestProgramEnrolmentFactory;