Package org.openmrs.module.htmlformentry.element

Source Code of org.openmrs.module.htmlformentry.element.PatientDetailSubmissionElement

/**
* The contents of this file are subject to the OpenMRS Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC.  All Rights Reserved.
*/
package org.openmrs.module.htmlformentry.element;

import org.openmrs.Location;
import org.openmrs.Patient;
import org.openmrs.PatientIdentifier;
import org.openmrs.PatientIdentifierType;
import org.openmrs.Person;
import org.openmrs.PersonAddress;
import org.openmrs.PersonName;
import org.openmrs.api.IdentifierNotUniqueException;
import org.openmrs.api.context.Context;
import org.openmrs.messagesource.MessageSourceService;
import org.openmrs.module.htmlformentry.FormEntryContext;
import org.openmrs.module.htmlformentry.FormEntryContext.Mode;
import org.openmrs.module.htmlformentry.FormEntrySession;
import org.openmrs.module.htmlformentry.FormSubmissionError;
import org.openmrs.module.htmlformentry.HtmlFormEntryUtil;
import org.openmrs.module.htmlformentry.ValidationException;
import org.openmrs.module.htmlformentry.action.FormSubmissionControllerAction;
import org.openmrs.module.htmlformentry.comparator.OptionComparator;
import org.openmrs.module.htmlformentry.widget.AddressWidget;
import org.openmrs.module.htmlformentry.widget.DateWidget;
import org.openmrs.module.htmlformentry.widget.DropdownWidget;
import org.openmrs.module.htmlformentry.widget.ErrorWidget;
import org.openmrs.module.htmlformentry.widget.HiddenFieldWidget;
import org.openmrs.module.htmlformentry.widget.NameWidget;
import org.openmrs.module.htmlformentry.widget.NumberFieldWidget;
import org.openmrs.module.htmlformentry.widget.Option;
import org.openmrs.module.htmlformentry.widget.TextFieldWidget;
import org.openmrs.module.htmlformentry.widget.Widget;
import org.openmrs.util.OpenmrsUtil;
import org.openmrs.validator.PatientIdentifierValidator;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
* Holds the widgets used to represent Patient Details, and serves as both the
* HtmlGeneratorElement and the FormSubmissionControllerAction for Patient
* Details.
*/
public class PatientDetailSubmissionElement implements HtmlGeneratorElement, FormSubmissionControllerAction {

  public static final String FIELD_PERSON_NAME = "name";

  public static final String FIELD_BIRTH_DATE_OR_AGE = "birthDateOrAge";

  public static final String FIELD_BIRTH_DATE = "birthDate";

  public static final String FIELD_AGE = "age";

  public static final String FIELD_GENDER = "gender";

  public static final String FIELD_IDENTIFIER = "identifier";

  public static final String FIELD_IDENTIFIER_LOCATION = "identifierLocation";

  public static final String FIELD_ADDRESS = "address";

  private NameWidget nameWidget;
  private ErrorWidget nameErrorWidget;
  private DropdownWidget genderWidget;
  private ErrorWidget genderErrorWidget;
  private Widget ageWidget;
  private ErrorWidget ageErrorWidget;
  private Widget birthDateWidget;
  private ErrorWidget birthDateErrorWidget;
  private Widget identifierTypeWidget;
  private Widget identifierTypeValueWidget;
  private ErrorWidget identifierTypeValueErrorWidget;
  private Widget identifierLocationWidget;
  private ErrorWidget identifierLocationErrorWidget;
  private AddressWidget addressWidget;

  private boolean required;

  public PatientDetailSubmissionElement(FormEntryContext context, Map<String, String> attributes) {
    createElement(context, attributes);
  }

