Skip to content

Commit

Permalink
#1448 - total standard report card type support.
Browse files Browse the repository at this point in the history
  • Loading branch information
petmongrels committed Jul 5, 2024
1 parent 35a752d commit f57ce97
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 115 deletions.
2 changes: 1 addition & 1 deletion packages/openchs-android/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"lodash": "4.17.21",
"moment": "2.29.4",
"native-base": "3.4.9",
"openchs-models": "1.31.92",
"openchs-models": "1.31.93",
"jshashes": "1.0.8",
"prop-types": "15.8.1",
"react": "18.2.0",
Expand Down
132 changes: 72 additions & 60 deletions packages/openchs-android/src/service/IndividualService.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,65 @@ import {getUnderlyingRealmCollection, KeyValue} from "openchs-models";
import RealmQueryService from "./query/RealmQueryService";
import {DashboardReportFilter} from "../model/DashboardReportFilter";
import CustomFilterService from "./CustomFilterService";
import {JSONStringify} from "../utility/JsonStringify";

function uniqSubjectWithVisitName(individualsWithVisits, individualWithVisit) {
const permissionAllowed = individualWithVisit.visitInfo.allow;
if (individualsWithVisits.has(individualWithVisit.individual.uuid)) {
const prevDate = individualsWithVisits.get(individualWithVisit.individual.uuid).visitInfo.sortingBy;
const smallerDate = moment(prevDate).isBefore(individualWithVisit.visitInfo.sortingBy) ? prevDate : individualWithVisit.visitInfo.sortingBy;
const presentEntry = individualWithVisit.visitInfo.visitName;
const previousEntries = individualsWithVisits.get(individualWithVisit.individual.uuid).visitInfo.visitName;
individualsWithVisits.set(individualWithVisit.individual.uuid,
{
individual: individualWithVisit.individual,
visitInfo: {
uuid: individualWithVisit.individual.uuid,
visitName: permissionAllowed ? [...previousEntries, ...presentEntry] : previousEntries,
groupingBy: smallerDate && General.formatDate(smallerDate) || '',
sortingBy: smallerDate,
}
})
} else {
permissionAllowed && individualsWithVisits.set(individualWithVisit.individual.uuid, individualWithVisit);
}
return individualsWithVisits;
}

function filterSubjects(subjects, subjectCriteria, reportFilters, customFilterService) {
subjects = applyConfiguredFilters(subjects, subjectCriteria);
subjects = applyUserFilters(subjects, reportFilters, Individual.schema.name, customFilterService);

const returnSubjects = subjects.map((subject) => {
const registrationDate = subject.registrationDate;
return {
individual: subject,
visitInfo: {
uuid: subject.uuid,
visitName: [],
groupingBy: General.formatDate(registrationDate),
sortingBy: registrationDate,
allow: true,
}
};
});
return [...returnSubjects
.reduce(uniqSubjectWithVisitName, new Map())
.values()]
.map(_.identity);
}

function getDateRange(date, duration) {
const fromDate = moment(date).subtract(duration.durationValue, duration.durationUnit).startOf('day').toDate();
const tillDate = moment(date).endOf('day').toDate();
return {fromDate, tillDate};
}

function get24HoursDateRange(date) {
const dateMidnight = moment(date).endOf('day').toDate();
const dateMorning = moment(date).startOf('day').toDate();
return {dateMidnight, dateMorning};
}

