public boolean areConsecutiveVisits(List<Integer> visits, Patient patient) {
   if (patient != null && visits != null && (visits.size() > 0)) {
     List<Visit> patientVisits = visitService.getVisitsByPatient(patient, true, false);
     if ((patientVisits != null) && (patientVisits.size() > 0)) {
       ArrayList<Integer> allVisits = new ArrayList<Integer>();
       int j = 0;
       for (Visit visit : patientVisits) {
         allVisits.add(j++, visit.getId());
       }
       if (allVisits.containsAll(visits)) {
         // find the index of the first candidate for a consecutive visit
         int i = allVisits.indexOf(visits.get(0));
         // make sure there are still more elements in the list than the the number of candidate
         // consecutives
         if ((allVisits.size() - i) >= visits.size()) {
           for (Integer candidateVisit : visits) {
             if (allVisits.get(i).compareTo(candidateVisit) == 0) {
               i++;
             } else {
               return false;
             }
           }
           return true;
         }
       }
     }
   }
   return false;
 }
  @Override
  @Transactional
  public VisitDomainWrapper createRetrospectiveVisit(
      Patient patient, Location location, Date startDatetime, Date stopDatetime)
      throws ExistingVisitDuringTimePeriodException {

    if (startDatetime.after(new Date())) {
      throw new IllegalArgumentException("emrapi.retrospectiveVisit.startDateCannotBeInFuture");
    }

    if (stopDatetime.after(new Date())) {
      throw new IllegalArgumentException("emrapi.retrospectiveVisit.stopDateCannotBeInFuture");
    }

    if (startDatetime.after(stopDatetime)) {
      throw new IllegalArgumentException("emrapi.retrospectiveVisit.endDateBeforeStartDateMessage");
    }

    if (hasVisitDuring(patient, location, startDatetime, stopDatetime)) {
      throw new ExistingVisitDuringTimePeriodException(
          "emrapi.retrospectiveVisit.patientAlreadyHasVisit");
    }

    Visit visit = buildVisit(patient, location, startDatetime);
    visit.setStopDatetime(stopDatetime);

    return wrap(visitService.saveVisit(visit));
  }
  @Test
  public void shouldAddNewTestOrder() throws Exception {
    executeDataSet("shouldAddNewTestOrder.xml");

    String json =
        "{ \"patientUuid\" : \"a76e8d23-0c38-408c-b2a8-ea5540f01b51\", "
            + "\"visitTypeUuid\" : \"b45ca846-c79a-11e2-b0c0-8e397087571c\", "
            + "\"encounterTypeUuid\": \"2b377dba-62c3-4e53-91ef-b51c68899890\", "
            + "\"encounterDateTime\" : \"2005-01-02T00:00:00.000+0000\", "
            + "\"testOrders\":["
            + "{\"concept\": {\"uuid\": \"d102c80f-1yz9-4da3-bb88-8122ce8868dd\"}, \"instructions\":\"do it\", \"orderTypeUuid\": \"1a61ef2a-250c-11e3-b832-0800271c1b75\" }]}";

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

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

    assertEquals(1, encounter.getOrders().size());
    Order testOrder = encounter.getOrders().iterator().next();
    assertEquals("d102c80f-1yz9-4da3-bb88-8122ce8868dd", testOrder.getConcept().getUuid());
    assertEquals("a76e8d23-0c38-408c-b2a8-ea5540f01b51", testOrder.getPatient().getUuid());
    assertEquals("f13d6fae-baa9-4553-955d-920098bec08f", testOrder.getEncounter().getUuid());
    assertEquals("1a61ef2a-250c-11e3-b832-0800271c1b75", testOrder.getOrderType().getUuid());
    assertEquals("do it", testOrder.getInstructions());
  }
  @Test
  public void shouldCreateNewEncounter() throws Exception {
    executeDataSet("shouldCreateMatchingEncounter.xml");

    String encounterDateTimeString = "2011-05-01T12:10:06.000+0530";
    Date encounterDateTime = new SimpleDateFormat(dateTimeFormat).parse(encounterDateTimeString);

    String json =
        "{ \"patientUuid\" : \"a76e8d23-0c38-408c-b2a8-ea5540f01b51\", "
            + "\"visitTypeUuid\" : \"b45ca846-c79a-11e2-b0c0-8e397087571c\", "
            + "\"encounterDateTime\" : \""
            + encounterDateTimeString
            + "\", "
            + "\"encounterTypeUuid\": \"2b377dba-62c3-4e53-91ef-b51c68899890\" }";

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

    assertEquals("1e5d5d48-6b78-11e0-93c3-18a905e044dc", response.getVisitUuid());

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

    assertEquals("a76e8d23-0c38-408c-b2a8-ea5540f01b51", encounter.getPatient().getUuid());
    assertEquals("2b377dba-62c3-4e53-91ef-b51c68899890", encounter.getEncounterType().getUuid());
    assertEquals(encounterDateTime, encounter.getEncounterDatetime());
  }
  @Test
  public void shouldAddNewDrugOrder() throws Exception {
    executeDataSet("shouldAddNewDrugOrder.xml");

    String json =
        "{ \"patientUuid\" : \"a76e8d23-0c38-408c-b2a8-ea5540f01b51\", "
            + "\"visitTypeUuid\" : \"b45ca846-c79a-11e2-b0c0-8e397087571c\", "
            + "\"encounterTypeUuid\": \"2b377dba-62c3-4e53-91ef-b51c68899890\", "
            + "\"encounterDateTime\" : \"2005-01-02T00:00:00.000+0000\", "
            + "\"testOrders\":["
            + "{\"concept\":{ \"uuid\": \"d102c80f-1yz9-4da3-bb88-8122ce8868dd\"}, "
            + "\"instructions\":\"do it\", \"orderTypeUuid\": \"1a61ef2a-250c-11e3-b832-0800271c1b75\" }],"
            + "\"drugOrders\":["
            + "{\"uuid\": \"4d6fb6e0-4950-426c-9a9b-1f97e6037893\","
            + "\"concept\": {\"uuid\": \"29dc4a20-507f-40ed-9545-d47e932483fa\"},"
            + "\"notes\": \"Take as needed\","
            + "\"startDate\": \"2013-09-30T09:26:09.717Z\","
            + "\"endDate\": \"2013-10-02T09:26:09.717Z\","
            + "\"numberPerDosage\": 1,"
            + "\"dosageInstruction\": {\"uuid\": \"632aa422-2696-11e3-895c-0800271c1b75\"},"
            + "\"dosageFrequency\": {\"uuid\": \"6302096d-2696-11e3-895c-0800271c1b75\"},"
            + "\"prn\": true}"
            + "]}";

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

    Visit visit = visitService.getVisitByUuid(response.getVisitUuid());
    Encounter encounter = visit.getEncounters().iterator().next();
    assertEquals(2, encounter.getOrders().size());

    List<Order> orders = new ArrayList<Order>(encounter.getOrders());

    List<DrugOrder> drugOrders = getOrdersOfType(orders, DrugOrder.class);
    assertEquals(1, drugOrders.size());
    DrugOrder drugOrder = drugOrders.get(0);
    assertEquals("a76e8d23-0c38-408c-b2a8-ea5540f01b51", drugOrder.getPatient().getUuid());
    assertEquals("f13d6fae-baa9-4553-955d-920098bec08f", drugOrder.getEncounter().getUuid());
    assertEquals("29dc4a20-507f-40ed-9545-d47e932483fa", drugOrder.getConcept().getUuid());
    assertEquals("1a61ef2a-250c-11e3-b832-9876541c1b75", drugOrder.getOrderType().getUuid());
    assertEquals("Take as needed", drugOrder.getInstructions());
    assertEquals(new DateTime("2013-09-30T09:26:09.717Z").toDate(), drugOrder.getStartDate());
    assertEquals(new DateTime("2013-10-02T09:26:09.717Z").toDate(), drugOrder.getAutoExpireDate());
    assertEquals("6302096d-2696-11e3-895c-0800271c1b75", drugOrder.getFrequency());
    assertEquals("632aa422-2696-11e3-895c-0800271c1b75", drugOrder.getUnits());
    assertEquals("test drug", drugOrder.getDrug().getDisplayName());
    assertEquals(Double.valueOf(1), drugOrder.getDose());
    assertEquals(true, drugOrder.getPrn());

    List<TestOrder> testOrders = getOrdersOfType(orders, TestOrder.class);
    assertEquals(1, testOrders.size());
    TestOrder testOrder = testOrders.get(0);
    assertEquals("d102c80f-1yz9-4da3-bb88-8122ce8868dd", testOrder.getConcept().getUuid());
    assertEquals("a76e8d23-0c38-408c-b2a8-ea5540f01b51", testOrder.getPatient().getUuid());
    assertEquals("f13d6fae-baa9-4553-955d-920098bec08f", testOrder.getEncounter().getUuid());
    assertEquals("1a61ef2a-250c-11e3-b832-0800271c1b75", testOrder.getOrderType().getUuid());
    assertEquals("do it", testOrder.getInstructions());
  }
 private Visit buildVisit(Patient patient, Location location, Date when) {
   Visit visit = new Visit();
   visit.setPatient(patient);
   visit.setLocation(getLocationThatSupportsVisits(location));
   visit.setStartDatetime(when);
   visit.setVisitType(emrApiProperties.getAtFacilityVisitType());
   return visit;
 }
 /**
  * @param visit
  * @param location
  * @param when
  * @return true if when falls in the visits timespan AND location is within visit.location
  */
 @Override
 public boolean isSuitableVisit(Visit visit, Location location, Date when) {
   if (OpenmrsUtil.compare(when, visit.getStartDatetime()) < 0) {
     return false;
   }
   if (OpenmrsUtil.compareWithNullAsLatest(when, visit.getStopDatetime()) > 0) {
     return false;
   }
   return isSameOrAncestor(visit.getLocation(), location);
 }
  /**
   * This method is synchronized to prevent multiple check-ins in a row at the same location and
   * during the same visit. See #579.
   *
   * @see org.openmrs.module.emrapi.adt.AdtService#checkInPatient(org.openmrs.Patient,
   *     org.openmrs.Location, org.openmrs.Provider, java.util.List, java.util.List, boolean)
   */
  @Override
  @Transactional
  public synchronized Encounter checkInPatient(
      Patient patient,
      Location where,
      Provider checkInClerk,
      List<Obs> obsForCheckInEncounter,
      List<Order> ordersForCheckInEncounter,
      boolean newVisit) {
    if (checkInClerk == null) {
      checkInClerk = getProvider(Context.getAuthenticatedUser());
    }

    Visit activeVisit = getActiveVisitHelper(patient, where);

    if (activeVisit != null && newVisit) {
      closeAndSaveVisit(activeVisit);
      activeVisit = null;
    }

    if (activeVisit == null) {
      activeVisit = ensureActiveVisit(patient, where);
    }

    Encounter lastEncounter = getLastEncounter(patient);
    if (lastEncounter != null
        && activeVisit.equals(lastEncounter.getVisit())
        && emrApiProperties.getCheckInEncounterType().equals(lastEncounter.getEncounterType())
        && where.equals(lastEncounter.getLocation())) {
      log.warn(
          "Patient id:{} tried to check-in twice in a row at id:{} during the same visit",
          patient.getId(),
          where.getId());
      return lastEncounter;
    }

    Encounter encounter =
        buildEncounter(
            emrApiProperties.getCheckInEncounterType(),
            patient,
            where,
            null,
            new Date(),
            obsForCheckInEncounter,
            ordersForCheckInEncounter);
    encounter.addProvider(emrApiProperties.getCheckInClerkEncounterRole(), checkInClerk);
    activeVisit.addEncounter(encounter);
    encounterService.saveEncounter(encounter);
    return encounter;
  }
  @Override
  public Encounter transferEncounter(Encounter encounter, Patient patient) {
    Encounter encounterCopy = encounter.copyAndAssignToAnotherPatient(patient);

    voidEncounter(encounter, "transfer to patient: id = " + patient.getId());

    // void visit if voided encounter is the only one
    Visit visit = encounter.getVisit();
    if (visit != null && visit.getEncounters().size() == 1) {
      Context.getVisitService().voidVisit(visit, "Visit does not contain non-voided encounters");
    }

    return saveEncounter(encounterCopy);
  }
  /**
   * Validates the given Encounter. Currently checks if the patient has been set and also ensures
   * that the patient for an encounter and the visit it is associated to if any, are the same.
   *
   * @param obj The encounter to validate.
   * @param errors Errors
   * @see org.springframework.validation.Validator#validate(java.lang.Object,
   *     org.springframework.validation.Errors)
   * @should fail if the patients for the visit and the encounter dont match
   * @should fail if patient is not set
   * @should fail if encounter dateTime is after current dateTime
   * @should fail if encounter dateTime is before visit startDateTime
   * @should fail if encounter dateTime is after visit stopDateTime
   */
  public void validate(Object obj, Errors errors) throws APIException {
    if (log.isDebugEnabled()) {
      log.debug(this.getClass().getName() + ".validate...");
    }

    if (obj == null || !(obj instanceof Encounter)) {
      throw new IllegalArgumentException(
          "The parameter obj should not be null and must be of type " + Encounter.class);
    }

    Encounter encounter = (Encounter) obj;

    ValidationUtils.rejectIfEmpty(
        errors, "patient", "Encounter.error.patient.required", "Patient is required");
    if (encounter.getVisit() != null
        && !ObjectUtils.equals(encounter.getVisit().getPatient(), encounter.getPatient())) {
      errors.rejectValue(
          "visit",
          "Encounter.visit.patients.dontMatch",
          "The patient for the encounter and visit should be the same");
    }

    Date encounterDateTime = encounter.getEncounterDatetime();

    if (encounterDateTime != null && encounterDateTime.after(new Date())) {
      errors.rejectValue(
          "encounterDatetime",
          "Encounter.datetimeShouldBeBeforeCurrent",
          "The encounter datetime should be before the current date.");
    }

    Visit visit = encounter.getVisit();
    if (visit != null && encounterDateTime != null) {
      if (visit.getStartDatetime() != null && encounterDateTime.before(visit.getStartDatetime())) {
        errors.rejectValue(
            "encounterDatetime",
            "Encounter.datetimeShouldBeInVisitDatesRange",
            "The encounter datetime should be between the visit start and stop dates.");
      }

      if (visit.getStopDatetime() != null && encounterDateTime.after(visit.getStopDatetime())) {
        errors.rejectValue(
            "encounterDatetime",
            "Encounter.datetimeShouldBeInVisitDatesRange",
            "The encounter datetime should be between the visit start and stop dates.");
      }
    }
  }
  private Date guessVisitStopDatetime(Visit visit) {
    if (visit.getEncounters() == null || visit.getEncounters().size() == 0) {
      return visit.getStartDatetime();
    }

    Iterator<Encounter> iterator = visit.getEncounters().iterator();
    Encounter latest = iterator.next();
    while (iterator.hasNext()) {
      Encounter candidate = iterator.next();
      if (OpenmrsUtil.compare(candidate.getEncounterDatetime(), latest.getEncounterDatetime())
          > 0) {
        latest = candidate;
      }
    }
    return latest.getEncounterDatetime();
  }
  @Test
  public void shouldCreateVisitWhenNoVisitsAreActive() throws Exception {
    executeDataSet("shouldCreateVisitWhenNoVisitsAreActive.xml");

    String json =
        "{ \"patientUuid\" : \"a76e8d23-0c38-408c-b2a8-ea5540f01b51\", \"visitTypeUuid\" : \"b45ca846-c79a-11e2-b0c0-8e397087571c\","
            + "\"encounterTypeUuid\": \"2b377dba-62c3-4e53-91ef-b51c68899890\" }";

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

    Visit visit = visitService.getVisitByUuid(response.getVisitUuid());
    assertEquals("a76e8d23-0c38-408c-b2a8-ea5540f01b51", visit.getPatient().getUuid());
    assertEquals("b45ca846-c79a-11e2-b0c0-8e397087571c", visit.getVisitType().getUuid());
  }
  @Test
  public void shouldAddNewObservation() throws Exception {
    executeDataSet("shouldAddNewObservation.xml");
    String encounterDateTime = "2005-01-02T00: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\": \"d102c80f-1yz9-4da3-bb88-8122ce8868dd\"}, \"conceptName\":\"Should be Ignored\", \"value\":20}, "
            + "{\"concept\": {\"uuid\": \"8f8e7340-a067-11e3-a5e2-0800200c9a66\"}, \"value\": {\"uuid\": \"e7167090-a067-11e3-a5e2-0800200c9a66\"}}, "
            + "{\"concept\": {\"uuid\": \"e102c80f-1yz9-4da3-bb88-8122ce8868dd\"}, \"value\":\"text value\", \"comment\":\"overweight\"}]}";

    MockHttpServletResponse response1 = handle(newPostRequest("/rest/emrapi/encounter", json));

    EncounterTransaction response = deserialize(response1, EncounterTransaction.class);

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

    assertEquals(3, encounter.getObs().size());
    Iterator<Obs> obsIterator = encounter.getObs().iterator();

    Map<String, Obs> map = new HashMap<String, Obs>();
    while (obsIterator.hasNext()) {
      Obs obs = obsIterator.next();
      map.put(obs.getConcept().getDatatype().getHl7Abbreviation(), obs);
    }
    Obs textObservation = map.get(ConceptDatatype.TEXT);
    assertEquals("text value", textObservation.getValueText());
    assertEquals("a76e8d23-0c38-408c-b2a8-ea5540f01b51", textObservation.getPerson().getUuid());
    assertEquals("e102c80f-1yz9-4da3-bb88-8122ce8868dd", textObservation.getConcept().getUuid());
    assertEquals("f13d6fae-baa9-4553-955d-920098bec08f", textObservation.getEncounter().getUuid());
    assertEquals("overweight", textObservation.getComment());
    //        TODO : change the observation startTime logic to take current time as start time when
    // startTime is not passed by the client
    //        assertEquals(DateUtils.parseDate(encounterDateTime, dateTimeFormat),
    // textObservation.getObsDatetime());

    assertEquals(
        "e7167090-a067-11e3-a5e2-0800200c9a66",
        map.get(ConceptDatatype.CODED).getValueCoded().getUuid());
    assertEquals(new Double(20.0), map.get(ConceptDatatype.NUMERIC).getValueNumeric());
  }
  @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);
  }
  @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());
  }
  @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);
  }
  private boolean shouldBeClosed(Visit visit) {

    if (visit.getStopDatetime() != null) {
      return false; // already closed
    }

    VisitDomainWrapper visitDomainWrapper = domainWrapperFactory.newVisitDomainWrapper(visit);

    if (visitDomainWrapper.isAdmitted() || visitDomainWrapper.isAwaitingAdmission()) {
      return false; // don't close the visit if patient is admitted or waiting admission
    }

    Disposition mostRecentDisposition = visitDomainWrapper.getMostRecentDisposition();
    if (mostRecentDisposition != null
        && mostRecentDisposition.getKeepsVisitOpen() != null
        && mostRecentDisposition.getKeepsVisitOpen()) {
      return false; // don't close the visit if the most recent disposition is one that keeps visit
                    // opens
    }

    Date now = new Date();
    Date mustHaveSomethingAfter = DateUtils.addHours(now, -emrApiProperties.getVisitExpireHours());

    if (OpenmrsUtil.compare(visit.getStartDatetime(), mustHaveSomethingAfter) >= 0) {
      return false;
    }

    if (visit.getEncounters() != null) {
      for (Encounter candidate : visit.getEncounters()) {
        if (OpenmrsUtil.compare(candidate.getEncounterDatetime(), mustHaveSomethingAfter) >= 0) {
          return false;
        }
      }
    }

    return true;
  }
  @Test
  public void shouldUpdateObservations() throws Exception {
    executeDataSet("shouldUpdateObservations.xml");

    String json =
        "{ \"patientUuid\" : \"a76e8d23-0c38-408c-b2a8-ea5540f01b51\", "
            + "\"visitTypeUuid\" : \"b45ca846-c79a-11e2-b0c0-8e397087571c\", "
            + "\"encounterTypeUuid\": \"2b377dba-62c3-4e53-91ef-b51c68899890\","
            + "\"encounterDateTime\" : \"2013-01-01T00:00:00.000+0000\", "
            + "\"observations\":["
            + "{\"uuid\":\"z9fb7f47-e80a-4056-9285-bd798be13c63\", "
            + " \"groupMembers\" : [{\"uuid\":\"ze48cdcb-6a76-47e3-9f2e-2635032f3a9a\", \"value\":20, \"comment\":\"new gc\" }] }, "
            + "{\"uuid\":\"zf616900-5e7c-4667-9a7f-dcb260abf1de\", \"comment\" : \"new c\", \"value\":100 }"
            + "]}";

    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(2, encounter.getObsAtTopLevel(false).size());
    Iterator<Obs> iterator = encounter.getObsAtTopLevel(false).iterator();

    Obs obs1 = iterator.next();
    assertEquals("zf616900-5e7c-4667-9a7f-dcb260abf1de", obs1.getUuid());
    assertEquals(new Double(100), obs1.getValueNumeric());
    assertEquals("new c", obs1.getComment());

    Obs obs2 = iterator.next();
    assertEquals("z9fb7f47-e80a-4056-9285-bd798be13c63", obs2.getUuid());
    assertEquals(1, obs2.getGroupMembers().size());
    Obs member = obs2.getGroupMembers().iterator().next();
    assertEquals(new Double(20), member.getValueNumeric());
    assertEquals("new gc", member.getComment());
  }
  /** @see EmrVisitAssignmentHandler#checkLocations(org.openmrs.Visit, org.openmrs.Encounter) */
  @Test
  public void checkLocations() {
    Patient patient = TestUtils.getPatient(7);
    Form moh257 = MetadataUtils.getForm(HivMetadata._Form.MOH_257_VISIT_SUMMARY);
    VisitType outpatient = MetadataUtils.getVisitType(CommonMetadata._VisitType.OUTPATIENT);

    // Save regular visit on Jan 1st at no specific location
    Visit visit0 = TestUtils.saveVisit(patient, outpatient, TestUtils.date(2012, 1, 1), null);

    // Save regular visit on Jan 1st at location #2
    Visit visit1 = TestUtils.saveVisit(patient, outpatient, TestUtils.date(2012, 1, 1), null);
    visit1.setLocation(Context.getLocationService().getLocation(1));

    // Save regular visit on Jan 1st at location #2
    Visit visit2 = TestUtils.saveVisit(patient, outpatient, TestUtils.date(2012, 1, 1), null);
    visit2.setLocation(Context.getLocationService().getLocation(2));

    // Save MOH257 for that day (will default to location #1)
    Encounter encounter = TestUtils.saveEncounter(patient, moh257, TestUtils.date(2012, 1, 1));

    Assert.assertThat(EmrVisitAssignmentHandler.checkLocations(visit0, encounter), is(true));
    Assert.assertThat(EmrVisitAssignmentHandler.checkLocations(visit1, encounter), is(true));
    Assert.assertThat(EmrVisitAssignmentHandler.checkLocations(visit2, encounter), is(false));
  }
 @Override
 public boolean visitsOverlap(Visit v1, Visit v2) {
   Location where1 = v1.getLocation();
   Location where2 = v2.getLocation();
   if ((where1 == null && where2 == null)
       || isSameOrAncestor(where1, where2)
       || isSameOrAncestor(where2, where1)) {
     // "same" location, so check if date ranges overlap (assuming startDatetime is never null)
     return (OpenmrsUtil.compareWithNullAsLatest(v1.getStartDatetime(), v2.getStopDatetime()) <= 0)
         && (OpenmrsUtil.compareWithNullAsLatest(v2.getStartDatetime(), v1.getStopDatetime())
             <= 0);
   }
   return false;
 }
 @Override
 @Transactional
 public void closeAndSaveVisit(Visit visit) {
   visit.setStopDatetime(guessVisitStopDatetime(visit));
   visitService.saveVisit(visit);
 }
 private boolean itBelongsToARealPatient(Visit candidate) {
   Patient patient = candidate.getPatient();
   PatientDomainWrapper domainWrapper =
       new PatientDomainWrapper(patient, emrApiProperties, null, null, null, null);
   return !domainWrapper.isTestPatient();
 }
  @Transactional
  @Override
  public void mergePatients(Patient preferred, Patient notPreferred) {
    boolean preferredWasUnknown =
        domainWrapperFactory.newPatientDomainWrapper(preferred).isUnknownPatient();
    boolean notPreferredWasUnknown =
        domainWrapperFactory.newPatientDomainWrapper(notPreferred).isUnknownPatient();
    if (preferredWasUnknown && !notPreferredWasUnknown) {
      throw new IllegalArgumentException("Cannot merge a permanent record into an unknown one");
    }

    List<Visit> preferredVisits = visitService.getVisitsByPatient(preferred, true, false);
    List<Visit> notPreferredVisits = visitService.getVisitsByPatient(notPreferred, true, false);

    // if the non-preferred patient has any visits that overlap with visits of the preferred
    // patient, we need to merge them together
    for (Visit losing : notPreferredVisits) {
      if (!losing.isVoided()) {
        for (Visit winning : preferredVisits) {
          if (!winning.isVoided() && visitsOverlap(losing, winning)) {
            mergeVisits(winning, losing);
            break;
          }
        }
      }
    }

    // merging in visits from the non-preferred patient (and extending visit durations) may have
    // caused preferred-patient visits to overlap
    Collections.sort(
        preferredVisits,
        new Comparator<Visit>() {
          @Override
          public int compare(Visit left, Visit right) {
            return OpenmrsUtil.compareWithNullAsEarliest(
                left.getStartDatetime(), right.getStartDatetime());
          }
        });
    for (int i = 0; i < preferredVisits.size(); ++i) {
      Visit visit = preferredVisits.get(i);
      if (!visit.isVoided()) {
        for (int j = i + 1; j < preferredVisits.size(); ++j) {
          Visit candidate = preferredVisits.get(j);
          if (!candidate.isVoided() && visitsOverlap(visit, candidate)) {
            mergeVisits(visit, candidate);
          }
        }
      }
    }

    if (patientMergeActions != null) {
      for (PatientMergeAction patientMergeAction : patientMergeActions) {
        patientMergeAction.beforeMergingPatients(preferred, notPreferred);
      }
    }

    try {
      patientService.mergePatients(preferred, notPreferred);
      // if we merged an unknown record into a permanent one, remove the unknown flag; if we merged
      // two unknown records, keep it
      if (!preferredWasUnknown) {
        removeAttributeOfUnknownPatient(preferred);
      }
    } catch (SerializationException e) {
      throw new APIException("Unable to merge patients due to serialization error", e);
    }

    if (patientMergeActions != null) {
      for (PatientMergeAction patientMergeAction : patientMergeActions) {
        patientMergeAction.afterMergingPatients(preferred, notPreferred);
      }
    }
  }
  public Visit mergeVisits(Visit preferred, Visit nonPreferred) {
    // extend date range of winning
    if (OpenmrsUtil.compareWithNullAsEarliest(
            nonPreferred.getStartDatetime(), preferred.getStartDatetime())
        < 0) {
      preferred.setStartDatetime(nonPreferred.getStartDatetime());
    }
    if (preferred.getStopDatetime() != null
        && OpenmrsUtil.compareWithNullAsLatest(
                preferred.getStopDatetime(), nonPreferred.getStopDatetime())
            < 0) {
      preferred.setStopDatetime(nonPreferred.getStopDatetime());
    }

    // move encounters from losing into winning
    if (nonPreferred.getEncounters() != null) {
      for (Encounter e : nonPreferred.getEncounters()) {
        e.setPatient(preferred.getPatient());
        preferred.addEncounter(e);
        encounterService.saveEncounter(e);
      }
    }
    nonPreferred.setEncounters(
        null); // we need to manually the encounters from the non-preferred visit before voiding or
               // all the encounters we just moved will also get voided!

    visitService.voidVisit(
        nonPreferred, "EMR - Merge Patients: merged into visit " + preferred.getVisitId());
    visitService.saveVisit(preferred);
    return preferred;
  }