/**
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* 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.
*
* The Original Code is OpenELIS code.
*
* Copyright (C) The Minnesota Department of Health. All Rights Reserved.
*
* Contributor(s): CIRG, University of Washington, Seattle WA.
*/
package us.mn.state.health.lims.patient.action;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.validator.GenericValidator;
import org.apache.struts.Globals;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessages;
import org.hibernate.StaleObjectStateException;
import org.hibernate.Transaction;
import us.mn.state.health.lims.address.dao.AddressPartDAO;
import us.mn.state.health.lims.address.dao.PersonAddressDAO;
import us.mn.state.health.lims.address.daoimpl.AddressPartDAOImpl;
import us.mn.state.health.lims.address.daoimpl.PersonAddressDAOImpl;
import us.mn.state.health.lims.address.valueholder.AddressPart;
import us.mn.state.health.lims.address.valueholder.PersonAddress;
import us.mn.state.health.lims.common.action.BaseAction;
import us.mn.state.health.lims.common.action.BaseActionForm;
import us.mn.state.health.lims.common.exception.LIMSRuntimeException;
import us.mn.state.health.lims.common.provider.query.PatientSearchResults;
import us.mn.state.health.lims.common.util.ConfigurationProperties;
import us.mn.state.health.lims.common.util.validator.ActionError;
import us.mn.state.health.lims.hibernate.HibernateUtil;
import us.mn.state.health.lims.patient.action.bean.PatientManagementInfo;
import us.mn.state.health.lims.patient.dao.PatientDAO;
import us.mn.state.health.lims.patient.daoimpl.PatientDAOImpl;
import us.mn.state.health.lims.patient.valueholder.Patient;
import us.mn.state.health.lims.patientidentity.dao.PatientIdentityDAO;
import us.mn.state.health.lims.patientidentity.daoimpl.PatientIdentityDAOImpl;
import us.mn.state.health.lims.patientidentity.valueholder.PatientIdentity;
import us.mn.state.health.lims.patientidentitytype.util.PatientIdentityTypeMap;
import us.mn.state.health.lims.patienttype.dao.PatientPatientTypeDAO;
import us.mn.state.health.lims.patienttype.daoimpl.PatientPatientTypeDAOImpl;
import us.mn.state.health.lims.patienttype.util.PatientTypeMap;
import us.mn.state.health.lims.patienttype.valueholder.PatientPatientType;
import us.mn.state.health.lims.person.dao.PersonDAO;
import us.mn.state.health.lims.person.daoimpl.PersonDAOImpl;
import us.mn.state.health.lims.person.valueholder.Person;
import us.mn.state.health.lims.sample.dao.SearchResultsDAO;
import us.mn.state.health.lims.sample.daoimpl.SearchResultsDAOImp;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
public class PatientManagementUpdateAction extends BaseAction implements IPatientUpdate {
protected Patient patient;
protected Person person;
private List<PatientIdentity> patientIdentities;
private String patientID = "";
private static PatientIdentityDAO identityDAO = new PatientIdentityDAOImpl();
private static PatientDAO patientDAO = new PatientDAOImpl();
private static PersonAddressDAO personAddressDAO = new PersonAddressDAOImpl();
private static final String AMBIGUOUS_DATE_CHAR = ConfigurationProperties.getInstance().getPropertyValue(ConfigurationProperties.Property.AmbiguousDateHolder);
private static final String AMBIGUOUS_DATE_HOLDER = AMBIGUOUS_DATE_CHAR + AMBIGUOUS_DATE_CHAR;
protected PatientUpdateStatus patientUpdateStatus = PatientUpdateStatus.NO_ACTION;
private static String ADDRESS_PART_VILLAGE_ID;
private static String ADDRESS_PART_COMMUNE_ID;
private static String ADDRESS_PART_DEPT_ID;
public static enum PatientUpdateStatus {
NO_ACTION, UPDATE, ADD
}
static{
AddressPartDAO addressPartDAO = new AddressPartDAOImpl();
List<AddressPart> partList = addressPartDAO.getAll();
for( AddressPart addressPart : partList){
if( "department".equals(addressPart.getPartName())){
ADDRESS_PART_DEPT_ID = addressPart.getId();
}else if( "commune".equals(addressPart.getPartName())){
ADDRESS_PART_COMMUNE_ID = addressPart.getId();
}else if( "village".equals(addressPart.getPartName())){
ADDRESS_PART_VILLAGE_ID = addressPart.getId();
}
}
}
@Override
protected ActionForward performAction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws Exception {
String forward = FWD_SUCCESS;
BaseActionForm dynaForm = (BaseActionForm) form;
PatientManagementInfo patientInfo = (PatientManagementInfo ) dynaForm.get("patientProperties");
setPatientUpdateStatus(patientInfo);
if (patientUpdateStatus != PatientUpdateStatus.NO_ACTION) {
ActionMessages errors;
errors = preparePatientData(mapping, request, patientInfo);
if (!errors.isEmpty()) {
saveErrors(request, errors);
request.setAttribute(Globals.ERROR_KEY, errors);
return mapping.findForward(FWD_FAIL);
}
Transaction tx = HibernateUtil.getSession().beginTransaction();
try {
persistPatientData(patientInfo);
tx.commit();
} catch (LIMSRuntimeException lre) {
tx.rollback();
errors = new ActionMessages();
if (lre.getException() instanceof StaleObjectStateException) {
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionError("errors.OptimisticLockException", null, null));
} else {
lre.printStackTrace();
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionError("errors.UpdateException", null, null));
}
saveErrors(request, errors);
request.setAttribute(Globals.ERROR_KEY, errors);
request.setAttribute(ALLOW_EDITS_KEY, "false");
return mapping.findForward(FWD_FAIL);
} finally {
HibernateUtil.closeSession();
}
dynaForm.initialize(mapping);
}
setSuccessFlag(request, forward);
return mapping.findForward(forward);
}
/*
* (non-Javadoc)
*
* @see
* us.mn.state.health.lims.patient.action.IPatientUpdate#preparePatientData
* (org.apache.struts.action.ActionMapping,
* javax.servlet.http.HttpServletRequest,
* us.mn.state.health.lims.common.action.BaseActionForm)
*/
public ActionMessages preparePatientData(ActionMapping mapping, HttpServletRequest request, PatientManagementInfo patientInfo)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
if( currentUserId == null){
currentUserId = getSysUserId(request);
}
ActionMessages errors = validatePatientInfo(patientInfo);
if( !errors.isEmpty()){
return errors;
}
initMembers();
if (patientUpdateStatus == PatientUpdateStatus.UPDATE) {
loadForUpdate(patientInfo);
}
copyFormBeanToValueHolders(patientInfo);
setSystemUserID();
setLastUpdatedTimeStamps(patientInfo);
return errors;
}
private ActionMessages validatePatientInfo( PatientManagementInfo patientInfo ){
ActionMessages errors = new ActionMessages();
if( ConfigurationProperties.getInstance().isPropertyValueEqual( ConfigurationProperties.Property.ALLOW_DUPLICATE_SUBJECT_NUMBERS, "false" )){
String newSTNumber = GenericValidator.isBlankOrNull( patientInfo.getSTnumber() ) ? null :patientInfo.getSTnumber();
String newSubjectNumber = GenericValidator.isBlankOrNull( patientInfo.getSubjectNumber() ) ? null :patientInfo.getSubjectNumber();
String newNationalId = GenericValidator.isBlankOrNull( patientInfo.getNationalId() ) ? null :patientInfo.getNationalId();
SearchResultsDAO search = new SearchResultsDAOImp();
List<PatientSearchResults> results = search.getSearchResults(null, null, newSTNumber, newSubjectNumber, newNationalId, null, null, null);
if( !results.isEmpty() ){
for( PatientSearchResults result : results){
if( !result.getPatientID().equals( patientInfo.getPatientPK() )){
if( newSTNumber != null && newSTNumber.equals( result.getSTNumber() )){
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionError("error.duplicate.STNumber", null, null));
}
if( newSubjectNumber != null && newSubjectNumber.equals( result.getSubjectNumber() )){
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionError("error.duplicate.subjectNumber", null, null));
}
if( newNationalId != null && newNationalId.equals( result.getNationalId() )){
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionError("error.duplicate.nationalId", null, null));
}
}
}
}
}
validateBirthdateFormat(patientInfo, errors);
return errors;
}
private void validateBirthdateFormat(PatientManagementInfo patientInfo, ActionMessages errors) {
String birthDate = patientInfo.getBirthDateForDisplay();
boolean validBirthDateFormat = true;
if( !GenericValidator.isBlankOrNull(birthDate)){
validBirthDateFormat = birthDate.length() == 10;
//the regex matches ambiguous day and month or ambiguous day or completely formed date
if(validBirthDateFormat){
validBirthDateFormat = birthDate.matches("(((" + AMBIGUOUS_DATE_HOLDER + "|\\d{2})/\\d{2})|" + AMBIGUOUS_DATE_HOLDER + "/(" + AMBIGUOUS_DATE_HOLDER + "|\\d{2}))/\\d{4}");
}
if( !validBirthDateFormat){
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionError("error.birthdate.format", null, null ));
}
}
}
private void setLastUpdatedTimeStamps(PatientManagementInfo patientInfo) {
String patientUpdate = patientInfo.getPatientLastUpdated();
if (!GenericValidator.isBlankOrNull(patientUpdate)) {
Timestamp timeStamp = Timestamp.valueOf(patientUpdate);
patient.setLastupdated(timeStamp);
}
String personUpdate = patientInfo.getPersonLastUpdated();
if (!GenericValidator.isBlankOrNull(personUpdate)) {
Timestamp timeStamp = Timestamp.valueOf(personUpdate);
person.setLastupdated(timeStamp);
}
}
private void initMembers() {
patient = new Patient();
person = new Person();
patientIdentities = new ArrayList<PatientIdentity>();
}
private void loadForUpdate(PatientManagementInfo patientInfo) {
patientID = patientInfo.getPatientPK();
patient = patientDAO.readPatient(patientID);
person = patient.getPerson();
patientIdentities = identityDAO.getPatientIdentitiesForPatient(patient.getId());
}
/*
* (non-Javadoc)
*
* @see
* us.mn.state.health.lims.patient.action.IPatientUpdate#setPatientUpdateStatus
* (us.mn.state.health.lims.common.action.BaseActionForm)
*/
public void setPatientUpdateStatus(PatientManagementInfo patientInfo) {
String status = patientInfo.getPatientProcessingStatus();
if (status.equals("noAction")) {
patientUpdateStatus = PatientUpdateStatus.NO_ACTION;
} else if (status.equals("update")) {
patientUpdateStatus = PatientUpdateStatus.UPDATE;
} else {
patientUpdateStatus = PatientUpdateStatus.ADD;
}
}
/*
* (non-Javadoc)
*
* @see
* us.mn.state.health.lims.patient.action.IPatientUpdate#getPatientUpdateStatus
* ()
*/
public PatientUpdateStatus getPatientUpdateStatus() {
return patientUpdateStatus;
}
private void copyFormBeanToValueHolders(PatientManagementInfo patientInfo) throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException {
PropertyUtils.copyProperties(patient, patientInfo);
PropertyUtils.copyProperties(person, patientInfo);
}
private void setSystemUserID() {
patient.setSysUserId(currentUserId);
person.setSysUserId(currentUserId);
for (PatientIdentity identity : patientIdentities) {
identity.setSysUserId(currentUserId);
}
}
public void persistPatientData(PatientManagementInfo patientInfo) throws LIMSRuntimeException {
PersonDAO personDAO = new PersonDAOImpl();
if (patientUpdateStatus == PatientUpdateStatus.ADD) {
personDAO.insertData(person);
} else if (patientUpdateStatus == PatientUpdateStatus.UPDATE) {
personDAO.updateData(person);
}
patient.setPerson(person);
if (patientUpdateStatus == PatientUpdateStatus.ADD) {
patientDAO.insertData(patient);
} else if (patientUpdateStatus == PatientUpdateStatus.UPDATE) {
patientDAO.updateData(patient);
}
persistPatientRelatedInformation(patientInfo);
patientID = patient.getId();
}
protected void persistPatientRelatedInformation(PatientManagementInfo patientInfo) {
persistIdentityTypes( patientInfo );
persistExtraPatientAddressInfo( patientInfo );
persistPatientType(patientInfo);
}
protected void persistIdentityTypes( PatientManagementInfo patientInfo ) {
persistIdentityType(patientInfo.getSTnumber(), "ST");
persistIdentityType(patientInfo.getMothersName(), "MOTHER");
persistIdentityType(patientInfo.getAka(), "AKA");
persistIdentityType(patientInfo.getInsuranceNumber(), "INSURANCE");
persistIdentityType(patientInfo.getOccupation(), "OCCUPATION");
persistIdentityType(patientInfo.getSubjectNumber(), "SUBJECT");
persistIdentityType(patientInfo.getMothersInitial(), "MOTHERS_INITIAL");
persistIdentityType(patientInfo.getEducation(), "EDUCATION");
persistIdentityType(patientInfo.getMaritialStatus(), "MARITIAL");
persistIdentityType(patientInfo.getNationality(), "NATIONALITY");
persistIdentityType(patientInfo.getHealthDistrict(), "HEALTH DISTRICT");
persistIdentityType(patientInfo.getHealthRegion(), "HEALTH REGION");
persistIdentityType(patientInfo.getOtherNationality(), "OTHER NATIONALITY");
}
private void persistExtraPatientAddressInfo(PatientManagementInfo patientInfo) {
PersonAddress village = null;
PersonAddress commune = null;
PersonAddress dept = null;
List<PersonAddress> personAddressList = personAddressDAO.getAddressPartsByPersonId(person.getId());
for( PersonAddress address : personAddressList){
if( address.getAddressPartId().equals(ADDRESS_PART_COMMUNE_ID)){
commune = address;
commune.setValue(patientInfo.getCommune());
commune.setSysUserId(currentUserId);
personAddressDAO.update(commune);
}else if( address.getAddressPartId().equals(ADDRESS_PART_VILLAGE_ID)){
village = address;
village.setValue( patientInfo.getCity());
village.setSysUserId(currentUserId);
personAddressDAO.update(village);
}else if( address.getAddressPartId().equals(ADDRESS_PART_DEPT_ID)){
dept = address;
if( !GenericValidator.isBlankOrNull(patientInfo.getAddressDepartment()) && !patientInfo.getAddressDepartment().equals("0")){
dept.setValue(patientInfo.getAddressDepartment());
dept.setType("D");
dept.setSysUserId(currentUserId);
personAddressDAO.update(dept);
}
}
}
if( commune == null){
insertNewPatientInfo(ADDRESS_PART_COMMUNE_ID, patientInfo.getCommune(), "T");
}
if( village == null){
insertNewPatientInfo(ADDRESS_PART_VILLAGE_ID, patientInfo.getCity(), "T");
}
if( dept == null && patientInfo.getAddressDepartment() != null && !patientInfo.getAddressDepartment().equals("0")){
insertNewPatientInfo(ADDRESS_PART_DEPT_ID, patientInfo.getAddressDepartment(), "D");
}
}
private void insertNewPatientInfo(String partId, String value, String type) {
PersonAddress address;
address = new PersonAddress();
address.setPersonId(person.getId());
address.setAddressPartId(partId);
address.setType(type);
address.setValue(value);
address.setSysUserId(currentUserId);
personAddressDAO.insert(address);
}
public void persistIdentityType(String paramValue, String type) throws LIMSRuntimeException {
Boolean newIdentityNeeded = true;
String typeID = PatientIdentityTypeMap.getInstance().getIDForType(type);
if (patientUpdateStatus == PatientUpdateStatus.UPDATE) {
for (PatientIdentity listIdentity : patientIdentities) {
if (listIdentity.getIdentityTypeId().equals(typeID)) {
newIdentityNeeded = false;
if ((listIdentity.getIdentityData() == null && !GenericValidator.isBlankOrNull(paramValue))
|| (listIdentity.getIdentityData() != null && !listIdentity.getIdentityData().equals(paramValue))) {
listIdentity.setIdentityData(paramValue);
identityDAO.updateData(listIdentity);
}
break;
}
}
}
if (newIdentityNeeded && !GenericValidator.isBlankOrNull(paramValue)) {
// either a new patient or a new identity item
PatientIdentity identity = new PatientIdentity();
identity.setPatientId(patient.getId());
identity.setIdentityTypeId(typeID);
identity.setSysUserId(currentUserId);
identity.setIdentityData(paramValue);
identity.setLastupdatedFields();
identityDAO.insertData(identity);
}
}
protected void persistPatientType(PatientManagementInfo patientInfo) {
PatientPatientTypeDAO patientPatientTypeDAO = new PatientPatientTypeDAOImpl();
String typeName = null;
try {
typeName = patientInfo.getPatientType();
} catch (Exception ignored) {
}
if (!GenericValidator.isBlankOrNull(typeName) && !"0".equals(typeName)) {
String typeID = PatientTypeMap.getInstance().getIDForType(typeName);
PatientPatientType patientPatientType = patientPatientTypeDAO.getPatientPatientTypeForPatient(patient.getId());
if (patientPatientType == null) {
patientPatientType = new PatientPatientType();
patientPatientType.setSysUserId(currentUserId);
patientPatientType.setPatientId(patient.getId());
patientPatientType.setPatientTypeId(typeID);
patientPatientTypeDAO.insertData(patientPatientType);
} else {
patientPatientType.setSysUserId(currentUserId);
patientPatientType.setPatientTypeId(typeID);
patientPatientTypeDAO.updateData(patientPatientType);
}
}
}
@Override
protected String getPageTitleKey() {
return "patient.management.title";
}
@Override
protected String getPageSubtitleKey() {
return "patient.management.title";
}
public String getPatientId(BaseActionForm dynaForm) {
return GenericValidator.isBlankOrNull(patientID) ? dynaForm.getString("patientPK") : patientID;
}
}