@SuppressWarnings("unused")
  public static JSONObject createJsonObservation(Obs obs) {
    JSONObject jsonObs = new JSONObject();
    jsonObs.put("observation_id", obs.getObsId());
    jsonObs.put("concept_name", obs.getConcept().getDisplayString());

    Date obsDate = obs.getObsDatetime() == null ? new Date() : obs.getObsDatetime();

    SimpleDateFormat formatDateJava = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
    String dateStr = obsDate.getTime() + "";

    jsonObs.put("date", dateStr);

    if (obs.getConcept().getDatatype().isNumeric()) { // ADD MORE DATATYPES

      ConceptNumeric conceptNumeric =
          Context.getConceptService().getConceptNumeric(obs.getConcept().getId());
      jsonObs.put("units_of_measurement", conceptNumeric.getUnits());
      jsonObs.put("absolute_high", conceptNumeric.getHiAbsolute());
      jsonObs.put("absolute_low", conceptNumeric.getLowAbsolute());
      jsonObs.put("critical_high", conceptNumeric.getHiCritical());
      jsonObs.put("critical_low", conceptNumeric.getLowCritical());
      jsonObs.put("normal_high", conceptNumeric.getHiNormal());
      jsonObs.put("normal_low", conceptNumeric.getLowNormal());
    }
    jsonObs.put("value_type", obs.getConcept().getDatatype().getName());

    jsonObs.put("value", obs.getValueAsString(Context.getLocale()));
    jsonObs.put("location", obs.getLocation().getDisplayString());
    jsonObs.put("creator", obs.getCreator().getDisplayString());
    Set<EncounterProvider> encounterProviders = obs.getEncounter().getEncounterProviders();

    if (encounterProviders != null && encounterProviders.iterator().hasNext()) {
      EncounterProvider provider = encounterProviders.iterator().next();
      if (provider.getProvider() != null) {
        jsonObs.put("provider", provider.getProvider().getName());
      }
    }

    SearchAPI searchAPI = SearchAPI.getInstance();
    if (!searchAPI.getSearchPhrase().getPhrase().equals("")
        && !searchAPI.getSearchPhrase().getPhrase().equals("*")) {
      for (ChartListItem item : searchAPI.getResults()) {
        if (item != null && item instanceof ObsItem && ((ObsItem) item).getObsId() != null) {
          if (((ObsItem) item).getObsId() == obs.getObsId()) {
            jsonObs.put("chosen", "true");
          }
        }
      }
    }

    return jsonObs;
  }
 Obs getLatestVlOrder(List<Obs> lstObs) {
   Obs latestObs = null;
   for (Obs o : lstObs) {
     if (o.getValueCoded() == Dictionary.getConcept(Dictionary.HIV_VIRAL_LOAD)) {
       if (latestObs == null) {
         latestObs = o;
       } else {
         if (o.getObsDatetime().after(latestObs.getObsDatetime())) {
           latestObs = o;
         }
       }
     }
   }
   return latestObs;
 }
Exemplo n.º 3
0
  /**
   * Builds a coded result from an observation
   *
   * @param obs
   */
  public Result(Obs obs) {
    this(
        obs.getObsDatetime(),
        null,
        obs.getValueAsBoolean(),
        obs.getValueCoded(),
        obs.getValueDatetime(),
        obs.getValueNumeric(),
        obs.getValueText(),
        obs);

    Concept concept = obs.getConcept();
    ConceptDatatype conceptDatatype = null;

    if (concept != null) {
      conceptDatatype = concept.getDatatype();

      if (conceptDatatype == null) {
        return;
      }
      if (conceptDatatype.isCoded()) {
        this.datatype = Datatype.CODED;
      } else if (conceptDatatype.isNumeric()) {
        this.datatype = Datatype.NUMERIC;
      } else if (conceptDatatype.isDate()) {
        this.datatype = Datatype.DATETIME;
      } else if (conceptDatatype.isText()) {
        this.datatype = Datatype.TEXT;
      } else if (conceptDatatype.isBoolean()) {
        this.datatype = Datatype.BOOLEAN;
      }
    }
  }
  /**
   * @see
   *     org.openmrs.module.htmlformentry.element.HtmlGeneratorElement#generateHtml(org.openmrs.module.htmlformentry.FormEntryContext)
   */
  @Override
  public String generateHtml(FormEntryContext context) {
    if (context.getExistingPatient() == null) {
      return "";
    }

    KenyaUiUtils kenyaui = Context.getRegisteredComponents(KenyaUiUtils.class).get(0);

    PatientWrapper patient = new PatientWrapper(context.getExistingPatient());

    Obs obs = patient.lastObs(MetadataUtils.getConcept(conceptId));

    StringBuilder sb = new StringBuilder("<span>");

    if (obs != null) {
      sb.append(kenyaui.formatObsValue(obs));

      if (showDate) {
        sb.append(" <small>(" + kenyaui.formatDate(obs.getObsDatetime()) + ")</small>");
      }
    } else if (noneMessage != null) {
      sb.append(noneMessage);
    }

    sb.append("</span>");
    return sb.toString();
  }
 private void addToObsGroup(Obs obsGroup, Obs member) {
   member.setPerson(obsGroup.getPerson());
   member.setObsDatetime(obsGroup.getObsDatetime());
   member.setLocation(obsGroup.getLocation());
   member.setEncounter(obsGroup.getEncounter());
   obsGroup.addGroupMember(member);
 }
Exemplo n.º 6
0
  /** @see Encounter#addObs(Obs) */
  @Test
  @Verifies(
      value = "should add encounter attrs to obs if attributes are null",
      method = "addObs(Obs)")
  public void addObs_shouldAddEncounterAttrsToObsIfAttributesAreNull() throws Exception {
    /// an encounter that will hav the date/location/patient on it
    Encounter encounter = new Encounter();

    Date date = new Date();
    encounter.setEncounterDatetime(date);

    Location location = new Location(1);
    encounter.setLocation(location);

    Patient patient = new Patient(1);
    encounter.setPatient(patient);

    // add an obs that doesn't have date/location/patient set on it.
    Obs obs = new Obs(123);
    encounter.addObs(obs);

    // make sure it was added
    assertEquals(1, encounter.getAllObs(true).size());

    // check the values of the obs attrs to see if they were added
    assertTrue(obs.getObsDatetime().equals(date));
    assertTrue(obs.getLocation().equals(location));
    assertTrue(obs.getPerson().equals(patient));
  }
 public ObsBuilder addMember(Concept question, String valueText) {
   Obs child = new Obs();
   child.setPerson(obs.getPerson());
   child.setObsDatetime(obs.getObsDatetime());
   child.setConcept(question);
   child.setValueText(valueText);
   obs.addGroupMember(child);
   return this;
 }
  public QueueItem saveQueueItem(QueueItem queueItem) {
    log.debug("saveQueueItem(). Entering");
    boolean isNew = false;
    Date newDate = queueItem.getEncounter().getEncounterDatetime();
    log.debug("Encounter date: " + newDate);
    Date originalDate = null;

    if (queueItem.getQueueItemId() == null) {
      isNew = true;
      log.debug("Got a  new queue item");
    }

    // Not new we update some of the Encounter info
    if (!isNew) {
      log.info("Updating previously queued encounter!");
      Encounter encounter = queueItem.getEncounter();
      Patient p = encounter.getPatient();
      originalDate = encounter.getEncounterDatetime();
      if (OpenmrsUtil.compare(originalDate, newDate) != 0) {

        // if the obs datetime is the same as the
        // original encounter datetime, fix it
        if (OpenmrsUtil.compare(queueItem.getDateCreated(), originalDate) == 0) {
          encounter.setEncounterDatetime(newDate);
        }
      }

      // if the Person in the encounter doesn't match the Patient in the ,
      // fix it
      if (!encounter.getPatient().getPersonId().equals(p.getPatientId())) {
        encounter.setPatient(p);
      }

      for (Obs obs : encounter.getAllObs(true)) {
        // if the date was changed
        if (OpenmrsUtil.compare(originalDate, newDate) != 0) {

          // if the obs datetime is the same as the
          // original encounter datetime, fix it
          if (OpenmrsUtil.compare(obs.getObsDatetime(), originalDate) == 0) {
            obs.setObsDatetime(newDate);
          }
        }

        // if the Person in the obs doesn't match the Patient in the
        // encounter, fix it
        if (!obs.getPerson().getPersonId().equals(p.getPatientId())) {
          obs.setPerson(p);
        }
      }
    }
    log.debug("Saving queu item.");
    dao.saveQueueItem(queueItem);
    return queueItem;
  }
