Skip to content

Commit

Permalink
EA-198: Add support for configuring Mother Child relationships within… (
Browse files Browse the repository at this point in the history
  • Loading branch information
mogoodrich authored Aug 8, 2024
1 parent 348d202 commit 131ee91
Show file tree
Hide file tree
Showing 13 changed files with 1,059 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,6 @@ public class EmrApiConstants {
));

public static final String GP_USE_LEGACY_DIAGNOSIS_SERVICE = "emrapi.useLegacyDiagnosisService";

public static final String METADATA_MAPPING_MOTHER_CHILD_RELATIONSHIP_TYPE = "emrapi.motherChildRelationshipType";
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.openmrs.PatientIdentifierType;
import org.openmrs.PersonAttributeType;
import org.openmrs.Provider;
import org.openmrs.RelationshipType;
import org.openmrs.Role;
import org.openmrs.VisitType;
import org.openmrs.module.emrapi.diagnosis.DiagnosisMetadata;
Expand Down Expand Up @@ -347,4 +348,8 @@ public List<Disposition> getDispositions() {
public DispositionDescriptor getDispositionDescriptor() {
return dispositionService.getDispositionDescriptor();
}

public RelationshipType getMotherChildRelationshipType() {
return getEmrApiMetadataByCode(RelationshipType.class, EmrApiConstants.METADATA_MAPPING_MOTHER_CHILD_RELATIONSHIP_TYPE, false);
}
}
12 changes: 12 additions & 0 deletions api/src/main/java/org/openmrs/module/emrapi/maternal/Child.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.openmrs.module.emrapi.maternal;

import lombok.Data;
import org.openmrs.Patient;
import org.openmrs.module.emrapi.adt.InpatientAdmission;

