@Override
  public void action(
      EncounterDomainWrapper encounterDomainWrapper,
      Obs dispositionObsGroupBeingCreated,
      Map<String, String[]> requestParameters) {

    if (encounterDomainWrapper.getVisit() == null) {
      return;
    }

    VisitDomainWrapper visitDomainWrapper = adtService.wrap(encounterDomainWrapper.getVisit());

    // if this is an active visit, we close it... *as long as* there are no subsequent encounters on
    // following days
    // (if there are subsequent encounters on following days, this is some sort of retrospective
    // entry, and we can't
    // determine exactly what should happen, so just do nothing)

    if (visitDomainWrapper.isActive()) {
      Date mostRecentEncounterDatetime =
          visitDomainWrapper.getMostRecentEncounter().getEncounterDatetime();

      if (!new DateMidnight(mostRecentEncounterDatetime)
          .isAfter(new DateMidnight(encounterDomainWrapper.getEncounterDatetime()))) {
        visitDomainWrapper.closeOnLastEncounterDatetime();
        visitService.saveVisit(visitDomainWrapper.getVisit());
      }
    }
  }
  @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));
  }
  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;
  }
  @Transactional
  public Visit ensureVisit(Patient patient, Date visitTime, Location department) {
    if (visitTime == null) {
      visitTime = new Date();
    }
    Visit visit = null;
    List<Patient> patientList = Collections.singletonList(patient);

    // visits that have not ended by the encounter date.
    List<Visit> candidates =
        visitService.getVisits(
            null, patientList, null, null, null, visitTime, null, null, null, true, false);
    if (candidates != null) {
      for (Visit candidate : candidates) {
        if (isSuitableVisit(candidate, department, visitTime)) {
          return candidate;
        }
      }
    }
    if (visit == null) {
      visit = buildVisit(patient, department, visitTime);
      visitService.saveVisit(visit);
    }
    return visit;
  }
 @Override
 @Transactional
 public Visit ensureActiveVisit(Patient patient, Location department) {
   Visit activeVisit = getActiveVisitHelper(patient, department);
   if (activeVisit == null) {
     Date now = new Date();
     activeVisit = buildVisit(patient, department, now);
     visitService.saveVisit(activeVisit);
   }
   return activeVisit;
 }
 @Override
 @Transactional
 public void closeAndSaveVisit(Visit visit) {
   visit.setStopDatetime(guessVisitStopDatetime(visit));
   visitService.saveVisit(visit);
 }