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;
  }
 @Override
 @Deprecated // use new VisitDomainWrapperFactory instead (this service method has been delegated
             // to use the new factory)
 public VisitDomainWrapper wrap(Visit visit) {
   return domainWrapperFactory.newVisitDomainWrapper(visit);
 }
  @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);
      }
    }
  }