From a0229096203de6b9a28c72c566ad8f7e2557ebb4 Mon Sep 17 00:00:00 2001 From: Lubwama Samuel Date: Wed, 19 Jun 2024 08:08:27 +0300 Subject: [PATCH] U4X-571: Change DSDM Stability Criteria to use API instead of Java API (#514) --- .../PatientStabilityFragmentController.java | 246 +--------- .../ARTEnrollmentSubmissionAction.java | 3 +- .../web/customdto/StabilityCriteria.java | 173 +++++++ .../resource/StabilityCriteriaResource.java | 436 ++++++++++++++++++ .../webapp/fragments/patientStability.gsp | 121 +++-- ...atientStabilityFragmentControllerTest.java | 9 +- 6 files changed, 710 insertions(+), 278 deletions(-) create mode 100644 omod/src/main/java/org/openmrs/module/ugandaemr/web/customdto/StabilityCriteria.java create mode 100644 omod/src/main/java/org/openmrs/module/ugandaemr/web/resource/StabilityCriteriaResource.java diff --git a/omod/src/main/java/org/openmrs/module/ugandaemr/fragment/controller/PatientStabilityFragmentController.java b/omod/src/main/java/org/openmrs/module/ugandaemr/fragment/controller/PatientStabilityFragmentController.java index 0da123910..9eb9da248 100644 --- a/omod/src/main/java/org/openmrs/module/ugandaemr/fragment/controller/PatientStabilityFragmentController.java +++ b/omod/src/main/java/org/openmrs/module/ugandaemr/fragment/controller/PatientStabilityFragmentController.java @@ -3,260 +3,20 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openmrs.*; -import org.openmrs.api.ConceptService; -import org.openmrs.api.ObsService; -import org.openmrs.api.PatientService; -import org.openmrs.api.context.Context; import org.openmrs.ui.framework.UiUtils; import org.openmrs.ui.framework.fragment.FragmentModel; import org.springframework.web.bind.annotation.RequestParam; -import java.text.DateFormat; + import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; + + public class PatientStabilityFragmentController { private static final Log log = LogFactory.getLog(PatientStabilityFragmentController.class); public void controller(FragmentModel model, @RequestParam(value = "patientId", required = false) Patient patient, @RequestParam(value = "visitId", required = false) Visit visit, @RequestParam(value = "encounterId", required = false) Encounter encounter, UiUtils ui) throws ParseException { - String allowCliniciansToMakeDecisionOnDSDM=Context.getAdministrationService().getGlobalProperty("ugandaemr.dsdm.allowClinicalOverrideDSDMPatientStability"); - if(allowCliniciansToMakeDecisionOnDSDM.equals("false")) { - Integer baselineRegimenConceptId = 99061; - Integer currentRegimenConceptId = 90315; - ObsService obsService = Context.getObsService(); - ConceptService conceptService = Context.getConceptService(); - PatientService patientService = Context.getPatientService(); - Integer minimumDurationOnCurrentRegimen = Integer.parseInt(Context.getAdministrationService().getGlobalProperty("ugandaemr.dsdm.currentRegimenDurationRequirementInMonths")); - - Visit encounterVisit = new Visit(); - if (visit == null && encounter != null) { - encounterVisit = encounter.getVisit(); - } else if (visit != null) { - encounterVisit = visit; - } - - - /** - * Last Viral Load - */ - List vlDateObsList = getObsListFromIdList("SELECT obs_id FROM obs where obs.person_id='" + patient.getPatientId() + "' AND obs.concept_id = 163023 AND obs.voided = false ORDER BY obs.encounter_id DESC LIMIT 1"); - - if (vlDateObsList.size() > 0) { - List vlObsList = getObsListFromIdList("SELECT obs_id FROM obs where obs.person_id='" + patient.getPatientId() + "' AND obs.concept_id = 856 AND encounter_id='" + vlDateObsList.get(0).getEncounter().getEncounterId() + "' AND obs.voided = false ORDER BY obs.encounter_id DESC LIMIT 1"); - - if (vlObsList.size() > 0) { - model.addAttribute("vlObs", vlObsList.get(0)); - model.addAttribute("vlDateObs", vlDateObsList.get(0)); - } else { - model.addAttribute("vlObs", null); - model.addAttribute("vlDateObs", null); - } - } else { - model.addAttribute("vlDateObs", null); - model.addAttribute("vlObs", null); - } - - List personList = new ArrayList<>(); - personList.add(patient.getPerson()); - - /** - * Current regimen - */ - int monthOffSet = -minimumDurationOnCurrentRegimen; - - Obs obs = getMostRecentObservation(encounterVisit, "90315"); - - String query = ""; - String queryCurrentRegimen = ""; - List regimenObsList = new ArrayList<>(); - List currentRegimenList = new ArrayList<>(); - - //Check if Obs of Regimen is on not Null - if (obs != null) { - //Check if Obs conceptId is the same as the art encounter regimen concept - // Check if regimen is a DTG regimen - if (checkIfDTG(obs)) { - query = "SELECT obs_id FROM obs where obs.obs_datetime <= DATE('" + encounterVisit.getStartDatetime() + "') AND obs.person_id='" + patient.getPatientId() + "' AND concept_id=" + currentRegimenConceptId + " AND obs.voided = false ORDER BY obs.obs_datetime DESC"; - } else { - query = "SELECT obs_id FROM obs where obs.obs_datetime <= DATE('" + getDateBefore(encounterVisit.getStartDatetime(), monthOffSet, 0) + "') AND obs.person_id='" + patient.getPatientId() + "' AND obs.value_coded = " + obs.getValueCoded().getConceptId() + " AND obs.voided = false ORDER BY obs.encounter_id DESC"; - } - regimenObsList = getObsListFromIdList(query); - - queryCurrentRegimen = "SELECT obs_id FROM obs where obs.person_id='" + patient.getPatientId() + "' AND obs.obs_datetime <= DATE('" + encounterVisit.getStartDatetime() + "') AND obs.value_coded = " + obs.getValueCoded().getConceptId() + " AND obs.voided = false ORDER BY obs.obs_datetime ASC LIMIT 0,1"; - - currentRegimenList = getObsListFromIdList(queryCurrentRegimen); - } - - - if (regimenObsList.size() > 0) { - if (checkIfDTG(regimenObsList.get(0)) && regimenObsList.size() > 1) { - List regimenBeforeDTGObs = getObsListFromIdList("SELECT obs_id FROM obs where obs.obs_datetime <= DATE('" + getDateBefore(encounterVisit.getStartDatetime(), -12, 0) + "') AND obs.person_id='" + patient.getPatientId() + "' AND obs.concept_id = " + currentRegimenConceptId + " AND obs.voided = false ORDER BY obs.encounter_id DESC"); - if (regimenBeforeDTGObs.size() > 0) { - model.addAttribute("regimenBeforeDTGObs", regimenBeforeDTGObs.get(0)); - } else { - model.addAttribute("regimenBeforeDTGObs", ""); - } - } else { - model.addAttribute("regimenBeforeDTGObs", ""); - } - model.addAttribute("regimenObs", regimenObsList.get(0)); - } else { - model.addAttribute("regimenObs", null); - model.addAttribute("regimenBeforeDTGObs", ""); - } - - if (currentRegimenList.size() > 0) { - model.addAttribute("currentRegimenObs", currentRegimenList.get(0)); - } else { - model.addAttribute("currentRegimenObs", null); - } - model.addAttribute("baselineRegimenConceptId", baselineRegimenConceptId); - - /** - * Adherence - */ - List adherenceObsList = getObsListFromIdList("SELECT obs_id FROM obs where obs.obs_datetime BETWEEN '" + getDateBefore(encounterVisit.getStartDatetime(), -6, 0) + "' AND '" + encounterVisit.getStartDatetime() + "' AND obs.person_id='" + patient.getPatientId() + "' AND obs.concept_id = 90221 AND obs.voided = false ORDER BY obs.encounter_id DESC"); - - if (adherenceObsList.size() > 0) { - model.addAttribute("adherenceObs", adherenceObsList); - } else { - model.addAttribute("adherenceObs", null); - } - - /** - * ThirdLine Regimen - */ - List concepts = new ArrayList<>(); - Collection conceptAnswers = conceptService.getConcept(1).getAnswers(false); - for (ConceptAnswer conceptAnswer : conceptAnswers) { - if (conceptAnswer.getConcept().getConceptId() != 90002) { - conceptAnswers.remove(conceptAnswer); - concepts.add(conceptAnswer.getAnswerConcept()); - } - } - if (regimenObsList.size() > 0 && concepts.contains(regimenObsList.get(0).getValueCoded())) { - model.addAttribute("onThirdRegimen", true); - } else { - model.addAttribute("onThirdRegimen", false); - } - - /** - * Clinic Staging - */ - - List clinicStage = new ArrayList<>(); - List clinicStageObsList = getObsListFromIdList("SELECT obs_id FROM obs where obs.person_id='" + patient.getPatientId() + "' AND obs.concept_id IN (99083,90203) AND obs.voided = false ORDER BY obs.encounter_id DESC"); - - if (clinicStageObsList.size() > 0) { - model.addAttribute("conceptForClinicStage", clinicStageObsList.get(0).getValueCoded().getConceptId()); - } else { - model.addAttribute("conceptForClinicStage", null); - } - - /** - * Sputum Results - */ - Obs spetumObs = getMostRecentObservation(encounterVisit, "307"); - model.addAttribute("sputumResultObs", spetumObs); - - /** - * Sputum ResultDate - */ - Obs spetumDateObs = getMostRecentObservation(encounterVisit, "99392"); - model.addAttribute("sputumResultDateObs", spetumDateObs); - - - /** - * Current Regimen - */ - model.addAttribute("artStartDate", getArtStartDate(patient)); - model.addAttribute("enableCliniciansMakeStabilityDecisions", allowCliniciansToMakeDecisionOnDSDM); - }else{ - model.addAttribute("enableCliniciansMakeStabilityDecisions", allowCliniciansToMakeDecisionOnDSDM); - } - } - - - /** - * This Subtracts a date provided by number of moths and years given and returns a new date - * - * @param referenceDate - * @param noOfMoths - * @return - */ - public String getDateBefore(Date referenceDate, int noOfMoths, int noOfYears) { - Calendar cal = Calendar.getInstance(); - cal.setTime(referenceDate); - if (noOfMoths != 0) { - cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH)); - } - cal.add(Calendar.MONTH, noOfMoths); - cal.add(Calendar.YEAR, noOfYears); - DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); - String finalDate = null; - try { - finalDate = format.format(cal.getTime()); - } catch (Exception e) { - log.error("Failed to format date",e); - } - return finalDate; - } - - /** - * Gets List of Obs Basing on the query provided - * - * @param query - * @return - */ - private List getObsListFromIdList(String query) { - List obsList = new ArrayList<>(); - for (Object o : Context.getAdministrationService().executeSQL(query, true)) { - obsList.add(Context.getObsService().getObs(Integer.parseInt(((ArrayList) o).get(0).toString()))); - } - return obsList; - } - - /** - * Get ART START DATE From Summary Page of a Patient - * - * @param patient - * @return - */ - public Date getArtStartDate(Patient patient) { - List list = Context.getObsService().getObservationsByPersonAndConcept(patient, Context.getConceptService().getConcept(99161)); - Date artStartDate = null; - if (list.size() > 0) { - artStartDate = list.get(0).getValueDatetime(); - } - return artStartDate; - - } - - /** - * Check if DTG - * - * @param obs - * @return - */ - private boolean checkIfDTG(Obs obs) { - return "164976,164977,164978,164979".contains(obs.getValueCoded().getConceptId().toString()); - } - - /** - * gets the latest Observation basing on the visit Date and the concepts - * @param encounterVisit - * @param concepts Separate with , if many - * @return - */ - public Obs getMostRecentObservation(Visit encounterVisit, String concepts) { - String query = "SELECT obs_id FROM obs where obs.obs_datetime <= DATE('" + encounterVisit.getStartDatetime() + "') AND obs.person_id='" + encounterVisit.getPatient().getPatientId() + "' AND concept_id in ("+concepts+") AND obs.voided = false ORDER BY obs.obs_datetime DESC LIMIT 0,1"; - List obs = getObsListFromIdList(query); - if (obs.size() > 0) { - return obs.get(0); - } - return null; } } diff --git a/omod/src/main/java/org/openmrs/module/ugandaemr/htmlformentry/ARTEnrollmentSubmissionAction.java b/omod/src/main/java/org/openmrs/module/ugandaemr/htmlformentry/ARTEnrollmentSubmissionAction.java index f7f869a24..edb6ca0be 100644 --- a/omod/src/main/java/org/openmrs/module/ugandaemr/htmlformentry/ARTEnrollmentSubmissionAction.java +++ b/omod/src/main/java/org/openmrs/module/ugandaemr/htmlformentry/ARTEnrollmentSubmissionAction.java @@ -13,7 +13,6 @@ import org.openmrs.module.htmlformentry.FormEntryContext; import org.openmrs.module.htmlformentry.FormEntryContext.Mode; import org.openmrs.module.htmlformentry.FormEntrySession; -import org.openmrs.module.ugandaemr.fragment.controller.PatientSummaryFragmentController; import org.openmrs.module.ugandaemr.metadata.core.Programs; import java.util.ArrayList; @@ -32,7 +31,7 @@ * 2. Adds the patient to the ART First Line Regimen workflow state of the HIV Care Program */ public class ARTEnrollmentSubmissionAction implements CustomFormSubmissionAction { - private static final Log log = LogFactory.getLog(PatientSummaryFragmentController.class); + private static final Log log = LogFactory.getLog(ARTEnrollmentSubmissionAction.class); @Override public void applyAction(FormEntrySession session) { diff --git a/omod/src/main/java/org/openmrs/module/ugandaemr/web/customdto/StabilityCriteria.java b/omod/src/main/java/org/openmrs/module/ugandaemr/web/customdto/StabilityCriteria.java new file mode 100644 index 000000000..fadd34a00 --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/ugandaemr/web/customdto/StabilityCriteria.java @@ -0,0 +1,173 @@ +package org.openmrs.module.ugandaemr.web.customdto; + +import org.openmrs.Obs; + +import java.util.Date; +import java.util.List; + +public class StabilityCriteria { + private String uuid; + private Obs vlObs; + private Obs vlDateObs; + private Date artStartDate; + private Obs regimenObs; + private Integer regimenObsConceptId; + private Obs currentRegimenObs; + private Integer currentRegimenObsConceptId; + private Obs regimenBeforeDTGObs; + private Integer regimenBeforeDTGObsValueConceptId; + private Boolean onThirdRegimen; + private List adherenceObs; + private Integer conceptForClinicStage; + private Obs sputumResultDateObs; + private Obs sputumResultObs; + private Integer sputumResultObsValueConceptId; + private Integer baselineRegimenConceptId; + private String enableCliniciansMakeStabilityDecisions; + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public Obs getVlObs() { + return vlObs; + } + + public void setVlObs(Obs vlObs) { + this.vlObs = vlObs; + } + + public Obs getVlDateObs() { + return vlDateObs; + } + + public void setVlDateObs(Obs vlDateObs) { + this.vlDateObs = vlDateObs; + } + + public Date getArtStartDate() { + return artStartDate; + } + + public void setArtStartDate(Date artStartDate) { + this.artStartDate = artStartDate; + } + + public Obs getRegimenObs() { + return regimenObs; + } + + public void setRegimenObs(Obs regimenObs) { + this.regimenObs = regimenObs; + } + + public Obs getCurrentRegimenObs() { + return currentRegimenObs; + } + + public void setCurrentRegimenObs(Obs currentRegimenObs) { + this.currentRegimenObs = currentRegimenObs; + } + + public Obs getRegimenBeforeDTGObs() { + return regimenBeforeDTGObs; + } + + public void setRegimenBeforeDTGObs(Obs regimenBeforeDTGObs) { + this.regimenBeforeDTGObs = regimenBeforeDTGObs; + } + + + public Boolean getOnThirdRegimen() { + return onThirdRegimen; + } + + public void setOnThirdRegimen(Boolean onThirdRegimen) { + this.onThirdRegimen = onThirdRegimen; + } + + public List getAdherenceObs() { + return adherenceObs; + } + + public void setAdherenceObs(List adherenceObs) { + this.adherenceObs = adherenceObs; + } + + + public Integer getConceptForClinicStage() { + return conceptForClinicStage; + } + + public void setConceptForClinicStage(Integer conceptForClinicStage) { + this.conceptForClinicStage = conceptForClinicStage; + } + + public Obs getSputumResultDateObs() { + return sputumResultDateObs; + } + + public void setSputumResultDateObs(Obs sputumResultDateObs) { + this.sputumResultDateObs = sputumResultDateObs; + } + + public Obs getSputumResultObs() { + return sputumResultObs; + } + + public void setSputumResultObs(Obs sputumResultObs) { + this.sputumResultObs = sputumResultObs; + } + + public Integer getBaselineRegimenConceptId() { + return baselineRegimenConceptId; + } + + public void setBaselineRegimenConceptId(Integer baselineRegimenConceptId) { + this.baselineRegimenConceptId = baselineRegimenConceptId; + } + + public String getEnableCliniciansMakeStabilityDecisions() { + return enableCliniciansMakeStabilityDecisions; + } + + public void setEnableCliniciansMakeStabilityDecisions(String enableCliniciansMakeStabilityDecisions) { + this.enableCliniciansMakeStabilityDecisions = enableCliniciansMakeStabilityDecisions; + } + + public Integer getRegimenObsConceptId() { + return regimenObsConceptId; + } + + public void setRegimenObsConceptId(Integer regimenObsConceptId) { + this.regimenObsConceptId = regimenObsConceptId; + } + + public Integer getCurrentRegimenObsConceptId() { + return currentRegimenObsConceptId; + } + + public void setCurrentRegimenObsConceptId(Integer currentRegimenObsConceptId) { + this.currentRegimenObsConceptId = currentRegimenObsConceptId; + } + + public Integer getRegimenBeforeDTGObsValueConceptId() { + return regimenBeforeDTGObsValueConceptId; + } + + public void setRegimenBeforeDTGObsValueConceptId(Integer regimenBeforeDTGObsValueConceptId) { + this.regimenBeforeDTGObsValueConceptId = regimenBeforeDTGObsValueConceptId; + } + + public Integer getSputumResultObsValueConceptId() { + return sputumResultObsValueConceptId; + } + + public void setSputumResultObsValueConceptId(Integer sputumResultObsValueConceptId) { + this.sputumResultObsValueConceptId = sputumResultObsValueConceptId; + } +} diff --git a/omod/src/main/java/org/openmrs/module/ugandaemr/web/resource/StabilityCriteriaResource.java b/omod/src/main/java/org/openmrs/module/ugandaemr/web/resource/StabilityCriteriaResource.java new file mode 100644 index 000000000..7462a9f03 --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/ugandaemr/web/resource/StabilityCriteriaResource.java @@ -0,0 +1,436 @@ +package org.openmrs.module.ugandaemr.web.resource; + +import org.openmrs.*; +import org.openmrs.api.ConceptService; +import org.openmrs.api.context.Context; +import org.openmrs.module.ugandaemr.web.customdto.StabilityCriteria; +import org.openmrs.module.webservices.rest.web.RequestContext; +import org.openmrs.module.webservices.rest.web.RestConstants; +import org.openmrs.module.webservices.rest.web.annotation.Resource; +import org.openmrs.module.webservices.rest.web.representation.DefaultRepresentation; +import org.openmrs.module.webservices.rest.web.representation.FullRepresentation; +import org.openmrs.module.webservices.rest.web.representation.RefRepresentation; +import org.openmrs.module.webservices.rest.web.representation.Representation; +import org.openmrs.module.webservices.rest.web.resource.api.PageableResult; +import org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource; +import org.openmrs.module.webservices.rest.web.resource.impl.DelegatingResourceDescription; +import org.openmrs.module.webservices.rest.web.resource.impl.NeedsPaging; +import org.openmrs.module.webservices.rest.web.response.ResourceDoesNotSupportOperationException; +import org.openmrs.module.webservices.rest.web.response.ResponseException; + + +import java.text.DateFormat; + +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Resource(name = RestConstants.VERSION_1 + "/stabilitycriteria", supportedClass = StabilityCriteria.class, supportedOpenmrsVersions = {"1.9.* - 9.*"}) +public class StabilityCriteriaResource extends DelegatingCrudResource { + + @Override + public StabilityCriteria newDelegate() { + return new StabilityCriteria(); + } + + @Override + public StabilityCriteria save(StabilityCriteria duplicateEncounter) { + throw new ResourceDoesNotSupportOperationException("Operation not supported"); + } + + @Override + public StabilityCriteria getByUniqueId(String uniqueId) { + throw new ResourceDoesNotSupportOperationException("Operation not supported"); + } + + @Override + protected void delete(StabilityCriteria StabilityCriteria, String s, RequestContext requestContext) throws ResponseException { + throw new ResourceDoesNotSupportOperationException("Operation not supported"); + } + + @Override + public void purge(StabilityCriteria StabilityCriteria, RequestContext requestContext) throws ResponseException { + throw new ResourceDoesNotSupportOperationException("Operation not supported"); + } + + @Override + public NeedsPaging doGetAll(RequestContext context) throws ResponseException { + throw new ResourceDoesNotSupportOperationException("Operation not supported"); + } + + @Override + public List getAvailableRepresentations() { + return Arrays.asList(Representation.DEFAULT, Representation.FULL); + } + + @Override + public DelegatingResourceDescription getRepresentationDescription(Representation rep) { + if (rep instanceof DefaultRepresentation) { + DelegatingResourceDescription description = new DelegatingResourceDescription(); + description.addProperty("uuid"); + description.addProperty("vlObs", Representation.REF); + description.addProperty("vlDateObs", Representation.REF); + description.addProperty("artStartDate"); + description.addProperty("regimenObs", Representation.REF); + description.addProperty("regimenObsConceptId"); + description.addProperty("currentRegimenObs", Representation.REF); + description.addProperty("currentRegimenObsConceptId"); + description.addProperty("regimenBeforeDTGObs", Representation.REF); + description.addProperty("regimenBeforeDTGObsValueConceptId"); + description.addProperty("onThirdRegimen"); + description.addProperty("adherenceObs", Representation.REF); + description.addProperty("conceptForClinicStage"); + description.addProperty("sputumResultDateObs", Representation.REF); + description.addProperty("sputumResultObs", Representation.REF); + description.addProperty("sputumResultObsValueConceptId"); + description.addProperty("baselineRegimenConceptId"); + description.addProperty("enableCliniciansMakeStabilityDecisions"); + + description.addSelfLink(); + + return description; + } else if (rep instanceof FullRepresentation) { + DelegatingResourceDescription description = new DelegatingResourceDescription(); + description.addProperty("uuid"); + description.addProperty("vlObs", Representation.FULL); + description.addProperty("vlDateObs", Representation.FULL); + description.addProperty("artStartDate"); + description.addProperty("regimenObs", Representation.FULL); + description.addProperty("regimenObsConceptId"); + description.addProperty("currentRegimenObs", Representation.FULL); + description.addProperty("currentRegimenObsConceptId"); + description.addProperty("regimenBeforeDTGObs", Representation.FULL); + description.addProperty("regimenBeforeDTGObsValueConceptId"); + description.addProperty("onThirdRegimen"); + description.addProperty("adherenceObs", Representation.FULL); + description.addProperty("conceptForClinicStage"); + description.addProperty("sputumResultDateObs", Representation.FULL); + description.addProperty("sputumResultObs", Representation.FULL); + description.addProperty("sputumResultObsValueConceptId"); + description.addProperty("baselineRegimenConceptId"); + description.addProperty("enableCliniciansMakeStabilityDecisions"); + description.addSelfLink(); + description.addLink("full", ".?v=" + RestConstants.REPRESENTATION_FULL); + return description; + } else if (rep instanceof RefRepresentation) { + DelegatingResourceDescription description = new DelegatingResourceDescription(); + description.addProperty("uuid"); + description.addProperty("vlObs", Representation.DEFAULT); + description.addProperty("vlDateObs", Representation.DEFAULT); + description.addProperty("artStartDate"); + description.addProperty("regimenObs", Representation.DEFAULT); + description.addProperty("regimenObsConceptId"); + description.addProperty("currentRegimenObs", Representation.DEFAULT); + description.addProperty("currentRegimenObsConceptId"); + description.addProperty("regimenBeforeDTGObs", Representation.DEFAULT); + description.addProperty("regimenBeforeDTGObsValueConceptId"); + description.addProperty("onThirdRegimen"); + description.addProperty("adherenceObs", Representation.DEFAULT); + description.addProperty("conceptForClinicStage"); + description.addProperty("sputumResultDateObs", Representation.DEFAULT); + description.addProperty("sputumResultObs", Representation.DEFAULT); + description.addProperty("sputumResultObsValueConceptId"); + description.addProperty("baselineRegimenConceptId"); + description.addProperty("enableCliniciansMakeStabilityDecisions"); + description.addSelfLink(); + return description; + } + return null; + } + + @Override + protected PageableResult doSearch(RequestContext context) { + Encounter encounter = null; + Patient patient = null; + Visit visit = null; + + if (context.getParameter("visit") != null) { + if (isUuid(context.getParameter("visit"))) { + visit = Context.getVisitService().getVisitByUuid(context.getParameter("visit")); + } else { + visit = Context.getVisitService().getVisit(Integer.parseInt(context.getParameter("visit"))); + } + } + if (context.getParameter("patient") != null) { + if (isUuid(context.getParameter("patient"))) { + patient = Context.getPatientService().getPatientByUuid(context.getParameter("patient")); + } else { + patient = Context.getPatientService().getPatient(Integer.parseInt(context.getParameter("patient"))); + } + } + if (context.getParameter("encounter") != null) { + if (isUuid(context.getParameter("encounter"))) { + encounter = Context.getEncounterService().getEncounterByUuid(context.getParameter("encounter")); + } else { + encounter = Context.getEncounterService().getEncounter((Integer.parseInt(context.getParameter("encounter")))); + } + } + + StabilityCriteria stabilityCriteria = generateStabilityCriteria(patient, encounter, visit); + + + return new NeedsPaging(Collections.singletonList(stabilityCriteria), context); + } + + + private StabilityCriteria generateStabilityCriteria(Patient patient, Encounter encounter, Visit visit) { + StabilityCriteria stabilityCriteria = newDelegate(); + String allowCliniciansToMakeDecisionOnDSDM = Context.getAdministrationService().getGlobalProperty("ugandaemr.dsdm.allowClinicalOverrideDSDMPatientStability"); + if (allowCliniciansToMakeDecisionOnDSDM.equals("false")) { + Integer baselineRegimenConceptId = 99061; + Integer currentRegimenConceptId = 90315; + ConceptService conceptService = Context.getConceptService(); + Integer minimumDurationOnCurrentRegimen = Integer.parseInt(Context.getAdministrationService().getGlobalProperty("ugandaemr.dsdm.currentRegimenDurationRequirementInMonths")); + + Visit encounterVisit = new Visit(); + if (visit == null && encounter != null) { + encounterVisit = encounter.getVisit(); + } else if (visit != null) { + encounterVisit = visit; + } + + + /** + * Last Viral Load + */ + List vlDateObsList = getObsListFromIdList("SELECT obs_id FROM obs where obs.person_id='" + patient.getPatientId() + "' AND obs.concept_id = 163023 AND obs.voided = false ORDER BY obs.encounter_id DESC LIMIT 1"); + + if (vlDateObsList.size() > 0) { + List vlObsList = getObsListFromIdList("SELECT obs_id FROM obs where obs.person_id='" + patient.getPatientId() + "' AND obs.concept_id = 856 AND encounter_id='" + vlDateObsList.get(0).getEncounter().getEncounterId() + "' AND obs.voided = false ORDER BY obs.encounter_id DESC LIMIT 1"); + + if (vlObsList.size() > 0) { + stabilityCriteria.setVlObs(vlObsList.get(0)); + stabilityCriteria.setVlDateObs(vlDateObsList.get(0)); + + } else { + stabilityCriteria.setVlObs(null); + stabilityCriteria.setVlDateObs(null); + } + } else { + stabilityCriteria.setVlObs(null); + stabilityCriteria.setVlDateObs(null); + } + + List personList = new ArrayList<>(); + personList.add(patient.getPerson()); + + /** + * Current regimen + */ + int monthOffSet = -minimumDurationOnCurrentRegimen; + + Obs obs = getMostRecentObservation(encounterVisit, "90315"); + + String query = ""; + String queryCurrentRegimen = ""; + List regimenObsList = new ArrayList<>(); + List currentRegimenList = new ArrayList<>(); + + //Check if Obs of Regimen is on not Null + if (obs != null) { + //Check if Obs conceptId is the same as the art encounter regimen concept + // Check if regimen is a DTG regimen + if (checkIfDTG(obs)) { + query = "SELECT obs_id FROM obs where obs.obs_datetime <= DATE('" + encounterVisit.getStartDatetime() + "') AND obs.person_id='" + patient.getPatientId() + "' AND concept_id=" + currentRegimenConceptId + " AND obs.voided = false ORDER BY obs.obs_datetime DESC"; + } else { + query = "SELECT obs_id FROM obs where obs.obs_datetime <= DATE('" + getDateBefore(encounterVisit.getStartDatetime(), monthOffSet, 0) + "') AND obs.person_id='" + patient.getPatientId() + "' AND obs.value_coded = " + obs.getValueCoded().getConceptId() + " AND obs.voided = false ORDER BY obs.encounter_id DESC"; + } + regimenObsList = getObsListFromIdList(query); + + queryCurrentRegimen = "SELECT obs_id FROM obs where obs.person_id='" + patient.getPatientId() + "' AND obs.obs_datetime <= DATE('" + encounterVisit.getStartDatetime() + "') AND obs.value_coded = " + obs.getValueCoded().getConceptId() + " AND obs.voided = false ORDER BY obs.obs_datetime ASC LIMIT 0,1"; + + currentRegimenList = getObsListFromIdList(queryCurrentRegimen); + } + + + if (regimenObsList.size() > 0) { + if (checkIfDTG(regimenObsList.get(0)) && regimenObsList.size() > 1) { + List regimenBeforeDTGObs = getObsListFromIdList("SELECT obs_id FROM obs where obs.obs_datetime <= DATE('" + getDateBefore(encounterVisit.getStartDatetime(), -12, 0) + "') AND obs.person_id='" + patient.getPatientId() + "' AND obs.concept_id = " + currentRegimenConceptId + " AND obs.voided = false ORDER BY obs.encounter_id DESC"); + if (regimenBeforeDTGObs.size() > 0) { + stabilityCriteria.setRegimenBeforeDTGObs(regimenBeforeDTGObs.get(0)); + stabilityCriteria.setRegimenBeforeDTGObsValueConceptId(regimenBeforeDTGObs.get(0).getValueCoded().getConceptId()); + } else { + stabilityCriteria.setRegimenBeforeDTGObs(null); + } + } else { + stabilityCriteria.setRegimenBeforeDTGObs(null); + } + stabilityCriteria.setRegimenObs(regimenObsList.get(0)); + stabilityCriteria.setRegimenObsConceptId(regimenObsList.get(0).getConcept().getConceptId()); + } else { + stabilityCriteria.setRegimenObs(null); + stabilityCriteria.setRegimenBeforeDTGObs(null); + } + + if (currentRegimenList.size() > 0) { + stabilityCriteria.setCurrentRegimenObs(currentRegimenList.get(0)); + stabilityCriteria.setCurrentRegimenObsConceptId(currentRegimenList.get(0).getConcept().getConceptId()); + } else { + stabilityCriteria.setCurrentRegimenObs(null); + } + stabilityCriteria.setBaselineRegimenConceptId(baselineRegimenConceptId); + + /** + * Adherence + */ + List adherenceObsList = getObsListFromIdList("SELECT obs_id FROM obs where obs.obs_datetime BETWEEN '" + getDateBefore(encounterVisit.getStartDatetime(), -6, 0) + "' AND '" + encounterVisit.getStartDatetime() + "' AND obs.person_id='" + patient.getPatientId() + "' AND obs.concept_id = 90221 AND obs.voided = false ORDER BY obs.encounter_id DESC"); + + if (adherenceObsList.size() > 0) { + stabilityCriteria.setAdherenceObs(adherenceObsList); + } else { + stabilityCriteria.setAdherenceObs(null); + } + + /** + * ThirdLine Regimen + */ + List concepts = new ArrayList<>(); + Collection conceptAnswers = conceptService.getConcept(1).getAnswers(false); + for (ConceptAnswer conceptAnswer : conceptAnswers) { + if (conceptAnswer.getConcept().getConceptId() != 90002) { + conceptAnswers.remove(conceptAnswer); + concepts.add(conceptAnswer.getAnswerConcept()); + } + } + if (regimenObsList.size() > 0 && concepts.contains(regimenObsList.get(0).getValueCoded())) { + stabilityCriteria.setOnThirdRegimen(true); + } else { + stabilityCriteria.setOnThirdRegimen(false); + } + + /** + * Clinic Staging + */ + + List clinicStage = new ArrayList<>(); + List clinicStageObsList = getObsListFromIdList("SELECT obs_id FROM obs where obs.person_id='" + patient.getPatientId() + "' AND obs.concept_id IN (99083,90203) AND obs.voided = false ORDER BY obs.encounter_id DESC"); + + if (clinicStageObsList.size() > 0) { + stabilityCriteria.setConceptForClinicStage(clinicStageObsList.get(0).getValueCoded().getConceptId()); + + } else { + stabilityCriteria.setConceptForClinicStage(null); + } + + /** + * Sputum Results + */ + Obs sputumResults = getMostRecentObservation(encounterVisit, "307"); + if (sputumResults != null) { + stabilityCriteria.setSputumResultObs(sputumResults); + stabilityCriteria.setSputumResultObsValueConceptId(sputumResults.getValueCoded().getConceptId()); + } + + + /** + * Sputum ResultDate + */ + stabilityCriteria.setSputumResultDateObs(getMostRecentObservation(encounterVisit, "99392")); + + + /** + * Current Regimen + */ + stabilityCriteria.setArtStartDate(getArtStartDate(patient)); + stabilityCriteria.setEnableCliniciansMakeStabilityDecisions(allowCliniciansToMakeDecisionOnDSDM); + } else { + stabilityCriteria.setEnableCliniciansMakeStabilityDecisions(allowCliniciansToMakeDecisionOnDSDM); + } + return stabilityCriteria; + } + + + /** + * This Subtracts a date provided by number of moths and years given and returns a new date + * + * @param referenceDate + * @param noOfMoths + * @return + */ + public String getDateBefore(Date referenceDate, int noOfMoths, int noOfYears) { + Calendar cal = Calendar.getInstance(); + cal.setTime(referenceDate); + if (noOfMoths != 0) { + cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH)); + } + cal.add(Calendar.MONTH, noOfMoths); + cal.add(Calendar.YEAR, noOfYears); + DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + String finalDate = null; + try { + finalDate = format.format(cal.getTime()); + } catch (Exception e) { + log.error("Failed to format date", e); + } + return finalDate; + } + + /** + * Gets List of Obs Basing on the query provided + * + * @param query + * @return + */ + private List getObsListFromIdList(String query) { + List obsList = new ArrayList<>(); + for (Object o : Context.getAdministrationService().executeSQL(query, true)) { + obsList.add(Context.getObsService().getObs(Integer.parseInt(((ArrayList) o).get(0).toString()))); + } + return obsList; + } + + /** + * Get ART START DATE From Summary Page of a Patient + * + * @param patient + * @return + */ + public Date getArtStartDate(Patient patient) { + List list = Context.getObsService().getObservationsByPersonAndConcept(patient, Context.getConceptService().getConcept(99161)); + Date artStartDate = null; + if (list.size() > 0) { + artStartDate = list.get(0).getValueDatetime(); + } + return artStartDate; + + } + + /** + * Check if DTG + * + * @param obs + * @return + */ + private boolean checkIfDTG(Obs obs) { + return "164976,164977,164978,164979".contains(obs.getValueCoded().getConceptId().toString()); + } + + + /** + * gets the latest Observation basing on the visit Date and the concepts + * + * @param encounterVisit + * @param concepts Separate with , if many + * @return + */ + public Obs getMostRecentObservation(Visit encounterVisit, String concepts) { + String query = "SELECT obs_id FROM obs where obs.obs_datetime <= DATE('" + encounterVisit.getStartDatetime() + "') AND obs.person_id='" + encounterVisit.getPatient().getPatientId() + "' AND concept_id in (" + concepts + ") AND obs.voided = false ORDER BY obs.obs_datetime DESC LIMIT 0,1"; + List obs = getObsListFromIdList(query); + if (!obs.isEmpty()) { + return obs.get(0); + } + return null; + } + + private Boolean isUuid(String params) { + String regex = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(params); + if (matcher.matches()) { + return true; + } else { + return false; + } + } +} diff --git a/omod/src/main/webapp/fragments/patientStability.gsp b/omod/src/main/webapp/fragments/patientStability.gsp index 3c4efea88..de7643f48 100644 --- a/omod/src/main/webapp/fragments/patientStability.gsp +++ b/omod/src/main/webapp/fragments/patientStability.gsp @@ -4,49 +4,112 @@ img { height: auto; } -<% if (enableCliniciansMakeStabilityDecisions == "false") { %> -
-
-
${vlObs?.valueNumeric ?: ""}
+ + +
+
+
-
${regimenObs?.valueCoded?.conceptId ?: ""}
+
-
${regimenObs?.encounter?.encounterDatetime ?: ""}
+
+
-
- <% if (currentRegimenObs?.concept?.conceptId == baselineRegimenConceptId) { %> - ${artStartDate ?: ""} - <% } else { %> - ${currentRegimenObs?.encounter?.encounterDatetime ?: ""} - <% } %> -
+
- <% if (regimenBeforeDTGObs != "") { %> -
${regimenBeforeDTGObs?.valueCoded?.conceptId ?: ""}
+
-
${regimenBeforeDTGObs?.encounter?.encounterDatetime ?: ""}
- <% } %> +
-
${onThirdRegimen}
+
-
<% adherenceObs?.each { %> - ${it?.valueCoded?.name}<% } %>
+
-
${conceptForClinicStage}
+
-
${sputumResultDateObs?.valueDate ?: ""}
+
-
${sputumResultDateObs?.encounter?.encounterDatetime ?: ""}
+
-
${sputumResultObs?.valueCoded?.conceptId ?: ""}
+
+
- - <% } %> +
\ No newline at end of file diff --git a/omod/src/test/java/org/openmrs/module/ugandaemr/fragment/PatientStabilityFragmentControllerTest.java b/omod/src/test/java/org/openmrs/module/ugandaemr/fragment/PatientStabilityFragmentControllerTest.java index f7bc26268..52884b70d 100644 --- a/omod/src/test/java/org/openmrs/module/ugandaemr/fragment/PatientStabilityFragmentControllerTest.java +++ b/omod/src/test/java/org/openmrs/module/ugandaemr/fragment/PatientStabilityFragmentControllerTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import org.openmrs.Patient; import org.openmrs.module.ugandaemr.fragment.controller.PatientStabilityFragmentController; +import org.openmrs.module.ugandaemr.web.resource.StabilityCriteriaResource; import org.openmrs.web.test.jupiter.BaseModuleWebContextSensitiveTest; @@ -29,16 +30,16 @@ public void cleanup() throws Exception { @Test public void testDateSubtraction() { - PatientStabilityFragmentController patientStabilityFragmentController = new PatientStabilityFragmentController(); + StabilityCriteriaResource stabilityCriteriaResource = new StabilityCriteriaResource(); - patientStabilityFragmentController.getDateBefore(new Date(), -12, 0); + stabilityCriteriaResource.getDateBefore(new Date(), -12, 0); } @Test public void testGetArtStartDate() { Patient patient = new Patient(1393); - PatientStabilityFragmentController patientStabilityFragmentController = new PatientStabilityFragmentController(); - Date artStartDate = patientStabilityFragmentController.getArtStartDate(patient); + StabilityCriteriaResource stabilityCriteriaResource = new StabilityCriteriaResource(); + Date artStartDate = stabilityCriteriaResource.getArtStartDate(patient); assertNotNull(artStartDate); assertEquals(artStartDate.toString(), "2013-02-06 00:00:00.0"); }