Exemplo n.º 9
0
  /** @see Encounter#addObs(Obs) */
  @Test
  @Verifies(
      value = "should add encounter attrs to obs if attributes are null",
      method = "addObs(Obs)")
  public void addObs_shouldAddEncounterAttrsToObsGroupMembersIfAttributesAreNull()
      throws Exception {
    /// an encounter that will hav the date/location/patient on it
    Encounter encounter = new Encounter();

    Date date = new Date();
    encounter.setEncounterDatetime(date);

    Location location = new Location(1);
    encounter.setLocation(location);

    Patient patient = new Patient(1);
    encounter.setPatient(patient);

    // add an obs that doesn't have date/location/patient set on it.
    Obs obs = new Obs(123);
    Obs childObs = new Obs(456);
    obs.addGroupMember(childObs);

    // check for infinite recursion
    // childObs-->childObs2   and childObs2-->childObs
    Obs childObs2 = new Obs(456);
    childObs.addGroupMember(childObs2);
    childObs2.addGroupMember(childObs);

    assertTrue(obs.getGroupMembers() != null && obs.getGroupMembers().size() == 1);

    encounter.addObs(obs);

    // check the values of the obs attrs to see if they were added
    assertTrue(childObs.getObsDatetime().equals(date));
    assertTrue(childObs.getLocation().equals(location));
    assertTrue(childObs.getPerson().equals(patient));
    assertTrue(childObs2.getObsDatetime().equals(date));
    assertTrue(childObs2.getLocation().equals(location));
    assertTrue(childObs2.getPerson().equals(patient));
  }
  /**
   * Convenience method to obtain the patient's (maximum) age in months.
   *
   * @return The patient's age in months at the time the given observations were taken.
   */
  protected int calculateAgeInMonths(Obs... observations) {
    long dateTaken = Long.MIN_VALUE;

    if (observations != null) {
      for (Obs obs : observations) {
        if (obs != null && obs.getObsDatetime() != null) {
          // determine the date the observation was taken (take the greater of the two)
          dateTaken = Math.max(dateTaken, obs.getObsDatetime().getTime());
        }
      }
    }

    if (dateTaken == Long.MIN_VALUE || dateTaken < birthdate.getTime()) {
      // unable to calculate patient's age!
      return 0;
    }

    // calculate how old this person was, in months, when the observations were taken
    final Period period = new Interval(birthdate.getTime(), dateTaken).toPeriod();
    final int ageInMonths = period.getYears() * 12 + period.getMonths();

    // return the patient's age in months
    return ageInMonths;
  }
  @Test
  public void shouldAddDiagnosesAdObservation() throws Exception {
    executeDataSet("baseMetaData.xml");
    executeDataSet("diagnosisMetaData.xml");
    executeDataSet("shouldAddDiagnosisAsObservation.xml");
    String cancerDiagnosisUuid = "d102c80f-1yz9-4da3-bb88-8122ce8868dh";
    String encounterDateTime = "2005-01-02T00:00:00.000+0000";
    String diagnosisDateTime = "2005-01-02T01:00:00.000+0000";
    String postData =
        "{"
            + "\"patientUuid\" : \"a76e8d23-0c38-408c-b2a8-ea5540f01b51\", "
            + "\"visitTypeUuid\" : \"b45ca846-c79a-11e2-b0c0-8e397087571c\", "
            + "\"encounterTypeUuid\": \"2b377dba-62c3-4e53-91ef-b51c68899891\", "
            + "\"encounterDateTime\" : \""
            + encounterDateTime
            + "\", "
            + "\"diagnoses\":["
            + "{\"order\":\"PRIMARY\", \"certainty\": \"CONFIRMED\", \"codedAnswer\": { \"uuid\": \""
            + cancerDiagnosisUuid
            + "\"}, \"diagnosisDateTime\": \""
            + diagnosisDateTime
            + "\" }"
            + "]"
            + "}";

    EncounterTransaction response =
        deserialize(
            handle(newPostRequest("/rest/emrapi/encounter", postData)), EncounterTransaction.class);

    Visit visit = visitService.getVisitByUuid(response.getVisitUuid());
    Encounter encounter = visit.getEncounters().iterator().next();

    Set<Obs> obsAtTopLevel = encounter.getObsAtTopLevel(false);
    assertEquals(1, obsAtTopLevel.size());
    Obs parentObservation = obsAtTopLevel.iterator().next();
    assertTrue(parentObservation.isObsGrouping());
    assertEquals(
        DateUtils.parseDate(diagnosisDateTime, dateTimeFormat), parentObservation.getObsDatetime());

    Set<Obs> diagnosisObservationGroupMembers = parentObservation.getGroupMembers();
    assertEquals(3, diagnosisObservationGroupMembers.size());
    ArrayList<String> valueCodedNames = getValuCodedNames(diagnosisObservationGroupMembers);
    assertTrue(valueCodedNames.contains("Confirmed"));
    assertTrue(valueCodedNames.contains("Primary"));
    assertTrue(valueCodedNames.contains("Cancer"));
  }
  @Test
  public void shouldUseVisitStartTimeAsEncounterDateTimeForPreviousVisits() throws Exception {
    Date visitStartDate = getDateFromString("2010-09-22 00:00:00");

    List<Document> documents = new ArrayList<>();
    documents.add(
        new Document(
            "/radiology/foo-lalala.jpg",
            null,
            "3f596de5-5caa-11e3-a4c0-0800271c1b75",
            null,
            null,
            false));

    VisitDocumentRequest visitDocumentRequest =
        new VisitDocumentRequest(
            patientUUID,
            firstVisitUuid,
            visitTypeUUID,
            null,
            null,
            firstEncounterTypeUUID,
            null,
            documents,
            secondProviderUuid,
            null,
            null);
    executeDataSet("visitDocumentData.xml");

    //        Date currentDate = new Date(System.currentTimeMillis() - 1000);
    visitDocumentService.upload(visitDocumentRequest);
    Context.flushSession();
    Context.clearSession();

    Visit visit = visitService.getVisit(1);
    Set<Encounter> encounters = visit.getEncounters();
    Encounter encounter = getEncounterByTypeUuid(encounters, firstEncounterTypeUUID);
    boolean condition = encounter.getEncounterDatetime().compareTo(visitStartDate) >= 0;
    assertTrue(condition);

    Set<Obs> allObs = encounter.getAllObs();
    Obs savedDocument = getSavedDocument(allObs, "3f596de5-5caa-11e3-a4c0-0800271c1b75");
    assertTrue(savedDocument.getObsDatetime().compareTo(visitStartDate) == 0);
  }
Exemplo n.º 13
0
 /** @see java.util.Iterator#next() */
 public Map<String, Object> next() {
   Locale locale = Context.getLocale();
   Obs obs = iter.next();
   Map<String, Object> ret = new HashMap<String, Object>();
   ret.put("patientId", obs.getPersonId());
   ret.put("question", obs.getConcept().getName(locale, false));
   ret.put("questionConceptId", obs.getConcept().getConceptId());
   ret.put("answer", obs.getValueAsString(locale));
   if (obs.getValueCoded() != null) {
     ret.put("answerConceptId", obs.getValueCoded());
   }
   ret.put("obsDatetime", obs.getObsDatetime());
   if (obs.getEncounter() != null) {
     ret.put("encounterId", obs.getEncounter().getEncounterId());
   }
   if (obs.getObsGroup() != null) {
     ret.put("obsGroupId", obs.getObsGroup().getObsId());
   }
   return ret;
 }