  public void createElement(FormEntryContext context, Map<String, String> attributes) {
    String field = attributes.get("field");
    Patient existingPatient = context.getExistingPatient();

    // Required attribute defaults to true if not specified
    required = ! "false".equalsIgnoreCase(attributes.get("required"));

    if (FIELD_PERSON_NAME.equalsIgnoreCase(field)) {
      nameWidget = new NameWidget();
      nameErrorWidget = new ErrorWidget();
      createWidgets(context, nameWidget, nameErrorWidget,
          existingPatient != null && existingPatient.getPersonName() != null ? existingPatient.getPersonName() : null);
    }
    else if (FIELD_GENDER.equalsIgnoreCase(field)) {
      MessageSourceService msg = Context.getMessageSourceService();
      genderWidget = new DropdownWidget();
      genderErrorWidget = new ErrorWidget();
      genderWidget.addOption(new Option(msg.getMessage("Patient.gender.male"), "M", false));
      genderWidget.addOption(new Option(msg.getMessage("Patient.gender.female"), "F", false));
      createWidgets(context, genderWidget, genderErrorWidget, existingPatient != null ? existingPatient.getGender() : null);
    }
    else if (FIELD_AGE.equalsIgnoreCase(field)) {
      ageWidget = new NumberFieldWidget(0d, 200d, false);
      ageErrorWidget = new ErrorWidget();
      createWidgets(context, ageWidget, ageErrorWidget, existingPatient != null ? existingPatient.getAge() : null);
    }
    else if (FIELD_BIRTH_DATE.equalsIgnoreCase(field)) {
      birthDateWidget = new DateWidget();
      birthDateErrorWidget = new ErrorWidget();
      createWidgets(context, birthDateWidget, birthDateErrorWidget, existingPatient != null ? existingPatient.getBirthdate() : null);
    }
    else if (FIELD_BIRTH_DATE_OR_AGE.equalsIgnoreCase(field)) {
      ageWidget = new NumberFieldWidget(0d, 200d, false);
      ageErrorWidget = new ErrorWidget();
      createWidgets(context, ageWidget, ageErrorWidget, existingPatient != null ? existingPatient.getAge() : null);

      birthDateWidget = new DateWidget();
      birthDateErrorWidget = new ErrorWidget();
      createWidgets(context, birthDateWidget, birthDateErrorWidget, existingPatient != null ? existingPatient.getBirthdate() : null);

    }
    else if (FIELD_IDENTIFIER.equalsIgnoreCase(field)) {

      PatientIdentifierType idType = HtmlFormEntryUtil.getPatientIdentifierType(attributes.get("identifierTypeId"));
     
      identifierTypeValueWidget = new TextFieldWidget();
      identifierTypeValueErrorWidget = new ErrorWidget();
      String initialValue = null;
      if (existingPatient != null) {
        if (idType == null) {
          if (existingPatient.getPatientIdentifier() != null) {
            initialValue = existingPatient.getPatientIdentifier().getIdentifier();
          }
        } else {
          if (existingPatient.getPatientIdentifier(idType) != null) {
            initialValue = existingPatient.getPatientIdentifier(idType).getIdentifier();
          }
        }
      }
      createWidgets(context, identifierTypeValueWidget, identifierTypeValueErrorWidget, initialValue);

      if (idType != null) {
        identifierTypeWidget = new HiddenFieldWidget();
        createWidgets(context, identifierTypeWidget, null, idType.getId().toString());
      }
      else {
        identifierTypeWidget = new DropdownWidget();
        List<PatientIdentifierType> patientIdentifierTypes = HtmlFormEntryUtil.getPatientIdentifierTypes();

        for (PatientIdentifierType patientIdentifierType : patientIdentifierTypes) {
          ((DropdownWidget) identifierTypeWidget).addOption(new Option(patientIdentifierType.getName(), patientIdentifierType
              .getPatientIdentifierTypeId().toString(), false));
        }

        createWidgets(context, identifierTypeWidget, null,
            existingPatient != null && existingPatient.getPatientIdentifier() != null ? existingPatient.getPatientIdentifier()
                .getIdentifierType().getId() : null);
      }
    }
    else if (FIELD_IDENTIFIER_LOCATION.equalsIgnoreCase(field)) {
      identifierLocationWidget = new DropdownWidget();
      identifierLocationErrorWidget = new ErrorWidget();

            Location defaultLocation = existingPatient != null
          && existingPatient.getPatientIdentifier() != null ? existingPatient.getPatientIdentifier().getLocation() : null;
      defaultLocation = defaultLocation == null ? context.getDefaultLocation() : defaultLocation;
            identifierLocationWidget.setInitialValue(defaultLocation);

            List<Option> locationOptions = new ArrayList<Option>();
            for(Location location:Context.getLocationService().getAllLocations()) {
                Option option = new Option(location.getName(), location.getId().toString(), location.equals(defaultLocation));
                locationOptions.add(option);
            }
            Collections.sort(locationOptions, new OptionComparator());

            // if initialValueIsSet=false, no initial/default location, hence this shows the 'select input' field as first option
            boolean initialValueIsSet = !(defaultLocation == null);
            ((DropdownWidget) identifierLocationWidget).addOption(new Option(Context.getMessageSourceService().getMessage("htmlformentry.chooseALocation"), "", !initialValueIsSet));
            if (!locationOptions.isEmpty()) {
                    for(Option option: locationOptions){
                    ((DropdownWidget) identifierLocationWidget).addOption(option);
                    }
            }
      createWidgets(context, identifierLocationWidget, identifierLocationErrorWidget, defaultLocation);
    }

    else if (FIELD_ADDRESS.equalsIgnoreCase(field)) {
      addressWidget = new AddressWidget();
      createWidgets(context, addressWidget, null, existingPatient != null ? existingPatient.getPersonAddress() : null);
    }
  }

