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;
  }
  @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));
  }
 @Override
 @Transactional
 public void closeAndSaveVisit(Visit visit) {
   visit.setStopDatetime(guessVisitStopDatetime(visit));
   visitService.saveVisit(visit);
 }