Skip to content

Commit 73fd0fe

Browse files
C2C-434: Show list of patients in MSPP Family planning report (#80)
1 parent b0e6997 commit 73fd0fe

File tree

6 files changed

+239
-206
lines changed

6 files changed

+239
-206
lines changed

api/src/main/java/org/openmrs/module/commonreports/CommonReportsConstants.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ public class CommonReportsConstants {
3636
public static final String COMPONENT_REPORTMANAGER_LAB = MODULE_ARTIFACT_ID + ".lab";
3737

3838
public static final String COMPONENT_REPORTMANAGER_VACCINATION = MODULE_ARTIFACT_ID + ".vaccination";
39-
39+
40+
public static final String COMPONENT_REPORTMANAGER_FAMILY_PLANNING = MODULE_ARTIFACT_ID + ".familyPlanning";
41+
4042
/*
4143
* URIs URLs
4244
*/
Lines changed: 176 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
package org.openmrs.module.commonreports.reports;
22

3-
import static org.openmrs.module.commonreports.common.Helper.getStringFromResource;
4-
5-
import java.io.InputStream;
63
import java.util.ArrayList;
74
import java.util.Arrays;
85
import java.util.Date;
96
import java.util.HashMap;
107
import java.util.List;
118
import java.util.Map;
12-
import java.util.Properties;
13-
import org.apache.commons.io.IOUtils;
9+
1410
import org.openmrs.module.commonreports.ActivatedReportManager;
11+
import org.openmrs.module.commonreports.CommonReportsConstants;
1512
import org.openmrs.module.initializer.api.InitializerService;
1613
import org.openmrs.module.reporting.common.MessageUtil;
17-
import org.openmrs.module.reporting.dataset.definition.SqlDataSetDefinition;
14+
import org.openmrs.module.reporting.cohort.definition.CompositionCohortDefinition;
15+
import org.openmrs.module.reporting.cohort.definition.GenderCohortDefinition;
16+
import org.openmrs.module.reporting.cohort.definition.SqlCohortDefinition;
17+
import org.openmrs.module.reporting.dataset.definition.CohortCrossTabDataSetDefinition;
18+
import org.openmrs.module.reporting.evaluation.parameter.Mapped;
1819
import org.openmrs.module.reporting.evaluation.parameter.Parameter;
1920
import org.openmrs.module.reporting.report.ReportDesign;
2021
import org.openmrs.module.reporting.report.definition.ReportDefinition;
2122
import org.openmrs.module.reporting.report.manager.ReportManagerUtil;
22-
import org.openmrs.util.OpenmrsClassLoader;
2323
import org.springframework.beans.factory.annotation.Autowired;
2424
import org.springframework.stereotype.Component;
2525

26-
@Component
26+
@Component(CommonReportsConstants.COMPONENT_REPORTMANAGER_FAMILY_PLANNING)
2727
public class MSPPFamilyPlanningReportManager extends ActivatedReportManager {
2828

2929
@Autowired
@@ -74,95 +74,188 @@ public List<Parameter> getParameters() {
7474
public ReportDefinition constructReportDefinition() {
7575

7676
ReportDefinition rd = new ReportDefinition();
77-
77+
rd.setUuid(getUuid());
7878
rd.setName(getName());
7979
rd.setDescription(getDescription());
8080
rd.setParameters(getParameters());
81-
rd.setUuid(getUuid());
8281

83-
SqlDataSetDefinition sqlDsd = new SqlDataSetDefinition();
84-
sqlDsd.setName(MessageUtil.translate("commonreports.report.MSPP.familyPlanning.datasetName"));
85-
sqlDsd.setDescription(MessageUtil.translate("commonreports.report.MSPP.familyPlanning.datasetDescription"));
82+
CohortCrossTabDataSetDefinition familyPlanning = new CohortCrossTabDataSetDefinition();
83+
familyPlanning.addParameters(getParameters());
84+
rd.addDataSetDefinition(getName(), Mapped.mapStraightThrough(familyPlanning));
85+
86+
Map<String, Object> parameterMappings = new HashMap<String, Object>();
87+
parameterMappings.put("onOrAfter", "${startDate}");
88+
parameterMappings.put("onOrBefore", "${endDate}");
8689

87-
String rawSql = getStringFromResource("org/openmrs/module/commonreports/sql/MSPPfamilyPlanning.sql");
88-
String sql = applyMetadataReplacements(rawSql);
90+
int fpAdministredConceptId = inizService.getConceptFromKey("report.MSPP.familyPlanning.FPAdministred")
91+
.getConceptId();
92+
int familyPlanningConceptId = inizService.getConceptFromKey("report.MSPP.familyPlanning.familyPlanning")
93+
.getConceptId();
94+
int typeOfUserConceptId = inizService.getConceptFromKey("report.MSPP.familyPlanning.typeOfUser").getConceptId();
95+
int newConceptId = inizService.getConceptFromKey("report.MSPP.familyPlanning.new").getConceptId();
96+
int existentConceptId = inizService.getConceptFromKey("report.MSPP.familyPlanning.existent").getConceptId();
97+
int microgynonConceptId = inizService.getConceptFromKey("report.MSPP.familyPlanning.microgynon").getConceptId();
98+
int microlutConceptId = inizService.getConceptFromKey("report.MSPP.familyPlanning.microlut").getConceptId();
99+
int depoProveraInjectionConceptId = inizService.getConceptFromKey("report.MSPP.familyPlanning.depoProveraInjection")
100+
.getConceptId();
101+
int jadelConceptId = inizService.getConceptFromKey("report.MSPP.familyPlanning.jadel").getConceptId();
102+
int condomConceptId = inizService.getConceptFromKey("report.MSPP.familyPlanning.condom").getConceptId();
89103

90-
sqlDsd.setSqlQuery(sql);
91-
sqlDsd.addParameters(getParameters());
104+
// Add rows for each method and user type combination
105+
// Microgynon - New Users
106+
familyPlanning.addRow("newMycogynonFemaleLT25", createFamilyPlanningCohort(fpAdministredConceptId,
107+
microgynonConceptId, familyPlanningConceptId, typeOfUserConceptId, newConceptId, "F", 25, false, 1),
108+
parameterMappings);
109+
familyPlanning.addRow("newMycogynonFemaleGT25", createFamilyPlanningCohort(fpAdministredConceptId,
110+
microgynonConceptId, familyPlanningConceptId, typeOfUserConceptId, newConceptId, "F", 25, true, 1),
111+
parameterMappings);
112+
familyPlanning
113+
.addRow(
114+
"existentMycogynonFemaleLT25", createFamilyPlanningCohort(fpAdministredConceptId, microgynonConceptId,
115+
familyPlanningConceptId, typeOfUserConceptId, existentConceptId, "F", 25, false, 1),
116+
parameterMappings);
117+
familyPlanning
118+
.addRow(
119+
"existentMycogynonFemaleGT25", createFamilyPlanningCohort(fpAdministredConceptId, microgynonConceptId,
120+
familyPlanningConceptId, typeOfUserConceptId, existentConceptId, "F", 25, true, 1),
121+
parameterMappings);
92122

93-
Map<String, Object> parameterMappings = new HashMap<String, Object>();
94-
parameterMappings.put("startDate", "${startDate}");
95-
parameterMappings.put("endDate", "${endDate}");
123+
// Microlut - New Users
124+
familyPlanning.addRow("newMicrolutFemaleLT25", createFamilyPlanningCohort(fpAdministredConceptId, microlutConceptId,
125+
familyPlanningConceptId, typeOfUserConceptId, newConceptId, "F", 25, false, 1), parameterMappings);
126+
familyPlanning.addRow("newMicrolutFemaleGT25", createFamilyPlanningCohort(fpAdministredConceptId, microlutConceptId,
127+
familyPlanningConceptId, typeOfUserConceptId, newConceptId, "F", 25, true, 1), parameterMappings);
128+
familyPlanning
129+
.addRow(
130+
"existentMicrolutFemaleLT25", createFamilyPlanningCohort(fpAdministredConceptId, microlutConceptId,
131+
familyPlanningConceptId, typeOfUserConceptId, existentConceptId, "F", 25, false, 1),
132+
parameterMappings);
133+
familyPlanning
134+
.addRow(
135+
"existentMicrolutFemaleGT25", createFamilyPlanningCohort(fpAdministredConceptId, microlutConceptId,
136+
familyPlanningConceptId, typeOfUserConceptId, existentConceptId, "F", 25, true, 1),
137+
parameterMappings);
138+
139+
// Depo Provera - New Users (3 months interval)
140+
familyPlanning.addRow("newDepoFemaleLT25", createFamilyPlanningCohort(fpAdministredConceptId,
141+
depoProveraInjectionConceptId, familyPlanningConceptId, typeOfUserConceptId, newConceptId, "F", 25, false, 3),
142+
parameterMappings);
143+
familyPlanning.addRow("newDepoFemaleGT25", createFamilyPlanningCohort(fpAdministredConceptId,
144+
depoProveraInjectionConceptId, familyPlanningConceptId, typeOfUserConceptId, newConceptId, "F", 25, true, 3),
145+
parameterMappings);
146+
familyPlanning
147+
.addRow("existentDepoFemaleLT25",
148+
createFamilyPlanningCohort(fpAdministredConceptId, depoProveraInjectionConceptId,
149+
familyPlanningConceptId, typeOfUserConceptId, existentConceptId, "F", 25, false, 3),
150+
parameterMappings);
151+
familyPlanning
152+
.addRow("existentDepoFemaleGT25",
153+
createFamilyPlanningCohort(fpAdministredConceptId, depoProveraInjectionConceptId,
154+
familyPlanningConceptId, typeOfUserConceptId, existentConceptId, "F", 25, true, 3),
155+
parameterMappings);
156+
157+
// Jadel - New Users (5 years interval)
158+
familyPlanning.addRow("newJadelFemaleLT25", createFamilyPlanningCohort(fpAdministredConceptId, jadelConceptId,
159+
familyPlanningConceptId, typeOfUserConceptId, newConceptId, "F", 25, false, 60), parameterMappings);
160+
familyPlanning.addRow("newJadelFemaleGT25", createFamilyPlanningCohort(fpAdministredConceptId, jadelConceptId,
161+
familyPlanningConceptId, typeOfUserConceptId, newConceptId, "F", 25, true, 60), parameterMappings);
162+
familyPlanning.addRow("existentJadelFemaleLT25", createFamilyPlanningCohort(fpAdministredConceptId, jadelConceptId,
163+
familyPlanningConceptId, typeOfUserConceptId, existentConceptId, "F", 25, false, 60), parameterMappings);
164+
familyPlanning.addRow("existentJadelFemaleGT25", createFamilyPlanningCohort(fpAdministredConceptId, jadelConceptId,
165+
familyPlanningConceptId, typeOfUserConceptId, existentConceptId, "F", 25, true, 60), parameterMappings);
166+
167+
// Condom - New Users (no interval)
168+
familyPlanning.addRow("newCondomFemaleLT25", createFamilyPlanningCohort(fpAdministredConceptId, condomConceptId,
169+
familyPlanningConceptId, typeOfUserConceptId, newConceptId, "F", 25, false, 0), parameterMappings);
170+
familyPlanning.addRow("newCondomFemaleGT25", createFamilyPlanningCohort(fpAdministredConceptId, condomConceptId,
171+
familyPlanningConceptId, typeOfUserConceptId, newConceptId, "F", 25, true, 0), parameterMappings);
172+
familyPlanning.addRow("existentCondomFemaleLT25", createFamilyPlanningCohort(fpAdministredConceptId, condomConceptId,
173+
familyPlanningConceptId, typeOfUserConceptId, existentConceptId, "F", 25, false, 0), parameterMappings);
174+
familyPlanning.addRow("existentCondomFemaleGT25", createFamilyPlanningCohort(fpAdministredConceptId, condomConceptId,
175+
familyPlanningConceptId, typeOfUserConceptId, existentConceptId, "F", 25, true, 0), parameterMappings);
176+
177+
// Condom - Males
178+
familyPlanning.addRow("newCondomMaleLT25", createFamilyPlanningCohort(fpAdministredConceptId, condomConceptId,
179+
familyPlanningConceptId, typeOfUserConceptId, newConceptId, "M", 25, false, 0), parameterMappings);
180+
familyPlanning.addRow("newCondomMaleGT25", createFamilyPlanningCohort(fpAdministredConceptId, condomConceptId,
181+
familyPlanningConceptId, typeOfUserConceptId, newConceptId, "M", 25, true, 0), parameterMappings);
182+
familyPlanning.addRow("existentCondomMaleLT25", createFamilyPlanningCohort(fpAdministredConceptId, condomConceptId,
183+
familyPlanningConceptId, typeOfUserConceptId, existentConceptId, "M", 25, false, 0), parameterMappings);
184+
familyPlanning.addRow("existentCondomMaleGT25", createFamilyPlanningCohort(fpAdministredConceptId, condomConceptId,
185+
familyPlanningConceptId, typeOfUserConceptId, existentConceptId, "M", 25, true, 0), parameterMappings);
96186

97-
rd.addDataSetDefinition(getName(), sqlDsd, parameterMappings);
187+
// Add a single column for "Total" (all patients)
188+
GenderCohortDefinition allGender = new GenderCohortDefinition();
189+
allGender.setMaleIncluded(true);
190+
allGender.setFemaleIncluded(true);
191+
familyPlanning.addColumn("Total", createCohortComposition(allGender), null);
98192

99193
return rd;
100194
}
101195

102-
@Override
103-
public List<ReportDesign> constructReportDesigns(ReportDefinition reportDefinition) {
104-
ReportDesign reportDesign = ReportManagerUtil.createExcelTemplateDesign("c51fc24f-50ba-48f8-9678-90462f7cff80",
105-
reportDefinition, "org/openmrs/module/commonreports/reportTemplates/familyPlanningReportTemplate.xls");
106-
107-
Properties designProperties = new Properties();
108-
109-
designProperties.put("newUser.label",
110-
MessageUtil.translate("commonreports.report.MSPP.familyPlanning.newUser.label"));
111-
designProperties.put("existentUser.label",
112-
MessageUtil.translate("commonreports.report.MSPP.familyPlanning.existentUser.label"));
113-
designProperties.put("LT25years.label",
114-
MessageUtil.translate("commonreports.report.MSPP.familyPlanning.LT25years.label"));
115-
designProperties.put("GT25years.label",
116-
MessageUtil.translate("commonreports.report.MSPP.familyPlanning.GT25years.label"));
117-
designProperties.put("method.label", MessageUtil.translate("commonreports.report.MSPP.familyPlanning.method.label"));
118-
designProperties.put("females.label",
119-
MessageUtil.translate("commonreports.report.MSPP.familyPlanning.females.label"));
120-
designProperties.put("males.label", MessageUtil.translate("commonreports.report.MSPP.familyPlanning.males.label"));
121-
designProperties.put("PC.label", MessageUtil.translate("commonreports.report.MSPP.familyPlanning.PC.label"));
122-
designProperties.put("PP.label", MessageUtil.translate("commonreports.report.MSPP.familyPlanning.PP.label"));
123-
designProperties.put("depo.label", MessageUtil.translate("commonreports.report.MSPP.familyPlanning.depo.label"));
124-
designProperties.put("implant.label",
125-
MessageUtil.translate("commonreports.report.MSPP.familyPlanning.implant.label"));
126-
designProperties.put("condoms.label",
127-
MessageUtil.translate("commonreports.report.MSPP.familyPlanning.condoms.label"));
128-
designProperties.put("total.label", MessageUtil.translate("commonreports.report.MSPP.familyPlanning.total.label"));
129-
130-
reportDesign.setProperties(designProperties);
131-
return Arrays.asList(reportDesign);
196+
/**
197+
* Creates a SqlCohortDefinition for family planning based on the provided parameters
198+
*
199+
* @param fpAdministredConceptId The concept ID for FP Administered
200+
* @param methodConceptId The concept ID for the method (microgynon, microlut, etc.)
201+
* @param familyPlanningConceptId The concept ID for family planning
202+
* @param typeOfUserConceptId The concept ID for type of user
203+
* @param userTypeConceptId The concept ID for new or existent user
204+
* @param gender Gender filter: "F" for female, "M" for male
205+
* @param ageThreshold Age threshold (e.g., 25)
206+
* @param ageGreaterOrEqual true for >= ageThreshold, false for < ageThreshold
207+
* @param intervalMonths Number of months to subtract from startDate (0 for no interval, 1 for 1
208+
* month, 3 for 3 months, 60 for 5 years)
209+
* @return SqlCohortDefinition
210+
*/
211+
private SqlCohortDefinition createFamilyPlanningCohort(int fpAdministredConceptId, int methodConceptId,
212+
int familyPlanningConceptId, int typeOfUserConceptId, int userTypeConceptId, String gender, int ageThreshold,
213+
boolean ageGreaterOrEqual, int intervalMonths) {
214+
215+
String intervalClause = "";
216+
if (intervalMonths > 0) {
217+
if (intervalMonths == 60) {
218+
intervalClause = "DATE_SUB(:onOrAfter, INTERVAL 5 YEAR)";
219+
} else {
220+
intervalClause = "DATE_SUB(:onOrAfter, INTERVAL " + intervalMonths + " MONTH)";
221+
}
222+
} else {
223+
intervalClause = ":onOrAfter";
224+
}
225+
226+
String ageCondition;
227+
if (ageGreaterOrEqual) {
228+
ageCondition = "round(DATEDIFF(obs.obs_datetime, person.birthdate)/365.25, 1) >= " + ageThreshold;
229+
} else {
230+
ageCondition = "round(DATEDIFF(obs.obs_datetime, person.birthdate)/365.25, 1) < " + ageThreshold;
231+
}
232+
233+
String sql = "SELECT DISTINCT obs.person_id " + "FROM obs "
234+
+ "INNER JOIN person ON obs.person_id = person.person_id " + "WHERE obs.voided = 0 "
235+
+ "AND obs.concept_id = " + fpAdministredConceptId + " AND obs.value_coded = " + methodConceptId + " "
236+
+ "AND obs.obs_group_id IN (" + " SELECT obs_group_id FROM obs WHERE " + "obs.obs_group_id IN ("
237+
+ " SELECT obs_id FROM obs " + "WHERE obs_datetime >= " + intervalClause
238+
+ " AND obs_datetime <= :onOrBefore " + "AND concept_id = " + familyPlanningConceptId
239+
+ " ) AND person.gender = '" + gender + "' " + "AND " + ageCondition + " AND obs.concept_id = "
240+
+ typeOfUserConceptId + " AND obs.value_coded = " + userTypeConceptId + ")";
241+
242+
SqlCohortDefinition cohort = new SqlCohortDefinition(sql);
243+
cohort.addParameter(new Parameter("onOrAfter", "On Or After", Date.class));
244+
cohort.addParameter(new Parameter("onOrBefore", "On Or Before", Date.class));
245+
246+
return cohort;
247+
}
248+
249+
private CompositionCohortDefinition createCohortComposition(Object... elements) {
250+
CompositionCohortDefinition compCD = new CompositionCohortDefinition();
251+
compCD.initializeFromElements(elements);
252+
return compCD;
132253
}
133254

134-
private String applyMetadataReplacements(String rawSql) {
135-
String s = rawSql
136-
.replace(":FPAdministred",
137-
inizService.getConceptFromKey("report.MSPP.familyPlanning.FPAdministred").getConceptId() + "")
138-
.replace(":familyPlanning",
139-
inizService.getConceptFromKey("report.MSPP.familyPlanning.familyPlanning").getConceptId() + "")
140-
.replace(":femaleLT25",
141-
"person.gender = 'F' AND round(DATEDIFF(obs.obs_datetime, person.birthdate)/365.25, 1) < 25")
142-
.replace(":femaleGT25",
143-
"person.gender = 'F' AND round(DATEDIFF(obs.obs_datetime, person.birthdate)/365.25, 1) >= 25")
144-
.replace(":maleLT25",
145-
"person.gender = 'M' AND round(DATEDIFF(obs.obs_datetime, person.birthdate)/365.25, 1) < 25")
146-
.replace(":maleGT25",
147-
"person.gender = 'M' AND round(DATEDIFF(obs.obs_datetime, person.birthdate)/365.25, 1) >= 25")
148-
149-
.replace(":typeOfUser",
150-
inizService.getConceptFromKey("report.MSPP.familyPlanning.typeOfUser").getConceptId() + "")
151-
.replace(":new", inizService.getConceptFromKey("report.MSPP.familyPlanning.new").getConceptId() + "")
152-
.replace(":existent",
153-
inizService.getConceptFromKey("report.MSPP.familyPlanning.existent").getConceptId() + "")
154-
155-
.replace(":microgynon",
156-
inizService.getConceptFromKey("report.MSPP.familyPlanning.microgynon").getConceptId() + "")
157-
158-
.replace(":microlut",
159-
inizService.getConceptFromKey("report.MSPP.familyPlanning.microlut").getConceptId() + "")
160-
161-
.replace(":depoProveraInjection",
162-
inizService.getConceptFromKey("report.MSPP.familyPlanning.depoProveraInjection").getConceptId() + "")
163-
.replace(":jadel", inizService.getConceptFromKey("report.MSPP.familyPlanning.jadel").getConceptId() + "")
164-
.replace(":condom", inizService.getConceptFromKey("report.MSPP.familyPlanning.condom").getConceptId() + "");
165-
return s;
255+
@Override
256+
public List<ReportDesign> constructReportDesigns(ReportDefinition reportDefinition) {
257+
return Arrays
258+
.asList(ReportManagerUtil.createCsvReportDesign("8e300676-75d7-48f8-82eb-4fe9971459fe", reportDefinition));
166259
}
167260

168261
}

api/src/main/resources/messages.properties

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,6 @@ ${project.parent.artifactId}.report.MSPP.emergency.0_14years=(0-14 years)
122122
${project.parent.artifactId}.report.MSPP.emergency.above14years=(15 years and above)
123123
${project.parent.artifactId}.report.MSPP.emergency.medicalAndSurgicalEmergency=Medical and surgical emergency
124124

125-
${project.parent.artifactId}.report.MSPP.familyPlanning.reportName=MSPP Family Planning
126-
${project.parent.artifactId}.report.MSPP.familyPlanning.reportDescription=Family Planning report required by the Haitian MSPP
127125
${project.parent.artifactId}.report.MSPP.familyPlanning.reportName=MSPP Family Planning
128126
${project.parent.artifactId}.report.MSPP.familyPlanning.reportDescription=Family Planning report required by Haitian MSPP
129127
${project.parent.artifactId}.report.MSPP.familyPlanning.datasetName=Family Planning SQL Dataset

0 commit comments

Comments
 (0)