function getSubjectUUIDsForCustomFilters(customFilterService, reportFilters) {
let uniqueSubjects = [];
let filterApplied = false;
Expand Down Expand Up @@ -217,29 +268,6 @@ class IndividualService extends BaseService {
return individuals;
}

_uniqIndividualWithVisitName(individualsWithVisits, individualWithVisit) {
const permissionAllowed = individualWithVisit.visitInfo.allow;
if (individualsWithVisits.has(individualWithVisit.individual.uuid)) {
const prevDate = individualsWithVisits.get(individualWithVisit.individual.uuid).visitInfo.sortingBy;
const smallerDate = moment(prevDate).isBefore(individualWithVisit.visitInfo.sortingBy) ? prevDate : individualWithVisit.visitInfo.sortingBy;
const presentEntry = individualWithVisit.visitInfo.visitName;
const previousEntries = individualsWithVisits.get(individualWithVisit.individual.uuid).visitInfo.visitName;
individualsWithVisits.set(individualWithVisit.individual.uuid,
{
individual: individualWithVisit.individual,
visitInfo: {
uuid: individualWithVisit.individual.uuid,
visitName: permissionAllowed ? [...previousEntries, ...presentEntry] : previousEntries,
groupingBy: smallerDate && General.formatDate(smallerDate) || '',
sortingBy: smallerDate,
}
})
} else {
permissionAllowed && individualsWithVisits.set(individualWithVisit.individual.uuid, individualWithVisit);
}
return individualsWithVisits;
}

allInWithFilters(ignored, reportFilters, queryAdditions, programs = [], encounterTypes = []) {
if (!this.hideTotalForProgram() || (_.isEmpty(programs) && _.isEmpty(encounterTypes))) {
return this.allIn(ignored, reportFilters, queryAdditions);
Expand All @@ -261,8 +289,7 @@ class IndividualService extends BaseService {
const performProgramVisitCriteria = `privilege.name = '${Privilege.privilegeName.performVisit}' AND privilege.entityType = '${Privilege.privilegeEntityType.encounter}'`;
const privilegeService = this.getService(PrivilegeService);
const allowedProgramEncounterTypeUuidsForPerformVisit = privilegeService.allowedEntityTypeUUIDListForCriteria(performProgramVisitCriteria, 'programEncounterTypeUuid');
const dateMidnight = moment(date).endOf('day').toDate();
const dateMorning = moment(date).startOf('day').toDate();
const {dateMidnight, dateMorning} = get24HoursDateRange(date);

let programEncounters = [];
if (queryProgramEncounter) {
Expand Down Expand Up @@ -341,7 +368,7 @@ class IndividualService extends BaseService {
}
const allEncounters = [...
[...programEncounters, ...encounters]
.reduce(this._uniqIndividualWithVisitName, new Map())
.reduce(uniqSubjectWithVisitName, new Map())
.values()
];
return allEncounters;
Expand Down Expand Up @@ -426,20 +453,19 @@ class IndividualService extends BaseService {
}
const allEncounters = [...
[...programEncounters, ...encounters]
.reduce(this._uniqIndividualWithVisitName, new Map())
.reduce(uniqSubjectWithVisitName, new Map())
.values()
];
return allEncounters;
}

allCompletedVisitsIn(date, queryAdditions) {
let fromDate = moment(date).startOf('day').toDate();
let tillDate = moment(date).endOf('day').toDate();
const {dateMidnight, dateMorning} = get24HoursDateRange(date);
return [...this.db.objects(ProgramEncounter.schema.name)
.filtered('encounterDateTime <= $0 ' +
'AND encounterDateTime >= $1 ',
tillDate,
fromDate)
dateMidnight,
dateMorning)
.filtered((_.isEmpty(queryAdditions) ? 'uuid != null' : `${queryAdditions}`))
.map((enc) => {
return enc.programEnrolment.individual;
Expand Down Expand Up @@ -510,14 +536,13 @@ class IndividualService extends BaseService {
})
}
return [...[...programEncounters, ...encounters]
.reduce(this._uniqIndividualWithVisitName, new Map())
.reduce(uniqSubjectWithVisitName, new Map())
.values()]
.map(_.identity);
}

recentlyRegistered(date, reportFilters, addressQuery, programs = [], encounterTypes = []) {
let fromDate = moment(date).subtract(1, 'day').startOf('day').toDate();
let tillDate = moment(date).endOf('day').toDate();
const {fromDate, tillDate} = getDateRange(date, new Duration(1, Duration.Day));
const addressFilter = DashboardReportFilter.getAddressFilter(reportFilters);

let individuals = this.db.objects(Individual.schema.name)
Expand Down Expand Up @@ -551,43 +576,30 @@ class IndividualService extends BaseService {
};
});
return [...individuals
.reduce(this._uniqIndividualWithVisitName, new Map())
.reduce(uniqSubjectWithVisitName, new Map())
.values()]
.map(_.identity);
}

allInV2(date, reportFilters, subjectCriteria) {
let {dateMidnight} = get24HoursDateRange(date);
let subjects = this.db.objects(Individual.schema.name)
.filtered('voided = false AND registrationDate <= $0', dateMidnight);

return filterSubjects(subjects, subjectCriteria, reportFilters, this.getService(CustomFilterService));
}

recentlyRegisteredV2(date, reportFilters, subjectCriteria, duration) {
const {tillDate, fromDate} = getDateRange(date, duration);

let individuals = this.db.objects(Individual.schema.name)
let subjects = this.db.objects(Individual.schema.name)
.filtered('voided = false ' +
'AND registrationDate <= $0 ' +
'AND registrationDate >= $1 ',
tillDate,
fromDate);

General.logDebug("IndividualService", JSONStringify(duration), "fromDate", fromDate, "tillDate", tillDate, subjectCriteria);

individuals = applyConfiguredFilters(individuals, subjectCriteria);
individuals = applyUserFilters(individuals, reportFilters, Individual.schema.name, this.getService(CustomFilterService));

individuals = individuals.map((individual) => {
const registrationDate = individual.registrationDate;
return {
individual,
visitInfo: {
uuid: individual.uuid,
visitName: [],
groupingBy: General.formatDate(registrationDate),
sortingBy: registrationDate,
allow: true,
}
};
});
return [...individuals
.reduce(this._uniqIndividualWithVisitName, new Map())
.values()]
.map(_.identity);
return filterSubjects(subjects, subjectCriteria, reportFilters, this.getService(CustomFilterService));
}

recentlyEnrolled(date, reportFilters = [], programEnrolmentCriteria = "", duration = new Duration(1, Duration.Day)) {
Expand Down Expand Up @@ -621,7 +633,7 @@ class IndividualService extends BaseService {
};
});
return [...enrolments
.reduce(this._uniqIndividualWithVisitName, new Map())
.reduce(uniqSubjectWithVisitName, new Map())
.values()]
.map(_.identity);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import RealmQueryService from "../query/RealmQueryService";

class ReportCardQueryBuilder {
static getProgramEncounterCriteria(reportCard) {
const subjectTypeQuery = RealmQueryService.orKeyValueQuery("programEnrolment.individual.subjectType.uuid", reportCard.standardReportCardInputSubjectTypes.map((x) => x.uuid));
const programQuery = RealmQueryService.orKeyValueQuery("programEnrolment.program.uuid", reportCard.standardReportCardInputPrograms.map((x) => x.uuid));
const encounterTypeQuery = RealmQueryService.orKeyValueQuery("encounterType.uuid", reportCard.standardReportCardInputEncounterTypes.map((x) => x.uuid));
return RealmQueryService.andQuery([subjectTypeQuery, programQuery, encounterTypeQuery]);
}

static getGeneralEncounterCriteria(reportCard) {
const subjectTypeQuery = RealmQueryService.orKeyValueQuery("individual.subjectType.uuid", reportCard.standardReportCardInputSubjectTypes.map((x) => x.uuid));
const encounterTypeQuery = RealmQueryService.orKeyValueQuery("encounterType.uuid", reportCard.standardReportCardInputEncounterTypes.map((x) => x.uuid));
return RealmQueryService.andQuery([subjectTypeQuery, encounterTypeQuery]);
}

static getProgramEnrolmentCriteria(reportCard) {
const subjectTypeQuery = RealmQueryService.orKeyValueQuery("individual.subjectType.uuid", reportCard.standardReportCardInputSubjectTypes.map((x) => x.uuid));
const programQuery = RealmQueryService.orKeyValueQuery("program.uuid", reportCard.standardReportCardInputPrograms.map((x) => x.uuid));
return RealmQueryService.andQuery([subjectTypeQuery, programQuery]);
}

static getSubjectCriteria(reportCard) {
const uptoProgramEncounterCriteria = [];
const uptoGeneralEncounterCriteria = [];

const subjectCriteria = RealmQueryService.orKeyValueQuery("subjectType.uuid", reportCard.standardReportCardInputSubjectTypes.map((x) => x.uuid));
if (reportCard.hasInputForSubject() > 0) uptoProgramEncounterCriteria.push(subjectCriteria);

const programMatch = RealmQueryService.orKeyValueQuery("$enrolment.program.uuid", reportCard.standardReportCardInputPrograms.map((x) => x.uuid));
const encounterTypeMatch = RealmQueryService.orKeyValueQuery("$encounter.encounterType.uuid", reportCard.standardReportCardInputEncounterTypes.map((x) => x.uuid));

const programEnrolmentWithEncounterTypeCriteria = `subquery(enrolments, $enrolment, $enrolment.voided = false and (${programMatch}) and (subquery($enrolment.encounters, $encounter, $encounter.voided = false and (${encounterTypeMatch})).@count > 0)).@count > 0`;
const programEnrolmentWithoutEncounterTypeCriteria = `subquery(enrolments, $enrolment, $enrolment.voided = false and (${programMatch})).@count > 0`;
if (reportCard.hasInputForProgramEncounter())
uptoProgramEncounterCriteria.push(programEnrolmentWithEncounterTypeCriteria);
else if (reportCard.hasInputForEnrolment())
uptoProgramEncounterCriteria.push(programEnrolmentWithoutEncounterTypeCriteria);

if (reportCard.hasInputForGeneralEncounter()) {
uptoGeneralEncounterCriteria.push(subjectCriteria);
uptoGeneralEncounterCriteria.push(`subquery(encounters, $encounter, $encounter.voided = false and (${encounterTypeMatch})).@count > 0`);
}

return RealmQueryService.orQuery([RealmQueryService.andQuery(uptoProgramEncounterCriteria), RealmQueryService.andQuery(uptoGeneralEncounterCriteria)]);
}
}

export default ReportCardQueryBuilder;
Loading

0 comments on commit f57ce97

Please sign in to comment.