  private void createWidgets(FormEntryContext context, Widget fieldWidget, ErrorWidget errorWidget, Object initialValue) {
    context.registerWidget(fieldWidget);
    if (errorWidget != null) {
      context.registerErrorWidget(fieldWidget, errorWidget);
    }
    if (initialValue != null && StringUtils.hasText(initialValue.toString())) {
      fieldWidget.setInitialValue(initialValue);
    }
  }

  @Override
  public String generateHtml(FormEntryContext context) {
    StringBuilder sb = new StringBuilder();
    MessageSourceService mss = Context.getMessageSourceService();

    if (nameWidget != null) {
      sb.append(nameWidget.generateHtml(context));
      if (context.getMode() != Mode.VIEW)
        sb.append(nameErrorWidget.generateHtml(context));
    }

    if (genderWidget != null) {
      sb.append(genderWidget.generateHtml(context));
      if (context.getMode() != Mode.VIEW)
        sb.append(genderErrorWidget.generateHtml(context));
    }

    if (birthDateWidget != null) {
      if (ageWidget != null) {
        sb.append(mss.getMessage("Person.birthdate")).append(" ");
      }
      sb.append(birthDateWidget.generateHtml(context));
      if (context.getMode() != Mode.VIEW)
        sb.append(birthDateErrorWidget.generateHtml(context));
    }

    if (ageWidget != null) {
      if (birthDateWidget != null) {
        sb.append(" ").append(mss.getMessage("Person.age.or")).append(" ");
      }     
      sb.append(ageWidget.generateHtml(context));
      if (context.getMode() != Mode.VIEW)
        sb.append(ageErrorWidget.generateHtml(context));
    }

   

    if (identifierTypeValueWidget != null) {
      sb.append(identifierTypeValueWidget.generateHtml(context));
      if (context.getMode() != Mode.VIEW) {
        // if value is required
        if (required) {
          sb.append("<span class='required'>*</span>");
        }

        sb.append(" ");
        sb.append(identifierTypeValueErrorWidget.generateHtml(context));
      }
    }
   
    if (identifierTypeWidget != null) {
      if (identifierTypeValueWidget instanceof DropdownWidget){       
        sb.append(" ").append(mss.getMessage("PatientIdentifier.identifierType")).append(" ");
      }
      sb.append(identifierTypeWidget.generateHtml(context)).append(" ");
    }

    if (identifierLocationWidget != null) {
      sb.append(identifierLocationWidget.generateHtml(context));
      if (context.getMode() != Mode.VIEW)
        sb.append(identifierLocationErrorWidget.generateHtml(context));
    }

    if (addressWidget != null) {
      sb.append(addressWidget.generateHtml(context));
    }

    return sb.toString();
  }

