/** @see {@link ExistingOrNewVisitAssignmentHandler#beforeCreateEncounter(Encounter)} */
  @Test
  @Verifies(
      value = "should resolve encounter and visit type uuids as global property values",
      method = "beforeCreateEncounter(Encounter)")
  public void beforeCreateEncounter_shouldResolveEncounterAndVisitTypeUuidsAsGlobalPropertyValues()
      throws Exception {
    final String encounterTypeUuid = "759799ab-c9a5-435e-b671-77773ada74e4";
    final String visitTypeUuid = "c0c579b0-8e59-401d-8a4a-976a0b183519";
    Encounter encounter = Context.getEncounterService().getEncounter(1);
    Assert.assertNull(encounter.getVisit());
    Assert.assertEquals(encounterTypeUuid, encounter.getEncounterType().getUuid());

    Calendar calendar = Calendar.getInstance();
    calendar.setTime(encounter.getEncounterDatetime());
    calendar.set(Calendar.YEAR, 1900);

    encounter.setEncounterDatetime(calendar.getTime());

    GlobalProperty gp =
        new GlobalProperty(
            OpenmrsConstants.GP_ENCOUNTER_TYPE_TO_VISIT_TYPE_MAPPING,
            encounterTypeUuid + ":" + visitTypeUuid);
    Context.getAdministrationService().saveGlobalProperty(gp);

    new ExistingOrNewVisitAssignmentHandler().beforeCreateEncounter(encounter);

    Assert.assertNotNull(encounter.getVisit());

    // should be set according toencounterTypeUuid:visitTypeUuid
    Assert.assertEquals(1, encounter.getEncounterType().getEncounterTypeId().intValue());
    Assert.assertEquals(
        Context.getVisitService().getVisitTypeByUuid(visitTypeUuid),
        encounter.getVisit().getVisitType());
  }
  /** @see {@link ExistingVisitAssignmentHandler#beforeCreateEncounter(Encounter)} */
  @Test
  @Verifies(
      value = "should assign mapping global property visit type",
      method = "beforeCreateEncounter(Encounter)")
  public void beforeCreateEncounter_shouldAssignMappingGlobalPropertyVisitType() throws Exception {
    Encounter encounter = Context.getEncounterService().getEncounter(1);
    Assert.assertNull(encounter.getVisit());

    Calendar calendar = Calendar.getInstance();
    calendar.setTime(encounter.getEncounterDatetime());
    calendar.set(Calendar.YEAR, 1900);

    encounter.setEncounterDatetime(calendar.getTime());

    GlobalProperty gp =
        new GlobalProperty(
            OpenmrsConstants.GP_ENCOUNTER_TYPE_TO_VISIT_TYPE_MAPPING, "3:4, 5:2, 1:2, 2:2");
    Context.getAdministrationService().saveGlobalProperty(gp);

    new ExistingOrNewVisitAssignmentHandler().beforeCreateEncounter(encounter);

    Assert.assertNotNull(encounter.getVisit());

    // should be set according to: 1:2 encounterTypeId:visitTypeId
    Assert.assertEquals(1, encounter.getEncounterType().getEncounterTypeId().intValue());
    Assert.assertEquals(
        Context.getVisitService().getVisitType(2), encounter.getVisit().getVisitType());
  }
  /** @see {@link ExistingVisitAssignmentHandler#beforeCreateEncounter(Encounter)} */
  @Test
  @Verifies(
      value = "should assign existing visit if match found",
      method = "beforeCreateEncounter(Encounter)")
  public void beforeCreateEncounter_shouldAssignExistingVisitIfMatchFound() throws Exception {
    Encounter encounter = Context.getEncounterService().getEncounter(1);
    Assert.assertNull(encounter.getVisit());

    new ExistingOrNewVisitAssignmentHandler().beforeCreateEncounter(encounter);

    Assert.assertNotNull(encounter.getVisit());
  }
  /**
   * 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.");
      }
    }
  }
  /** @see {@link ExistingVisitAssignmentHandler#beforeCreateEncounter(Encounter)} */
  @Test
  @Verifies(
      value = "should assign new visit if no match found",
      method = "beforeCreateEncounter(Encounter)")
  public void beforeCreateEncounter_shouldAssignNewVisitIfNoMatchFound() throws Exception {
    Encounter encounter = Context.getEncounterService().getEncounter(1);
    Assert.assertNull(encounter.getVisit());

    Calendar calendar = Calendar.getInstance();
    calendar.setTime(encounter.getEncounterDatetime());
    calendar.set(Calendar.YEAR, 1900);

    encounter.setEncounterDatetime(calendar.getTime());

    new ExistingOrNewVisitAssignmentHandler().beforeCreateEncounter(encounter);

    Assert.assertNotNull(encounter.getVisit());
  }
  /** @see {@link ExistingVisitAssignmentHandler#beforeCreateEncounter(Encounter)} */
  @Test
  @Verifies(
      value = "should assign first visit type if mapping global property is not set",
      method = "beforeCreateEncounter(Encounter)")
  public void beforeCreateEncounter_shouldAssignFirstVisitTypeIfMappingGlobalPropertyIsNotSet()
      throws Exception {
    VisitType visitType = Context.getVisitService().getAllVisitTypes().get(0);

    Encounter encounter = Context.getEncounterService().getEncounter(1);
    Assert.assertNull(encounter.getVisit());

    Calendar calendar = Calendar.getInstance();
    calendar.setTime(encounter.getEncounterDatetime());
    calendar.set(Calendar.YEAR, 1900);

    encounter.setEncounterDatetime(calendar.getTime());

    new ExistingOrNewVisitAssignmentHandler().beforeCreateEncounter(encounter);

    Assert.assertNotNull(encounter.getVisit());
    Assert.assertEquals(visitType, encounter.getVisit().getVisitType());
  }
  @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);
  }
  /**
   * 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;
  }
  /** @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;
  }
 @Before
 public void init() {
   initMocks(this);
   when(encounter.getVisit()).thenReturn(new Visit());
 }