@Data
public class Child {
private Patient child;
private Patient mother;
private InpatientAdmission childAdmission;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.openmrs.module.emrapi.maternal;

import java.util.List;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ChildrenByMothersSearchCriteria {
private List<String> motherUuids; // restrict to children of these mothers
@Accessors(fluent = true) private boolean requireMotherHasActiveVisit = false; // restrict to children of mothers who have an active visit
@Accessors(fluent = true) private boolean requireChildHasActiveVisit = false; // restrict to children who have an active visit
@Accessors(fluent = true) private boolean requireChildBornDuringMothersActiveVisit = false; // restrict to children who were born during their mother's active visit
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.openmrs.module.emrapi.maternal;

import java.util.List;

import org.openmrs.api.OpenmrsService;

public interface MaternalService extends OpenmrsService {

/**
* Fetches patients who are "children" (personB) of a Mother-Child relationship
* @param criteria search criteria (see class for details)
* @return a list of children, with their linked mothers (note this returns a "Child" per mother-child pair, so a child with multiple mothers will appear multiple times)
*/
List<Child> getChildrenByMothers(ChildrenByMothersSearchCriteria criteria);

/**
* Fetches patients who are "mothers" (personA) of a Mother-Child relationship
* @param criteria search criteria (see class for details)
* @return a list of mothers, with their linked children (note this returns a "Mother" per mother-child pair, so a mother with multiple children will appear multiple times)
*/
List<Mother> getMothersByChildren(MothersByChildrenSearchCriteria criteria);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package org.openmrs.module.emrapi.maternal;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.openmrs.Patient;
import org.openmrs.RelationshipType;
import org.openmrs.api.APIException;
import org.openmrs.api.impl.BaseOpenmrsService;
import org.openmrs.module.emrapi.EmrApiProperties;
import org.openmrs.module.emrapi.adt.AdtService;
import org.openmrs.module.emrapi.adt.InpatientAdmission;
import org.openmrs.module.emrapi.adt.InpatientAdmissionSearchCriteria;
import org.openmrs.module.emrapi.db.EmrApiDAO;

public class MaternalServiceImpl extends BaseOpenmrsService implements MaternalService {

private EmrApiProperties emrApiProperties;

private AdtService adtService;

private EmrApiDAO emrApiDAO;

public void setEmrApiProperties(EmrApiProperties emrApiProperties) {
this.emrApiProperties = emrApiProperties;
}

public void setEmrApiDAO(EmrApiDAO emrApiDAO) {
this.emrApiDAO = emrApiDAO;
}

public void setAdtService(AdtService adtService) {
this.adtService = adtService;
}

public List<Child> getChildrenByMothers(ChildrenByMothersSearchCriteria criteria) {

RelationshipType motherChildRelationshipType = emrApiProperties.getMotherChildRelationshipType();

if (motherChildRelationshipType == null) {
throw new APIException("Mother-Child relationship type has not been configured");
}

Map<String, Object> parameters = new HashMap<>();
parameters.put("motherUuids", criteria.getMotherUuids());
parameters.put("childUuids", null);
parameters.put("motherChildRelationshipType", motherChildRelationshipType);
parameters.put("requireMotherHasActiveVisit", criteria.requireMotherHasActiveVisit());
parameters.put("requireChildHasActiveVisit", criteria.requireChildHasActiveVisit());
parameters.put("requireChildBornDuringMothersActiveVisit", criteria.requireChildBornDuringMothersActiveVisit());

List<?> l = emrApiDAO.executeHqlFromResource("hql/mother_child.hql", parameters, List.class);

List<Child> ret = new ArrayList<>();

for (Object req : l) {
Object[] row = (Object[]) req;
Child child = new Child();
child.setMother((Patient) row[0]);
child.setChild((Patient) row[1]);
ret.add(child);
}

// now fetch all the admissions for children in the result set
InpatientAdmissionSearchCriteria inpatientAdmissionSearchCriteria = new InpatientAdmissionSearchCriteria();
inpatientAdmissionSearchCriteria.setPatientIds(new ArrayList<>(ret.stream().map(Child::getChild).map(Patient::getId).collect(Collectors.toSet())));
List<InpatientAdmission> admissions = adtService.getInpatientAdmissions(inpatientAdmissionSearchCriteria);
Map<Patient, InpatientAdmission> admissionsByPatient = new HashMap<>();
for (InpatientAdmission admission : admissions) {
admissionsByPatient.put(admission.getVisit().getPatient(), admission);
}
for (Child child : ret) {
child.setChildAdmission(admissionsByPatient.get(child.getChild()));
}

return ret;
}

public List<Mother> getMothersByChildren(MothersByChildrenSearchCriteria criteria) {
RelationshipType motherChildRelationshipType = emrApiProperties.getMotherChildRelationshipType();

if (motherChildRelationshipType == null) {
throw new APIException("Mother-Child relationship type has not been configured");
}

Map<String, Object> parameters = new HashMap<>();
parameters.put("motherUuids", null);
parameters.put("childUuids", criteria.getChildUuids());
parameters.put("motherChildRelationshipType", motherChildRelationshipType);
parameters.put("requireMotherHasActiveVisit", criteria.requireMotherHasActiveVisit());
parameters.put("requireChildHasActiveVisit", criteria.requireChildHasActiveVisit());
parameters.put("requireChildBornDuringMothersActiveVisit", criteria.requireChildBornDuringMothersActiveVisit());

List<?> l = emrApiDAO.executeHqlFromResource("hql/mother_child.hql", parameters, List.class);

List<Mother> ret = new ArrayList<>();

for (Object req : l) {
Object[] row = (Object[]) req;
Mother mother = new Mother();
mother.setMother((Patient) row[0]);
mother.setChild((Patient) row[1]);
ret.add(mother);
}

// now fetch all the admissions for mothers in the result set
InpatientAdmissionSearchCriteria inpatientAdmissionSearchCriteria = new InpatientAdmissionSearchCriteria();
inpatientAdmissionSearchCriteria.setPatientIds(new ArrayList<>(ret.stream().map(Mother::getMother).map(Patient::getId).collect(Collectors.toSet())));
List<InpatientAdmission> admissions = adtService.getInpatientAdmissions(inpatientAdmissionSearchCriteria);
Map<Patient, InpatientAdmission> admissionsByPatient = new HashMap<>();
for (InpatientAdmission admission : admissions) {
admissionsByPatient.put(admission.getVisit().getPatient(), admission);
}
for (Mother mother : ret) {
mother.setMotherAdmission(admissionsByPatient.get(mother.getMother()));
}


return ret;
}
}
13 changes: 13 additions & 0 deletions api/src/main/java/org/openmrs/module/emrapi/maternal/Mother.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.openmrs.module.emrapi.maternal;

import lombok.Data;
import org.openmrs.Patient;
import org.openmrs.module.emrapi.adt.InpatientAdmission;


@Data
public class Mother {
private Patient mother;
private Patient child;
private InpatientAdmission motherAdmission;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.openmrs.module.emrapi.maternal;

import java.util.List;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MothersByChildrenSearchCriteria {
private List<String> childUuids; // restrict to mothers of these children
@Accessors(fluent = true) private Boolean requireMotherHasActiveVisit = false; // restrict to mothers who have an active visit
@Accessors(fluent = true) private Boolean requireChildHasActiveVisit = false; // restrict to mothers of children who have an active visit
@Accessors(fluent = true) private boolean requireChildBornDuringMothersActiveVisit = false; // restrict to mothers who had a child born during their active visit

}
18 changes: 18 additions & 0 deletions api/src/main/resources/hql/mother_child.hql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
select
mother,
child
from
Relationship as motherChildRelationship
inner join motherChildRelationship.personA as mother
inner join motherChildRelationship.personB as child
where
((:motherUuids) is null or mother.uuid in (:motherUuids))
and ((:childUuids) is null or child.uuid in (:childUuids))
and motherChildRelationship.relationshipType = :motherChildRelationshipType
and (:requireMotherHasActiveVisit = false or (select count(motherVisit) from Visit as motherVisit where motherVisit.patient = mother and motherVisit.stopDatetime is null and motherVisit.voided = false) > 0)
and (:requireChildHasActiveVisit = false or (select count(childVisit) from Visit as childVisit where childVisit.patient = child and childVisit.stopDatetime is null and childVisit.voided = false) > 0)
and (:requireChildBornDuringMothersActiveVisit = false or (select count(motherVisit) from Visit as motherVisit where motherVisit.patient = mother and motherVisit.stopDatetime is null and motherVisit.voided = false
and year(child.birthdate) >= year(motherVisit.startDatetime)
and month(child.birthdate) >= month(motherVisit.startDatetime)
and day(child.birthdate) >= day(motherVisit.startDatetime)) > 0)
and mother.voided = false and child.voided = false and motherChildRelationship.voided = false
28 changes: 28 additions & 0 deletions api/src/main/resources/moduleApplicationContext.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,34 @@
</property>
</bean>

<bean id="maternalService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="target">
<bean class="org.openmrs.module.emrapi.maternal.MaternalServiceImpl">
<property name="adtService" ref="adtService"/>
<property name="emrApiProperties" ref="emrApiProperties"/>
<property name="emrApiDAO" ref="emrApiDAOImpl"/>
</bean>
</property>
<property name="preInterceptors">
<ref bean="serviceInterceptors"/>
</property>
<property name="transactionAttributeSource">
<ref bean="transactionAttributeSource"/>
</property>
</bean>

<bean parent="serviceContext">
<property name="moduleService">
<list merge="true">
<value>org.openmrs.module.emrapi.maternal.MaternalService</value>
<ref bean="maternalService"/>
</list>
</property>
</bean>

<bean id="exitFromCareService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager"/>
Expand Down
Loading

0 comments on commit 131ee91

Please sign in to comment.