  @Override
  public void handleSubmission(FormEntrySession session, HttpServletRequest request) {

    Patient patient = (Patient) session.getSubmissionActions().getCurrentPerson();

    if (patient == null) {
      throw new RuntimeException("Programming exception: person shouldn't be null");
    }

    FormEntryContext context = session.getContext();

    if (nameWidget != null) {
      PersonName name = (PersonName) nameWidget.getValue(context, request);

      if (patient != null) {
        if (!name.isPreferred()) {
          PersonName currentPreferredName = context.getExistingPatient().getPersonName();
          if (currentPreferredName != null){
            currentPreferredName.setPreferred(false);
            currentPreferredName.setVoided(true);
          }
        }
      }
     
      // HACK: we need to set the date created and uuid here as a hack around a hibernate flushing issue (see saving the Patient in FormEntrySession applyActions())
      if (name.getDateCreated() == null) {
        name.setDateCreated(new Date());
      }
      if (name.getUuid() == null) {
        name.setUuid(UUID.randomUUID().toString());
      }
     
     
      name.setPreferred(true);
      patient.addName(name);
    }

    if (genderWidget != null) {
      String value = (String) genderWidget.getValue(context, request);
      patient.setGender(value);
    }

    if (ageWidget != null) {
      Double value = (Double) ageWidget.getValue(context, request);
      if (value != null)
        calculateBirthDate(patient, null, value);
    }

    if (birthDateWidget != null) {
      Date value = (Date) birthDateWidget.getValue(context, request);
      if (value != null) {
        calculateBirthDate(patient, value, null);
      }
    }
    if (identifierTypeValueWidget != null && identifierTypeWidget != null) {
      String identifier = (String) identifierTypeValueWidget.getValue(context, request);
      PatientIdentifierType identifierType = getIdentifierType((String) identifierTypeWidget.getValue(context, request));

      // Look for an existing identifier of this type
      PatientIdentifier patientIdentifier = patient.getPatientIdentifier(identifierType);

      if (StringUtils.hasText(identifier)) {
        // No existing identifier of this type, so create new
        if (patientIdentifier == null) {
          patientIdentifier = new PatientIdentifier();
          patientIdentifier.setIdentifierType(identifierType);

          // HACK: we need to set the date created  and uuid here as a hack around a hibernate flushing issue (see saving the Patient in FormEntrySession applyActions())
          patientIdentifier.setDateChanged(new Date());
          patientIdentifier.setUuid(UUID.randomUUID().toString());

          // For 1.9+ onwards patients require a preferred identifier
          if (patient.getPatientId() == null) {
            patientIdentifier.setPreferred(true);
          }

          patient.addIdentifier(patientIdentifier);
        }

        if (!identifier.equals(patientIdentifier.getIdentifier()) || !identifierType.equals(patientIdentifier.getIdentifierType())) {
          validateIdentifier(identifierType.getId(), identifier);
        }

        patientIdentifier.setIdentifier(identifier);
      }
      else if (patientIdentifier != null) {
        // If this field is not required, then we interpret a blank value as a request to avoid any existing identifier
        session.getSubmissionActions().getIdentifiersToVoid().add(patientIdentifier);
      }
    }

    //
    // TODO current behavior always updates location of the preferred identifier rather than
    // a specific identifier type being edited by the identifier widget. But identifier location
    // widget isn't aware of the identifier type widget
    //
    if (identifierLocationWidget != null) {
      PatientIdentifier patientIdentifier = patient.getPatientIdentifier();
      if (patientIdentifier == null) {
        patientIdentifier = new PatientIdentifier();
        patient.addIdentifier(patientIdentifier);
      }

      Object locationString = identifierLocationWidget.getValue(context, request);
      Location location = (Location) HtmlFormEntryUtil.convertToType(locationString.toString().trim(), Location.class);
      patientIdentifier.setLocation(location);
      patientIdentifier.setPreferred(true);

    }

    if (addressWidget != null) {
      PersonAddress personAddress = (PersonAddress) addressWidget.getValue(context, request);
      if (context.getMode() == Mode.EDIT) {
        if (!personAddress.isPreferred()) {
          PersonAddress currentPreferredAddress = context.getExistingPatient().getPersonAddress();
          currentPreferredAddress.setPreferred(false);
          currentPreferredAddress.setVoided(true);
        }
      }
      personAddress.setPreferred(true);
      patient.addAddress(personAddress);
    }

        session.getSubmissionActions().setPatientUpdateRequired(true);
  }