Exemplo n.º 14
0
  /**
   * This is an equivalent to a copy constructor. Creates a new copy of the given <code>obsToCopy
   * </code> with a null obs id
   *
   * @param obsToCopy The Obs that is going to be copied
   * @return a new Obs object with all the same attributes as the given obs
   */
  public static Obs newInstance(Obs obsToCopy) {
    Obs newObs =
        new Obs(
            obsToCopy.getPerson(),
            obsToCopy.getConcept(),
            obsToCopy.getObsDatetime(),
            obsToCopy.getLocation());

    newObs.setObsGroup(obsToCopy.getObsGroup());
    newObs.setAccessionNumber(obsToCopy.getAccessionNumber());
    newObs.setValueCoded(obsToCopy.getValueCoded());
    newObs.setValueDrug(obsToCopy.getValueDrug());
    newObs.setValueGroupId(obsToCopy.getValueGroupId());
    newObs.setValueDatetime(obsToCopy.getValueDatetime());
    newObs.setValueNumeric(obsToCopy.getValueNumeric());
    newObs.setValueModifier(obsToCopy.getValueModifier());
    newObs.setValueText(obsToCopy.getValueText());
    newObs.setComment(obsToCopy.getComment());
    newObs.setOrder(obsToCopy.getOrder());
    newObs.setEncounter(obsToCopy.getEncounter());
    newObs.setDateStarted(obsToCopy.getDateStarted());
    newObs.setDateStopped(obsToCopy.getDateStopped());
    newObs.setCreator(obsToCopy.getCreator());
    newObs.setDateCreated(obsToCopy.getDateCreated());
    newObs.setVoided(obsToCopy.getVoided());
    newObs.setVoidedBy(obsToCopy.getVoidedBy());
    newObs.setDateVoided(obsToCopy.getDateVoided());
    newObs.setVoidReason(obsToCopy.getVoidReason());

    newObs.setValueComplex(obsToCopy.getValueComplex());
    newObs.setComplexData(obsToCopy.getComplexData());

    if (obsToCopy.getGroupMembers() != null)
      for (Obs member : obsToCopy.getGroupMembers()) {
        // if the obs hasn't been saved yet, no need to duplicate it
        if (member.getObsId() == null) newObs.addGroupMember(member);
        else newObs.addGroupMember(Obs.newInstance(member));
      }

    return newObs;
  }
  @Test
  public void shouldAddNewObservationGroup() throws Exception {
    executeDataSet("shouldAddNewObservation.xml");
    String encounterDateTime = "2005-01-02T00:00:00.000+0000";
    String observationTime = "2005-01-02T12:00:00.000+0000";
    String json =
        "{ \"patientUuid\" : \"a76e8d23-0c38-408c-b2a8-ea5540f01b51\", "
            + "\"visitTypeUuid\" : \"b45ca846-c79a-11e2-b0c0-8e397087571c\", "
            + "\"encounterTypeUuid\": \"2b377dba-62c3-4e53-91ef-b51c68899890\", "
            + "\"encounterDateTime\" : \""
            + encounterDateTime
            + "\", "
            + "\"observations\":["
            + "{\"concept\":{\"uuid\": \"e102c80f-1yz9-4da3-bb88-8122ce8868dd\"}, "
            + " \"groupMembers\" : [{\"concept\":{\"uuid\": \"d102c80f-1yz9-4da3-bb88-8122ce8868dd\"}, \"value\":20, \"comment\":\"overweight\", \"observationDateTime\": \""
            + observationTime
            + "\"}] }"
            + "]}";

    EncounterTransaction response =
        deserialize(
            handle(newPostRequest("/rest/emrapi/encounter", json)), EncounterTransaction.class);

    Visit visit = visitService.getVisitByUuid(response.getVisitUuid());
    Encounter encounter = (Encounter) visit.getEncounters().toArray()[0];

    assertEquals(1, encounter.getObs().size());
    Obs obs = (Obs) encounter.getAllObs().toArray()[0];
    assertEquals("e102c80f-1yz9-4da3-bb88-8122ce8868dd", obs.getConcept().getUuid());

    assertEquals(1, obs.getGroupMembers().size());
    Obs member = obs.getGroupMembers().iterator().next();
    assertEquals("d102c80f-1yz9-4da3-bb88-8122ce8868dd", member.getConcept().getUuid());
    assertEquals(new Double(20.0), member.getValueNumeric());
    assertEquals("a76e8d23-0c38-408c-b2a8-ea5540f01b51", member.getPerson().getUuid());
    assertEquals("f13d6fae-baa9-4553-955d-920098bec08f", member.getEncounter().getUuid());
    assertEquals("overweight", member.getComment());
    assertEquals(
        new SimpleDateFormat(dateTimeFormat).parse(observationTime), member.getObsDatetime());
  }
  /**
   * Convenience method to obtain the patient's (maximum) age in days.
   *
   * @return The patient's age in weeks at the time the given observations were taken.
   */
  protected int calculateAgeInDays(Obs... observations) {
    long dateTaken = Long.MIN_VALUE;

    if (observations != null) {
      for (Obs obs : observations) {
        // determine the date the observation was taken (take the greater of the two)
        dateTaken = Math.max(dateTaken, obs.getObsDatetime().getTime());
      }
    }

    if (dateTaken == Long.MIN_VALUE || dateTaken < birthdate.getTime()) {
      // unable to calculate patient's age!
      return 0;
    }

    // calculate how old this person was, in months, when the observations were taken
    final Duration duration = new Interval(birthdate.getTime(), dateTaken).toDuration();
    final int ageInDays = (int) (duration.getStandardDays());

    // return the patient's age in weeks
    return ageInDays;
  }
  @Test
  public void shouldUseNewDateAsEncounterDateTimeForActiveVisits() throws Exception {
    Date visitStartDate = getDateFromString("2014-06-22 00:00:00");
    Date encounterDate = getDateFromString("2014-06-23 00:00:00");
    Date obsDate = getDateFromString("2014-06-24 00:10:00");

    List<Document> documents = new ArrayList<>();
    documents.add(new Document("/radiology/fooo-bar.jpg", null, conceptUuid, null, obsDate, false));

    visitDocumentRequest =
        new VisitDocumentRequest(
            patientUUID,
            secondVisitUuid,
            visitTypeUUID,
            visitStartDate,
            null,
            secondEncounterTypeUUID,
            encounterDate,
            documents,
            firstProviderUuid,
            null,
            null);

    Date currentDate = new Date(System.currentTimeMillis() - 1000);
    visitDocumentService.upload(visitDocumentRequest);
    Context.flushSession();
    Context.clearSession();

    Visit visit = visitService.getVisit(2);
    Set<Encounter> encounters = visit.getEncounters();
    Encounter encounter = getEncounterByTypeUuid(encounters, secondEncounterTypeUUID);
    boolean condition = encounter.getEncounterDatetime().compareTo(currentDate) >= 0;
    assertTrue(condition);

    Set<Obs> allObs = encounter.getAllObs();
    Obs savedDocument = getSavedDocument(allObs, conceptUuid);
    assertTrue(savedDocument.getObsDatetime().compareTo(currentDate) >= 0);
  }
  @Override
  public CalculationResultMap evaluate(
      Collection<Integer> cohort,
      Map<String, Object> parameterValues,
      PatientCalculationContext context) {
    Program hivProgram = MetadataUtils.existing(Program.class, HivMetadata._Program.HIV);

    Set<Integer> alive = Filters.alive(cohort, context);
    Set<Integer> inHivProgram = Filters.inProgram(hivProgram, alive, context);

    Set<Integer> aliveAndFemale = Filters.female(Filters.alive(cohort, context), context);

    CalculationResultMap ret = new CalculationResultMap();

    // need to exclude those on ART already
    Set<Integer> onArt =
        CalculationUtils.patientsThatPass(calculate(new OnArtCalculation(), cohort, context));
    // find the observation for viral load recorded
    CalculationResultMap viralLoad =
        Calculations.lastObs(Dictionary.getConcept(Dictionary.HIV_VIRAL_LOAD), cohort, context);
    // get a list of all the viral load
    CalculationResultMap viralLoadList =
        Calculations.allObs(Dictionary.getConcept(Dictionary.HIV_VIRAL_LOAD), cohort, context);
    // check for non detectables
    CalculationResultMap ldlViralLoad =
        Calculations.allObs(
            Dictionary.getConcept(Dictionary.HIV_VIRAL_LOAD_QUALITATIVE), cohort, context);

    // check for test orders
    CalculationResultMap testOrders =
        Calculations.allObs(Dictionary.getConcept(Dictionary.TESTS_ORDERED), cohort, context);

    // check for last ldl
    CalculationResultMap ldlLast =
        Calculations.lastObs(
            Dictionary.getConcept(Dictionary.HIV_VIRAL_LOAD_QUALITATIVE), cohort, context);

    // find for prgnant females

    CalculationResultMap pregStatusObss =
        Calculations.lastObs(
            Dictionary.getConcept(Dictionary.PREGNANCY_STATUS), aliveAndFemale, context);

    // get the initial art start date
    CalculationResultMap artStartDate =
        calculate(new InitialArtStartDateCalculation(), cohort, context);

    for (Integer ptId : cohort) {
      boolean needsViralLoadTest = false;
      Obs viralLoadObs = EmrCalculationUtils.obsResultForPatient(viralLoad, ptId);
      Date dateInitiated = EmrCalculationUtils.datetimeResultForPatient(artStartDate, ptId);
      ListResult listResult = (ListResult) viralLoadList.get(ptId);
      ListResult testOrdersList = (ListResult) testOrders.get(ptId);
      List<Obs> testObsList = CalculationUtils.extractResultValues(testOrdersList);
      List<Obs> listObsViralLoads = CalculationUtils.extractResultValues(listResult);
      ListResult ldlList = (ListResult) ldlViralLoad.get(ptId);
      List<List> listLdl = CalculationUtils.extractResultValues(ldlList);
      Obs lastLdlObs = EmrCalculationUtils.obsResultForPatient(ldlLast, ptId);
      // find pregnancy obs
      Obs pregnantEdd = EmrCalculationUtils.obsResultForPatient(pregStatusObss, ptId);

      // Find latest viral load test order
      Obs lastVlTestOrder = getLatestVlOrder(testObsList);

      if (inHivProgram.contains(ptId) && onArt.contains(ptId)) {
        if (listObsViralLoads.size() == 0
            && listLdl.size() == 0
            && dateInitiated != null
            && (daysSince(dateInitiated, context) >= 180)) {
          needsViralLoadTest = true;
        }
        // need to check here if patient has had any viral load
        /*if(dateInitiated != null && (daysSince(dateInitiated, context) >= 360)) {
            needsViralLoadTest = true;
        }*/

        // those continuing should receive one VL every year
        // pick the date of the last viral load numeric values
        if (viralLoadObs != null && (daysSince(viralLoadObs.getObsDatetime(), context) >= 360)) {
          needsViralLoadTest = true;
        }
        // pick the date of the ldl
        if (lastLdlObs != null && (daysSince(lastLdlObs.getObsDatetime(), context) >= 360)) {
          needsViralLoadTest = true;
        }

        // if vl more than
        if (viralLoadObs != null
            && viralLoadObs.getValueNumeric() > 1000
            && (daysSince(viralLoadObs.getObsDatetime(), context) > 90)) {
          needsViralLoadTest = true;

          if (lastLdlObs != null && (daysSince(lastLdlObs.getObsDatetime(), context) < 360)) {
            needsViralLoadTest = false;
          }
        }

        // check for pregnancy
        if (pregnantEdd != null
            && pregnantEdd.getValueCoded().equals(Dictionary.getConcept(Dictionary.YES))
            && dateInitiated != null) {
          Date whenVLWillBeDue =
              DateUtil.adjustDate(
                  DateUtil.adjustDate(dateInitiated, 6, DurationUnit.MONTHS),
                  -1,
                  DurationUnit.DAYS);
          // if last vl is 6 months older then the patient is due for vl
          if (viralLoadObs == null && lastLdlObs == null) {
            needsViralLoadTest = true;
          }
          if (viralLoadObs == null
              && lastLdlObs == null
              && (context.getNow().after(whenVLWillBeDue))) {
            needsViralLoadTest = true;
          }
          if (viralLoadObs != null
              && viralLoadObs.getValueNumeric() > 1000
              && (monthsBetween(viralLoadObs.getObsDatetime(), context.getNow()) >= 3)) {
            needsViralLoadTest = true;
            if (lastLdlObs != null && (daysSince(lastLdlObs.getObsDatetime(), context) < 360)) {
              needsViralLoadTest = false;
            }
          }
          if (viralLoadObs != null && daysSince(viralLoadObs.getObsDatetime(), context) >= 180) {
            needsViralLoadTest = true;
          }
          if (lastLdlObs != null && daysSince(lastLdlObs.getObsDatetime(), context) >= 180) {
            needsViralLoadTest = true;
          }
        }

        // check if has vl test order within 6 months
        if (lastVlTestOrder != null
            && daysSince(lastVlTestOrder.getObsDatetime(), context) >= 180) {
          needsViralLoadTest = true;
        }

        if (lastVlTestOrder != null && daysSince(lastVlTestOrder.getObsDatetime(), context) < 180) {
          needsViralLoadTest = false;
        }
      }

      ret.put(ptId, new BooleanResult(needsViralLoadTest, this));
    }
    return ret;
  }
  public PatientDataResult calculateResult(
      List<PatientDataResult> results, EvaluationContext context) {

    PatientAttributeResult alert = new PatientAttributeResult(null, null);

    ProgramWorkflowState state = (ProgramWorkflowState) context.getParameterValue("state");

    StringBuffer alerts = new StringBuffer();

    double height = 0;
    double weight = 0;

    for (PatientDataResult result : results) {

      if (result.getName().equals("CD4Test")) {
        AllObservationValuesResult cd4 = (AllObservationValuesResult) result;

        if (cd4.getValue() != null) {
          int decline = calculateDecline(cd4.getValue());

          if (decline > 50
              && (state.toString().contains("GROUP") || state.toString().contains("FOLLOWING"))) {
            alerts.append("CD4 decline(");
            alerts.append(decline);
            alerts.append(").\n");
          }

          Obs lastCd4 = null;

          if (cd4.getValue().size() > 0) {
            lastCd4 = cd4.getValue().get(cd4.getValue().size() - 1);
          }

          if (lastCd4 == null) {
            alerts.append("No CD4 recorded.\n");
          } else {
            Date dateCd4 = lastCd4.getObsDatetime();
            Date date = Calendar.getInstance().getTime();

            int diff = calculateMonthsDifference(date, dateCd4);

            if (diff > 12) {
              alerts.append("Very late CD4(" + diff + " months ago).\n");
            } else if ((diff > 6) && state.toString().contains("FOLLOWING")) {
              alerts.append("Late CD4(" + diff + " months ago).\n");
            }

            if (state.toString().contains("FOLLOWING")
                && lastCd4.getValueNumeric() != null
                && lastCd4.getValueNumeric() < 500) {
              alerts.append("Eligible for Treatment.\n");
            }
          }
        }
      }
      if (result.getName().equals("viralLoadTest")) {
        AllObservationValuesResult viraload = (AllObservationValuesResult) result;

        if (viraload.getValue() != null) {
          Obs lastviraload = null;

          if (viraload.getValue().size() > 0) {
            lastviraload = viraload.getValue().get(viraload.getValue().size() - 1);
          }

          if (state.toString().contains("GROUP") && (lastviraload == null)) {
            alerts.append("No VL recorded.\n");
          } else {
            try {
              Date dateVl = lastviraload.getObsDatetime();
              Date date = Calendar.getInstance().getTime();

              int diff = calculateMonthsDifference(date, dateVl);

              if (state.toString().contains("GROUP")) {
                if (diff > 12) {
                  alerts.append("Late VL(" + diff + " months ago).\n");
                }

                if (lastviraload.getValueNumeric() != null
                    && lastviraload.getValueNumeric() > 1000) {
                  alerts.append("VL Failure " + lastviraload.getValueNumeric() + ".\n");
                }
              }
            } catch (Exception e) {
            }
          }
        }
      }
      if (result.getName().equals("weightObs")) {
        AllObservationValuesResult wt = (AllObservationValuesResult) result;

        if (wt.getValue() != null) {
          int decline = calculatePercentageDecline(wt.getValue());

          if (decline > 5) {
            alerts.append("WT decline(");
            alerts.append(decline);
            alerts.append("%, ");
            int kilosLost = calculateDecline(wt.getValue());
            alerts.append(kilosLost);
            alerts.append("kg)\n");
          }

          if (wt.getValue().size() > 0) {
            weight = wt.getValue().get(wt.getValue().size() - 1).getValueNumeric();
          }
        }

        if (wt.getValue() == null || wt.getValue().size() == 0) {
          alerts.append("No weight recorded.\n");
        }
      }

      if (result.getName().equals("RecentHeight")) {
        ObservationResult heightOb = (ObservationResult) result;

        if (heightOb.getValue() == null || heightOb.getValue().trim().length() == 0) {
          alerts.append("No height recorded.\n");
        } else {
          height = Double.parseDouble(heightOb.getValue());
        }
      }

      if (result.getName().equals("lastEncInMonth")) {
        DateValueResult encinmonths = (DateValueResult) result;
        if (encinmonths.getValue() != null) {
          Date dateVl = encinmonths.getDateOfObservation();
          Date date = Calendar.getInstance().getTime();
          int diff = calculateMonthsDifference(date, dateVl);
          if (diff > 12) {
            alerts.append("LTFU determine status.\n");
          }
        }
      }

      if (result.getName().equals("IO") && result.getValue() != null) {
        alerts.append("OI reported last visit: " + result.getValue() + "\n");
      }

      if (result.getName().equals("SideEffects") && result.getValue() != null) {
        alerts.append("Side effects reported last visit: " + result.getValue() + "\n");
      }
    }

    if (height > 0 && weight > 0) {
      double bmi = weight / (height / 100 * height / 100);
      int decimalPlace = 1;
      BigDecimal bd = new BigDecimal(Double.toString(bmi));
      bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);

      if (bmi < 16) {
        alerts.append("Very low BMI (" + bd.doubleValue() + ").\n");
      } else if (bmi < 18.5) {
        alerts.append("Low BMI (" + bd.doubleValue() + ").\n");
      }
    }

    alert.setValue(alerts.toString().trim());
    return alert;
  }
  /**
   * @see EligibleForArtTriggerCalculation#evaluate(java.util.Collection, java.util.Map,
   *     org.openmrs.calculation.patient.PatientCalculationContext)
   * @verifies calculate the obs which triggered a patient to become eligible for ART
   * @verifies return null for patients who have never been eligible for ART
   */
  @Test
  public void evaluate_shouldCalculateEligibilityTrigger() throws Exception {

    PatientService ps = Context.getPatientService();

    // Confirm patient #6 HIV+ when they're 1 year old and give them very low CD4 soon after
    TestUtils.saveObs(
        ps.getPatient(6),
        Dictionary.getConcept(Dictionary.DATE_OF_HIV_DIAGNOSIS),
        TestUtils.date(2008, 05, 27),
        TestUtils.date(2010, 1, 1));
    TestUtils.saveObs(
        ps.getPatient(6),
        Dictionary.getConcept(Dictionary.CD4_COUNT),
        300.0,
        TestUtils.date(2009, 1, 1));

    // Give patient #7 low CD4 when they're 3 years old and very low CD4 after
    TestUtils.saveObs(
        ps.getPatient(7),
        Dictionary.getConcept(Dictionary.CD4_COUNT),
        900.0,
        TestUtils.date(1979, 8, 25));
    TestUtils.saveObs(
        ps.getPatient(7),
        Dictionary.getConcept(Dictionary.CD4_COUNT),
        300.0,
        TestUtils.date(2009, 1, 1));

    // Give patient #8 WHO stage of 3
    TestUtils.saveObs(
        ps.getPatient(8),
        Dictionary.getConcept(Dictionary.CURRENT_WHO_STAGE),
        Dictionary.getConcept(Dictionary.WHO_STAGE_3_PEDS),
        TestUtils.date(2009, 1, 1));

    Context.flushSession();

    List<Integer> cohort = Arrays.asList(6, 7, 8, 999);

    CalculationResultMap resultMap =
        new EligibleForArtTriggerCalculation()
            .evaluate(
                cohort,
                null,
                Context.getService(PatientCalculationService.class).createCalculationContext());

    Obs patient6Trigger = (Obs) resultMap.get(6).getValue(); // Eligible through HIV confirmation
    Assert.assertEquals(Dictionary.DATE_OF_HIV_DIAGNOSIS, patient6Trigger.getConcept().getUuid());
    Assert.assertEquals(TestUtils.date(2008, 05, 27), patient6Trigger.getValueDate());

    Obs patient7Trigger = (Obs) resultMap.get(7).getValue(); // Eligible through CD4 count
    Assert.assertEquals(Dictionary.CD4_COUNT, patient7Trigger.getConcept().getUuid());
    Assert.assertEquals(TestUtils.date(1979, 8, 25), patient7Trigger.getObsDatetime());

    Obs patient8Trigger = (Obs) resultMap.get(8).getValue(); // Eligible through WHO stage
    Assert.assertEquals(Dictionary.CURRENT_WHO_STAGE, patient8Trigger.getConcept().getUuid());
    Assert.assertEquals(TestUtils.date(2009, 1, 1), patient8Trigger.getObsDatetime());

    Assert.assertNull(resultMap.get(999)); // Was never eligible for ART
  }
  /**
   * Adds the column headers and column data to the DataSet
   *
   * @param dataSet
   * @param encounters
   * @param patientIdentifierTypes
   * @param optionalColumns
   * @param columnDisplayFormat
   * @param maxColumnHeaderWidth
   * @param allColumns
   * @param fieldMap
   * @return
   */
  public DataSet addData(
      SimpleDataSet dataSet,
      List<Encounter> encounters,
      List<PatientIdentifierType> patientIdentifierTypes,
      List<EncounterAndObsDataSetDefinition.ObsOptionalColumn> optionalColumns,
      List<EncounterAndObsDataSetDefinition.ColumnDisplayFormat> columnDisplayFormat,
      Integer maxColumnHeaderWidth,
      Set<ObsColumnDescriptor> allColumns,
      Map<Encounter, Map<ObsColumnDescriptor, Obs>> fieldMap) {
    for (Encounter encounter : encounters) {

      DataSetRow row = new DataSetRow();

      List<String> providerNames = new ArrayList<String>();
      for (EncounterProvider ep : encounter.getEncounterProviders()) {
        providerNames.add(ep.getProvider().getName());
      }

      // Add the standard columns for encounters
      DataSetColumn c1 =
          new DataSetColumn(
              ObjectUtil.trimStringIfNeeded("ENCOUNTER_ID", maxColumnHeaderWidth),
              ObjectUtil.trimStringIfNeeded("ENCOUNTER_ID", maxColumnHeaderWidth),
              Integer.class);
      row.addColumnValue(c1, encounter.getEncounterId());
      DataSetColumn c2 =
          new DataSetColumn(
              ObjectUtil.trimStringIfNeeded("ENCOUNTER_DATETIME", maxColumnHeaderWidth),
              ObjectUtil.trimStringIfNeeded("ENCOUNTER_DATETIME", maxColumnHeaderWidth),
              String.class);
      row.addColumnValue(c2, encounter.getEncounterDatetime().toString());
      DataSetColumn c3 =
          new DataSetColumn(
              ObjectUtil.trimStringIfNeeded("LOCATION", maxColumnHeaderWidth),
              ObjectUtil.trimStringIfNeeded("LOCATION", maxColumnHeaderWidth),
              String.class);
      row.addColumnValue(
          c3, (encounter.getLocation() != null) ? encounter.getLocation().getName() : EMPTY);
      DataSetColumn c4 =
          new DataSetColumn(
              ObjectUtil.trimStringIfNeeded("PROVIDER", maxColumnHeaderWidth),
              ObjectUtil.trimStringIfNeeded("PROVIDER", maxColumnHeaderWidth),
              String.class);
      row.addColumnValue(c4, OpenmrsUtil.join(providerNames, ", "));
      DataSetColumn c5 =
          new DataSetColumn(
              ObjectUtil.trimStringIfNeeded("INTERNAL_PATIENT_ID", maxColumnHeaderWidth),
              ObjectUtil.trimStringIfNeeded("INTERNAL_PATIENT_ID", maxColumnHeaderWidth),
              Integer.class);
      row.addColumnValue(
          c5, encounter.getPatient() != null ? encounter.getPatient().getPatientId() : EMPTY);

      if (patientIdentifierTypes != null) {
        for (PatientIdentifierType pit : patientIdentifierTypes) {
          List<PatientIdentifier> patientIdentifiers =
              encounter.getPatient().getPatientIdentifiers(pit);

          StringBuffer sbPatientIdentifiers = new StringBuffer();
          int count = 0;
          for (PatientIdentifier patientIdentifier : patientIdentifiers) {
            if (count > 0) {
              sbPatientIdentifiers.append(", ");
            }
            sbPatientIdentifiers.append(patientIdentifier.toString());
            count++;
          }

          DataSetColumn c6 =
              new DataSetColumn(
                  pit.getName(),
                  ObjectUtil.trimStringIfNeeded(pit.getName(), maxColumnHeaderWidth),
                  String.class);
          row.addColumnValue(c6, sbPatientIdentifiers.toString());
        }
      }

      Map<ObsColumnDescriptor, Obs> obsInEncounter = fieldMap.get(encounter);

      // Look up all obs for a given encounter based on column headers for all encounters
      for (ObsColumnDescriptor columnKey : allColumns) {

        Obs obs = obsInEncounter.get(columnKey);
        String columnName = columnKey.format(columnDisplayFormat, maxColumnHeaderWidth);
        DataSetColumn obsDsc = new DataSetColumn(columnName, columnName, String.class);

        StringBuffer columnValue = new StringBuffer();
        if (obs != null && obs.getValueCoded() != null) {
          if (columnDisplayFormat.contains(
              EncounterAndObsDataSetDefinition.ColumnDisplayFormat.ID)) {
            columnValue.append(obs.getValueCoded());
          }

          if (columnDisplayFormat.contains(EncounterAndObsDataSetDefinition.ColumnDisplayFormat.ID)
              && columnDisplayFormat.contains(
                  EncounterAndObsDataSetDefinition.ColumnDisplayFormat.BEST_SHORT_NAME)) {
            columnValue.append("_");
          }

          if (columnDisplayFormat.contains(
              EncounterAndObsDataSetDefinition.ColumnDisplayFormat.BEST_SHORT_NAME)) {
            String conceptName = obs.getValueAsString(Context.getLocale());
            columnValue.append(
                maxColumnHeaderWidth != null
                        && conceptName.length() > maxColumnHeaderWidth - columnValue.length()
                    ? conceptName.substring(0, maxColumnHeaderWidth - columnValue.length() - 1)
                    : conceptName);
          }
          row.addColumnValue(obsDsc, (obs != null) ? columnValue.toString() : EMPTY);
        } else {
          row.addColumnValue(
              obsDsc, (obs != null) ? obs.getValueAsString(Context.getLocale()) : EMPTY);
        }

        String dateColumnName =
            columnKey.format(
                columnDisplayFormat,
                maxColumnHeaderWidth != null ? maxColumnHeaderWidth - 5 : null);
        DataSetColumn obsDscDate =
            new DataSetColumn(dateColumnName + "_DATE", dateColumnName + "_DATE", String.class);
        row.addColumnValue(obsDscDate, (obs != null) ? obs.getObsDatetime().toString() : EMPTY);

        String parentColumnName =
            columnKey.format(
                columnDisplayFormat,
                maxColumnHeaderWidth != null ? maxColumnHeaderWidth - 7 : null);
        DataSetColumn obsDscParent =
            new DataSetColumn(
                parentColumnName + "_PARENT", parentColumnName + "_PARENT", String.class);
        row.addColumnValue(
            obsDscParent,
            (obs != null && obs.getObsGroup() != null) ? obs.getObsGroup().getId() : EMPTY);

        if (optionalColumns != null) {

          if (optionalColumns.contains(
              EncounterAndObsDataSetDefinition.ObsOptionalColumn.VALUE_MODIFIER)) {
            String valModColumnName =
                columnKey.format(
                    columnDisplayFormat,
                    maxColumnHeaderWidth != null ? maxColumnHeaderWidth - 10 : null);
            DataSetColumn obsDscValueModifier =
                new DataSetColumn(
                    valModColumnName + "_VALUE_MOD", valModColumnName + "_VALUE_MOD", String.class);
            row.addColumnValue(obsDscValueModifier, (obs != null) ? obs.getValueModifier() : EMPTY);
          }
          if (optionalColumns.contains(
              EncounterAndObsDataSetDefinition.ObsOptionalColumn.ACCESSION_NUMBER)) {
            String accessionNumColumnName =
                columnKey.format(
                    columnDisplayFormat,
                    maxColumnHeaderWidth != null ? maxColumnHeaderWidth - 14 : null);
            DataSetColumn obsDscAccessionNumber =
                new DataSetColumn(
                    accessionNumColumnName + "_ACCESSION_NUM",
                    accessionNumColumnName + "_ACCESSION_NUM",
                    String.class);
            row.addColumnValue(
                obsDscAccessionNumber, (obs != null) ? obs.getAccessionNumber() : EMPTY);
          }
          if (optionalColumns.contains(
              EncounterAndObsDataSetDefinition.ObsOptionalColumn.COMMENT)) {
            String commentColumnName =
                columnKey.format(
                    columnDisplayFormat,
                    maxColumnHeaderWidth != null ? maxColumnHeaderWidth - 8 : null);
            DataSetColumn obsDscComment =
                new DataSetColumn(
                    commentColumnName + "_COMMENT", commentColumnName + "_COMMENT", String.class);
            row.addColumnValue(obsDscComment, (obs != null) ? obs.getComment() : EMPTY);
          }
        }
      }

      dataSet.addRow(row);
    }
    return dataSet;
  }
  /** @see org.openmrs.api.EncounterService#saveEncounter(org.openmrs.Encounter) */
  public Encounter saveEncounter(Encounter encounter) throws APIException {

    // if authenticated user is not supposed to edit encounter of certain type
    if (!canEditEncounter(encounter, null)) {
      throw new APIException(
          "Encounter.error.privilege.required.edit",
          new Object[] {encounter.getEncounterType().getEditPrivilege()});
    }

    // If new encounter, try to assign a visit using the registered visit assignment handler.
    if (encounter.getEncounterId() == null) {

      // Am using Context.getEncounterService().getActiveEncounterVisitHandler() instead of just
      // getActiveEncounterVisitHandler() for modules which may want to AOP around this call.
      EncounterVisitHandler encounterVisitHandler =
          Context.getEncounterService().getActiveEncounterVisitHandler();
      if (encounterVisitHandler != null) {
        encounterVisitHandler.beforeCreateEncounter(encounter);

        // If we have been assigned a new visit, persist it.
        if (encounter.getVisit() != null && encounter.getVisit().getVisitId() == null) {
          Context.getVisitService().saveVisit(encounter.getVisit());
        }
      }
    }

    boolean isNewEncounter = false;
    Date newDate = encounter.getEncounterDatetime();
    Date originalDate = null;
    Location newLocation = encounter.getLocation();
    Location originalLocation = null;
    // check permissions
    if (encounter.getEncounterId() == null) {
      isNewEncounter = true;
      Context.requirePrivilege(PrivilegeConstants.ADD_ENCOUNTERS);
    } else {
      Context.requirePrivilege(PrivilegeConstants.EDIT_ENCOUNTERS);
    }

    // This must be done after setting dateCreated etc on the obs because
    // of the way the ORM tools flush things and check for nullity
    // This also must be done before the save encounter so we can use the
    // orig date
    // after the save
    Patient p = encounter.getPatient();

    if (!isNewEncounter) {
      // fetch the datetime from the database prior to saving for this
      // encounter
      // to see if it has changed and change all obs after saving if so
      originalDate = dao.getSavedEncounterDatetime(encounter);
      if (encounter.getLocation() != null) {
        originalLocation = dao.getSavedEncounterLocation(encounter);
      }
      // Our data model duplicates the patient column to allow for
      // observations to
      // not have to look up the parent Encounter to find the patient
      // Therefore, encounter.patient must always equal
      // encounter.observations[0-n].patient

      // If we are changing encounter.encounterDatetime, then we need to
      // also apply that
      // to Obs that inherited their obsDatetime from the encounter in the
      // first place

      for (Obs obs : encounter.getAllObs(true)) {
        // if the date was changed
        if (OpenmrsUtil.compare(originalDate, newDate) != 0
            && OpenmrsUtil.compare(obs.getObsDatetime(), originalDate) == 0) {

          // if the obs datetime is the same as the
          // original encounter datetime, fix it
          obs.setObsDatetime(newDate);
        }

        if (!OpenmrsUtil.nullSafeEquals(newLocation, originalLocation)
            && obs.getLocation().equals(originalLocation)) {
          obs.setLocation(newLocation);
        }

        // if the Person in the obs doesn't match the Patient in the
        // encounter, fix it
        if (!obs.getPerson().getPersonId().equals(p.getPatientId())) {
          obs.setPerson(p);
        }
      }
    }
    // same goes for Orders
    for (Order o : encounter.getOrders()) {
      if (!p.equals(o.getPatient())) {
        o.setPatient(p);
      }
    }

    // do the actual saving to the database
    dao.saveEncounter(encounter);

    // save the new orders
    for (Order o : encounter.getOrders()) {
      if (o.getOrderId() == null) {
        Context.getOrderService().saveOrder(o, null);
      }
    }
    return encounter;
  }