  private void validateIdentifier(Integer identifierType, String identifier) {
    if (identifierType != null && identifier != null) {
      try {
        PatientIdentifier pi = new PatientIdentifier();

        pi.setIdentifier(identifier);
        pi.setIdentifierType(getIdentifierType(identifierType.toString()));

        // note that this is a bit of a hack; we can't call the PatientIdentifierValidator.validateIdentifier(identifier) method
        // because it (as of 1.8) also tests to make sure that an identifier has a location associated with it; when validating an
        // individual identifier widget, there will be no location because the location is collected in another widget
        PatientIdentifierValidator.validateIdentifier(pi.getIdentifier(), pi.getIdentifierType());
       
        if (Context.getPatientService().isIdentifierInUseByAnotherPatient(pi)) {
          throw new IdentifierNotUniqueException(Context.getMessageSourceService().getMessage(
              "PatientIdentifier.error.notUniqueWithParameter", new Object[] { pi.getIdentifier() },
              Context.getLocale()));
        }
      }
      catch (Exception e) {
        throw new ValidationException(e.getMessage());
      }
    }
  }

  private PatientIdentifierType getIdentifierType(String id) {
    PatientIdentifierType patientIdentifierType = Context.getPatientService().getPatientIdentifierType(new Integer(id));
    if (patientIdentifierType == null) {
      throw new RuntimeException("Invalid identifierTypeId given " + id);
    }
    return patientIdentifierType;
  }

  @SuppressWarnings("unused")
    @Override
  public Collection<FormSubmissionError> validateSubmission(FormEntryContext context, HttpServletRequest request) {
    List<FormSubmissionError> ret = new ArrayList<FormSubmissionError>();

    List<FormSubmissionError> ageOrBirthdDateErrorMessage = new ArrayList<FormSubmissionError>();

    validateMandatoryField(context, request, genderWidget, genderErrorWidget, ret);

    if (required) {
      validateMandatoryField(context, request, identifierTypeValueWidget, identifierTypeValueErrorWidget, ret);
    }

    validateMandatoryField(context, request, identifierLocationWidget, identifierLocationErrorWidget, ret);

    if(nameWidget != null){
      PersonName personName = nameWidget.getValue(context, request);
      if(!StringUtils.hasText(personName.getGivenName()) || !StringUtils.hasText(personName.getFamilyName())){
        ret.add(new FormSubmissionError(context.getFieldName(nameErrorWidget), Context.getMessageSourceService().getMessage("htmlformentry.error.name.required")));
      }
    }
   
    if (ageWidget != null && validateMandatoryField(context, request, ageWidget, ageErrorWidget, ageOrBirthdDateErrorMessage)) {
      try {
        Number value = (Number) ageWidget.getValue(context, request);
      }
      catch (Exception e) {
        ret.add(new FormSubmissionError(context.getFieldName(ageErrorWidget), e.getMessage()));
      }
    }

    if (birthDateWidget != null
        && validateMandatoryField(context, request, birthDateWidget, birthDateErrorWidget, ageOrBirthdDateErrorMessage)) {
      try {
        if (birthDateWidget.getValue(context, request) != null
            && OpenmrsUtil.compare((Date) birthDateWidget.getValue(context, request), new Date()) > 0) {
          ret.add(new FormSubmissionError(context.getFieldName(birthDateErrorWidget), Context.getMessageSourceService().getMessage(
              "htmlformentry.error.cannotBeInFuture")));
        }
      }
      catch (Exception e) {
        ret.add(new FormSubmissionError(context.getFieldName(birthDateErrorWidget), e.getMessage()));
      }
    }

    if (ageWidget != null && birthDateWidget != null) {
      if (ageOrBirthdDateErrorMessage.size() > 1) {
        ret.add(new FormSubmissionError(context.getFieldName(ageErrorWidget), Context.getMessageSourceService().getMessage(
            "Person.birthdate.required")));
      }
    }
    else {
      ret.addAll(ageOrBirthdDateErrorMessage);
    }

    if (identifierTypeWidget != null && identifierTypeValueWidget != null) {
      String identifierTypeId = (String) identifierTypeWidget.getValue(context, request);
      String identifierValue = (String) identifierTypeValueWidget.getValue(context, request);
      if(StringUtils.hasText(identifierValue)){
        try {
          validateIdentifier(Integer.getInteger(identifierTypeId), identifierValue);
        }
        catch (Exception e) {
          ret.add(new FormSubmissionError(context.getFieldName(identifierTypeValueErrorWidget), e.getMessage()));
        }
      }
    }

    return ret;
  }

  private boolean validateMandatoryField(FormEntryContext context, HttpServletRequest request, Widget widget, ErrorWidget errorWidget,
      List<FormSubmissionError> ret) {

    try {
      if (widget != null) {
        Object obj = widget.getValue(context, request);
        if (obj == null || (obj instanceof String && !StringUtils.hasText((String) obj))) {
          throw new Exception("htmlformentry.error.required");
        }
      }
    }
    catch (Exception ex) {
      ret.add(new FormSubmissionError(context.getFieldName(errorWidget), Context.getMessageSourceService().getMessage(ex.getMessage())));
      return false;
    }

    return true;
  }

  /**
   * If there's a birthdate specified
   */
  private void calculateBirthDate(Person person, Date date, Double age) {
    Date birthdate = null;
    boolean birthdateEstimated = false;
    if (date != null) {
        birthdate = date;
        //if you have a previous date that's marked as estimated and date does not change -->  keep it that way
        //if you have a previous date that's marked as estimated but date changes --> not estimated
        //if new --> not estimated
        //if existing and not estimated --> not estimated
        birthdateEstimated = person.getBirthdate() != null && person.getBirthdateEstimated() != null && person.getBirthdate().equals(date) ? person.getBirthdateEstimated() : false;
    }
    else if (age != null) { 
      try {
        Double ageRemainder  = BigDecimal.valueOf(age).subtract(BigDecimal.valueOf(Math.floor(age))).doubleValue();
        if (ageRemainder.equals(Double.valueOf(0)))
          person.setBirthdateFromAge(age.intValue(), new Date()); //default to usual behavior from core
        else { //a decimal was entered
          Calendar c = Calendar.getInstance();
          c.setTime(new Date());
          c.add(Calendar.DAY_OF_MONTH, - Double.valueOf((ageRemainder * 365)).intValue()); //if patient is 2.2 years old, patient was 2.0 years 2.2 - (.2*365) days ago
          c.add(Calendar.YEAR, -1 * Double.valueOf(Math.floor(age)).intValue());
          birthdate = c.getTime();
        }
        birthdateEstimated = true;
      }
      catch (NumberFormatException e) {
        throw new RuntimeException("Error getting date from age", e);
      }
    } else {
      throw new IllegalArgumentException("You must provide either an age or a birthdate for this patient.");
    }
    if (birthdate != null)
      person.setBirthdate(birthdate);
    person.setBirthdateEstimated(birthdateEstimated);
  }
}
TOP

Related Classes of org.openmrs.module.htmlformentry.element.PatientDetailSubmissionElement

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.