Exemplo n.º 23
0
  /**
   * This method produces a model containing the following mappings:
   *
   * <pre>
   *     (always)
   *          (java.util.Date) now
   *          (String) size
   *          (Locale) locale
   *          (String) portletUUID // unique for each instance of any portlet
   *          (other parameters)
   *     (if there's currently an authenticated user)
   *          (User) authenticatedUser
   *     (if the request has a patientId attribute)
   *          (Integer) patientId
   *          (Patient) patient
   *          (List<Obs>) patientObs
   *          (List<Encounter>) patientEncounters
   *          (List<DrugOrder>) patientDrugOrders
   *          (List<DrugOrder>) currentDrugOrders
   *          (List<DrugOrder>) completedDrugOrders
   *          (Obs) patientWeight // most recent weight obs
   *          (Obs) patientHeight // most recent height obs
   *          (Double) patientBmi // BMI derived from most recent weight and most recent height
   *          (String) patientBmiAsString // BMI rounded to one decimal place, or "?" if unknown
   *          (Integer) personId
   *          (if the patient has any obs for the concept in the global property 'concept.reasonExitedCare')
   *              (Obs) patientReasonForExit
   *     (if the request has a personId or patientId attribute)
   *          (Person) person
   *          (List<Relationship>) personRelationships
   *          (Map<RelationshipType, List<Relationship>>) personRelationshipsByType
   *     (if the request has an encounterId attribute)
   *          (Integer) encounterId
   *          (Encounter) encounter
   *          (Set<Obs>) encounterObs
   *     (if the request has a userId attribute)
   *          (Integer) userId
   *          (User) user
   *     (if the request has a patientIds attribute, which should be a (String) comma-separated list of patientIds)
   *          (PatientSet) patientSet
   *          (String) patientIds
   *     (if the request has a conceptIds attribute, which should be a (String) commas-separated list of conceptIds)
   *          (Map<Integer, Concept>) conceptMap
   *          (Map<String, Concept>) conceptMapByStringIds
   * </pre>
   *
   * @should calculate bmi into patientBmiAsString
   * @should not fail with empty height and weight properties
   */
  @SuppressWarnings("unchecked")
  public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    AdministrationService as = Context.getAdministrationService();
    ConceptService cs = Context.getConceptService();

    // find the portlet that was identified in the openmrs:portlet taglib
    Object uri = request.getAttribute("javax.servlet.include.servlet_path");
    String portletPath = "";
    Map<String, Object> model = null;
    {
      HttpSession session = request.getSession();
      String uniqueRequestId = (String) request.getAttribute(WebConstants.INIT_REQ_UNIQUE_ID);
      String lastRequestId =
          (String) session.getAttribute(WebConstants.OPENMRS_PORTLET_LAST_REQ_ID);
      if (uniqueRequestId.equals(lastRequestId)) {
        model =
            (Map<String, Object>) session.getAttribute(WebConstants.OPENMRS_PORTLET_CACHED_MODEL);

        // remove cached parameters
        List<String> parameterKeys = (List<String>) model.get("parameterKeys");
        for (String key : parameterKeys) {
          model.remove(key);
        }
      }
      if (model == null) {
        log.debug("creating new portlet model");
        model = new HashMap<String, Object>();
        session.setAttribute(WebConstants.OPENMRS_PORTLET_LAST_REQ_ID, uniqueRequestId);
        session.setAttribute(WebConstants.OPENMRS_PORTLET_CACHED_MODEL, model);
      }
    }

    if (uri != null) {
      long timeAtStart = System.currentTimeMillis();
      portletPath = uri.toString();

      // Allowable extensions are '' (no extension) and '.portlet'
      if (portletPath.endsWith("portlet")) portletPath = portletPath.replace(".portlet", "");
      else if (portletPath.endsWith("jsp"))
        throw new ServletException(
            "Illegal extension used for portlet: '.jsp'. Allowable extensions are '' (no extension) and '.portlet'");

      log.debug("Loading portlet: " + portletPath);

      String id = (String) request.getAttribute("org.openmrs.portlet.id");
      String size = (String) request.getAttribute("org.openmrs.portlet.size");
      Map<String, Object> params =
          (Map<String, Object>) request.getAttribute("org.openmrs.portlet.parameters");
      Map<String, Object> moreParams =
          (Map<String, Object>) request.getAttribute("org.openmrs.portlet.parameterMap");

      model.put("now", new Date());
      model.put("id", id);
      model.put("size", size);
      model.put("locale", Context.getLocale());
      model.put("portletUUID", UUID.randomUUID().toString().replace("-", ""));
      List<String> parameterKeys = new ArrayList<String>(params.keySet());
      model.putAll(params);
      if (moreParams != null) {
        model.putAll(moreParams);
        parameterKeys.addAll(moreParams.keySet());
      }
      model.put("parameterKeys", parameterKeys); // so we can clean these up in the next request

      // if there's an authenticated user, put them, and their patient set, in the model
      if (Context.getAuthenticatedUser() != null) {
        model.put("authenticatedUser", Context.getAuthenticatedUser());
      }

      Integer personId = null;

      // if a patient id is available, put patient data documented above in the model
      Object o = request.getAttribute("org.openmrs.portlet.patientId");
      if (o != null) {
        String patientVariation = "";
        Integer patientId = (Integer) o;
        if (!model.containsKey("patient")) {
          // we can't continue if the user can't view patients
          if (Context.hasPrivilege(PrivilegeConstants.VIEW_PATIENTS)) {
            Patient p = Context.getPatientService().getPatient(patientId);
            model.put("patient", p);

            // add encounters if this user can view them
            if (Context.hasPrivilege(PrivilegeConstants.VIEW_ENCOUNTERS))
              model.put(
                  "patientEncounters", Context.getEncounterService().getEncountersByPatient(p));

            if (Context.hasPrivilege(PrivilegeConstants.VIEW_OBS)) {
              List<Obs> patientObs = Context.getObsService().getObservationsByPerson(p);
              model.put("patientObs", patientObs);
              Obs latestWeight = null;
              Obs latestHeight = null;
              String bmiAsString = "?";
              try {
                String weightString = as.getGlobalProperty("concept.weight");
                ConceptNumeric weightConcept = null;
                if (StringUtils.hasLength(weightString))
                  weightConcept =
                      cs.getConceptNumeric(
                          cs.getConcept(Integer.valueOf(weightString)).getConceptId());
                String heightString = as.getGlobalProperty("concept.height");
                ConceptNumeric heightConcept = null;
                if (StringUtils.hasLength(heightString))
                  heightConcept =
                      cs.getConceptNumeric(
                          cs.getConcept(Integer.valueOf(heightString)).getConceptId());
                for (Obs obs : patientObs) {
                  if (obs.getConcept().equals(weightConcept)) {
                    if (latestWeight == null
                        || obs.getObsDatetime().compareTo(latestWeight.getObsDatetime()) > 0)
                      latestWeight = obs;
                  } else if (obs.getConcept().equals(heightConcept)) {
                    if (latestHeight == null
                        || obs.getObsDatetime().compareTo(latestHeight.getObsDatetime()) > 0)
                      latestHeight = obs;
                  }
                }
                if (latestWeight != null) model.put("patientWeight", latestWeight);
                if (latestHeight != null) model.put("patientHeight", latestHeight);
                if (latestWeight != null && latestHeight != null) {
                  double weightInKg;
                  double heightInM;
                  if (weightConcept.getUnits().equals("kg"))
                    weightInKg = latestWeight.getValueNumeric();
                  else if (weightConcept.getUnits().equals("lb"))
                    weightInKg = latestWeight.getValueNumeric() * 0.45359237;
                  else
                    throw new IllegalArgumentException(
                        "Can't handle units of weight concept: " + weightConcept.getUnits());
                  if (heightConcept.getUnits().equals("cm"))
                    heightInM = latestHeight.getValueNumeric() / 100;
                  else if (heightConcept.getUnits().equals("m"))
                    heightInM = latestHeight.getValueNumeric();
                  else if (heightConcept.getUnits().equals("in"))
                    heightInM = latestHeight.getValueNumeric() * 0.0254;
                  else
                    throw new IllegalArgumentException(
                        "Can't handle units of height concept: " + heightConcept.getUnits());
                  double bmi = weightInKg / (heightInM * heightInM);
                  model.put("patientBmi", bmi);
                  String temp = "" + bmi;
                  bmiAsString = temp.substring(0, temp.indexOf('.') + 2);
                }
              } catch (Exception ex) {
                if (latestWeight != null && latestHeight != null)
                  log.error(
                      "Failed to calculate BMI even though a weight and height were found", ex);
              }
              model.put("patientBmiAsString", bmiAsString);
            } else {
              model.put("patientObs", new HashSet<Obs>());
            }

            // information about whether or not the patient has exited care
            Obs reasonForExitObs = null;
            String reasonForExitConceptString = as.getGlobalProperty("concept.reasonExitedCare");
            if (StringUtils.hasLength(reasonForExitConceptString)) {
              Concept reasonForExitConcept = cs.getConcept(reasonForExitConceptString);
              if (reasonForExitConcept != null) {
                List<Obs> patientExitObs =
                    Context.getObsService()
                        .getObservationsByPersonAndConcept(p, reasonForExitConcept);
                if (patientExitObs != null) {
                  log.debug("Exit obs is size " + patientExitObs.size());
                  if (patientExitObs.size() == 1) {
                    reasonForExitObs = patientExitObs.iterator().next();
                    Concept exitReason = reasonForExitObs.getValueCoded();
                    Date exitDate = reasonForExitObs.getObsDatetime();
                    if (exitReason != null && exitDate != null) {
                      patientVariation = "Exited";
                    }
                  } else {
                    if (patientExitObs.size() == 0) {
                      log.debug("Patient has no reason for exit");
                    } else {
                      log.error("Too many reasons for exit - not putting data into model");
                    }
                  }
                }
              }
            }
            model.put("patientReasonForExit", reasonForExitObs);

            if (Context.hasPrivilege(PrivilegeConstants.VIEW_ORDERS)) {
              List<DrugOrder> drugOrderList = Context.getOrderService().getDrugOrdersByPatient(p);
              model.put("patientDrugOrders", drugOrderList);
              List<DrugOrder> currentDrugOrders = new ArrayList<DrugOrder>();
              List<DrugOrder> discontinuedDrugOrders = new ArrayList<DrugOrder>();
              Date rightNow = new Date();
              for (Iterator<DrugOrder> iter = drugOrderList.iterator(); iter.hasNext(); ) {
                DrugOrder next = iter.next();
                if (next.isCurrent() || next.isFuture()) currentDrugOrders.add(next);
                if (next.isDiscontinued(rightNow)) discontinuedDrugOrders.add(next);
              }
              model.put("currentDrugOrders", currentDrugOrders);
              model.put("completedDrugOrders", discontinuedDrugOrders);

              List<RegimenSuggestion> standardRegimens =
                  Context.getOrderService().getStandardRegimens();
              if (standardRegimens != null) model.put("standardRegimens", standardRegimens);
            }

            if (Context.hasPrivilege(PrivilegeConstants.VIEW_PROGRAMS)
                && Context.hasPrivilege(PrivilegeConstants.VIEW_PATIENT_PROGRAMS)) {
              model.put(
                  "patientPrograms",
                  Context.getProgramWorkflowService()
                      .getPatientPrograms(p, null, null, null, null, null, false));
              model.put(
                  "patientCurrentPrograms",
                  Context.getProgramWorkflowService()
                      .getPatientPrograms(p, null, null, new Date(), new Date(), null, false));
            }

            model.put("patientId", patientId);
            if (p != null) {
              personId = p.getPatientId();
              model.put("personId", personId);
            }

            model.put("patientVariation", patientVariation);
          }
        }
      }

      // if a person id is available, put person and relationships in the model
      if (personId == null) {
        o = request.getAttribute("org.openmrs.portlet.personId");
        if (o != null) {
          personId = (Integer) o;
          model.put("personId", personId);
        }
      }
      if (personId != null) {
        if (!model.containsKey("person")) {
          Person p = (Person) model.get("patient");
          if (p == null) p = Context.getPersonService().getPerson(personId);
          model.put("person", p);

          if (Context.hasPrivilege(PrivilegeConstants.VIEW_RELATIONSHIPS)) {
            List<Relationship> relationships = new ArrayList<Relationship>();
            relationships.addAll(Context.getPersonService().getRelationshipsByPerson(p));
            Map<RelationshipType, List<Relationship>> relationshipsByType =
                new HashMap<RelationshipType, List<Relationship>>();
            for (Relationship rel : relationships) {
              List<Relationship> list = relationshipsByType.get(rel.getRelationshipType());
              if (list == null) {
                list = new ArrayList<Relationship>();
                relationshipsByType.put(rel.getRelationshipType(), list);
              }
              list.add(rel);
            }

            model.put("personRelationships", relationships);
            model.put("personRelationshipsByType", relationshipsByType);
          }
        }
      }

      // if an encounter id is available, put "encounter" and "encounterObs" in the model
      o = request.getAttribute("org.openmrs.portlet.encounterId");
      if (o != null && !model.containsKey("encounterId")) {
        if (!model.containsKey("encounter")) {
          if (Context.hasPrivilege(PrivilegeConstants.VIEW_ENCOUNTERS)) {
            Encounter e = Context.getEncounterService().getEncounter((Integer) o);
            model.put("encounter", e);
            if (Context.hasPrivilege(PrivilegeConstants.VIEW_OBS))
              model.put("encounterObs", e.getObs());
          }
          model.put("encounterId", (Integer) o);
        }
      }

      // if a user id is available, put "user" in the model
      o = request.getAttribute("org.openmrs.portlet.userId");
      if (o != null) {
        if (!model.containsKey("user")) {
          if (Context.hasPrivilege(PrivilegeConstants.VIEW_USERS)) {
            User u = Context.getUserService().getUser((Integer) o);
            model.put("user", u);
          }
          model.put("userId", (Integer) o);
        }
      }

      // if a list of patient ids is available, make a patientset out of it
      o = request.getAttribute("org.openmrs.portlet.patientIds");
      if (o != null && !"".equals(o) && !model.containsKey("patientIds")) {
        if (!model.containsKey("patientSet")) {
          Cohort ps = new Cohort((String) o);
          model.put("patientSet", ps);
          model.put("patientIds", (String) o);
        }
      }

      o = model.get("conceptIds");
      if (o != null && !"".equals(o)) {
        if (!model.containsKey("conceptMap")) {
          log.debug("Found conceptIds parameter: " + o);
          Map<Integer, Concept> concepts = new HashMap<Integer, Concept>();
          Map<String, Concept> conceptsByStringIds = new HashMap<String, Concept>();
          String conceptIds = (String) o;
          String[] ids = conceptIds.split(",");
          for (String cId : ids) {
            try {
              Integer i = Integer.valueOf(cId);
              Concept c = cs.getConcept(i);
              concepts.put(i, c);
              conceptsByStringIds.put(i.toString(), c);
            } catch (Exception ex) {
            }
          }
          model.put("conceptMap", concepts);
          model.put("conceptMapByStringIds", conceptsByStringIds);
        }
      }

      populateModel(request, model);
      log.debug(portletPath + " took " + (System.currentTimeMillis() - timeAtStart) + " ms");
    }

    return new ModelAndView(portletPath, "model", model);
  }
  public DataSetRow renderRow(
      Patient p,
      PatientIdentifierType patientIdentifierType,
      Location location,
      Date startDate,
      Date endDate) {

    PatientDataHelper pdh = new PatientDataHelper();
    ProgramHelper ph = new ProgramHelper();
    HivMetadata hivMetadata = new HivMetadata();

    DataSetRow row = new DataSetRow();
    pdh.addCol(row, "#", p.getPatientId());
    pdh.addCol(row, "KS ID", pdh.preferredIdentifierAtLocation(p, patientIdentifierType, location));
    pdh.addCol(
        row,
        "ART ID",
        pdh.preferredIdentifierAtLocation(p, lookupPatientIdentifierType("ARV Number"), location));
    pdh.addCol(row, "Birthdate", pdh.getBirthdate(p));
    pdh.addCol(row, "Gender", pdh.getGender(p));
    pdh.addCol(row, "VHW", pdh.vhwName(p, false));
    pdh.addCol(row, "Village", pdh.getVillage(p));

    PatientProgram latestKsProgram =
        ph.getMostRecentProgramEnrollmentAtLocation(
            p, lookupProgram("Kaposis sarcoma program"), location);

    Date latestKsProgramDate = null;
    if (latestKsProgram != null) {
      latestKsProgramDate = latestKsProgram.getDateEnrolled();
      pdh.addCol(row, "KS Program Enrollment Date", pdh.formatYmd(latestKsProgramDate));

      for (PatientState ps : ph.getActiveStatesOnDate(p, latestKsProgramDate)) {
        String programName = ps.getPatientProgram().getProgram().getName();
        pdh.addCol(row, programName + " Status at Enrollment", pdh.formatStateName(ps));
        pdh.addCol(row, programName + " Status Date at Enrollment", pdh.formatStateStartDate(ps));
      }
    }

    Obs mostRecentDxDate = pdh.getLatestObs(p, "DATE OF HIV DIAGNOSIS", null, endDate);
    pdh.addCol(row, "Date HIV Diagnosis", pdh.formatValueDatetime(mostRecentDxDate));

    Program hivProgram = hivMetadata.getHivProgram();
    ProgramWorkflowState onArvState = hivMetadata.getOnArvsState();

    PatientState earliestOnArvsState = ph.getFirstTimeInState(p, hivProgram, onArvState, endDate);
    Date arvStartDate = (earliestOnArvsState == null ? null : earliestOnArvsState.getStartDate());

    if (latestKsProgramDate != null) {
      pdh.addCol(
          row,
          "On ART at KS Enrollment",
          arvStartDate != null && arvStartDate.compareTo(latestKsProgramDate) <= 0);
    }

    Map<String, String> reasonsForStartingArvs = pdh.getReasonStartingArvs(p, endDate);
    for (String reasonKey : reasonsForStartingArvs.keySet()) {
      pdh.addCol(row, "ARV Reason " + reasonKey, reasonsForStartingArvs.get(reasonKey));
    }

    if (arvStartDate != null) {
      pdh.addCol(row, "Start Date for ART", pdh.formatStateStartDate(earliestOnArvsState));
      if (latestKsProgramDate != null) {
        pdh.addCol(
            row,
            "Months on ART at KS Enrollment",
            DateUtil.monthsBetween(arvStartDate, latestKsProgramDate));
      }
    }

    if (latestKsProgramDate != null) {
      Obs artRegimen =
          pdh.getLatestObs(p, "Malawi Antiretroviral drugs received", null, latestKsProgramDate);
      pdh.addCol(row, "ART Regimen Obs at Enrollment", pdh.formatValue(artRegimen));

      Set<Concept> drugOrdersAtEnrollment = pdh.getDrugsTakingOnDate(p, latestKsProgramDate);
      pdh.addCol(
          row, "Drugs Taking at Enrollment", pdh.formatConcepts(drugOrdersAtEnrollment, "+"));

      Obs cd4 = pdh.getLatestObs(p, "CD4 count", null, latestKsProgramDate);
      pdh.addCol(row, "CD4 at enrollment", pdh.formatValue(cd4));
      pdh.addCol(row, "CD4 at enrollment date", pdh.formatObsDatetime(cd4));
    }

    Obs height = pdh.getLatestObs(p, "Height (cm)", null, endDate);
    pdh.addCol(row, "Latest Height", pdh.formatValue(height));
    pdh.addCol(row, "Latest Height Date", pdh.formatObsDatetime(height));

    Obs firstTaxolObs = pdh.getEarliestObs(p, "Paclitaxel (taxol) dose received", null, endDate);
    pdh.addCol(row, "First Taxol Dose Received Date", pdh.formatObsDatetime(firstTaxolObs));

    DrugOrder firstTaxolOrder = pdh.getEarliestDrugOrder(p, "Paclitaxel", endDate);
    pdh.addCol(row, "First Taxol Drug Order Date", pdh.formatOrderStartDate(firstTaxolOrder));

    Date firstTaxolDate = null;
    if (firstTaxolObs != null) {
      firstTaxolDate = firstTaxolObs.getObsDatetime();
    }
    if (firstTaxolOrder != null) {
      if (firstTaxolDate == null || firstTaxolOrder.getStartDate().before(firstTaxolDate)) {
        firstTaxolDate = firstTaxolOrder.getStartDate();
      }
    }
    pdh.addCol(row, "First Taxol Date", pdh.formatYmd(firstTaxolDate));

    if (firstTaxolDate != null) {
      Obs cd4AtTaxol = pdh.getLatestObs(p, "CD4 count", null, firstTaxolDate);
      pdh.addCol(row, "Most recent CD4 at First Taxol", pdh.formatValue(cd4AtTaxol));
      pdh.addCol(row, "Most recent CD4 at First Taxol Date", pdh.formatObsDatetime(cd4AtTaxol));
    }

    for (PatientState ps : ph.getActiveStatesOnDate(p, endDate)) {
      String ed = pdh.formatYmd(endDate);
      String programName = ps.getPatientProgram().getProgram().getName();
      pdh.addCol(row, programName + " Status on " + ed, pdh.formatStateName(ps));
      pdh.addCol(row, programName + " Status Date on " + ed, pdh.formatStateStartDate(ps));
    }

    pdh.addCol(row, "Death Date", pdh.formatYmd(p.getDeathDate()));

    return row;
  }