/**
* 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) CIRG, University of Washington, Seattle WA. All Rights Reserved.
*
*/
package us.mn.state.health.lims.referral.action;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.validator.GenericValidator;
import org.apache.struts.Globals;
import org.apache.struts.action.*;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.hibernate.StaleObjectStateException;
import org.hibernate.Transaction;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import us.mn.state.health.lims.analysis.dao.AnalysisDAO;
import us.mn.state.health.lims.analysis.daoimpl.AnalysisDAOImpl;
import us.mn.state.health.lims.analysis.valueholder.Analysis;
import us.mn.state.health.lims.common.action.BaseAction;
import us.mn.state.health.lims.common.action.IActionConstants;
import us.mn.state.health.lims.common.exception.LIMSRuntimeException;
import us.mn.state.health.lims.common.services.*;
import us.mn.state.health.lims.common.services.StatusService.AnalysisStatus;
import us.mn.state.health.lims.common.services.StatusService.OrderStatus;
import us.mn.state.health.lims.common.util.DateUtil;
import us.mn.state.health.lims.common.util.validator.ActionError;
import us.mn.state.health.lims.hibernate.HibernateUtil;
import us.mn.state.health.lims.note.dao.NoteDAO;
import us.mn.state.health.lims.note.daoimpl.NoteDAOImpl;
import us.mn.state.health.lims.note.valueholder.Note;
import us.mn.state.health.lims.organization.dao.OrganizationDAO;
import us.mn.state.health.lims.organization.daoimpl.OrganizationDAOImpl;
import us.mn.state.health.lims.patient.valueholder.Patient;
import us.mn.state.health.lims.referral.action.beanitems.IReferralResultTest;
import us.mn.state.health.lims.referral.action.beanitems.ReferralItem;
import us.mn.state.health.lims.referral.action.beanitems.ReferredTest;
import us.mn.state.health.lims.referral.dao.ReferralDAO;
import us.mn.state.health.lims.referral.dao.ReferralResultDAO;
import us.mn.state.health.lims.referral.daoimpl.ReferralDAOImpl;
import us.mn.state.health.lims.referral.daoimpl.ReferralResultDAOImpl;
import us.mn.state.health.lims.referral.valueholder.Referral;
import us.mn.state.health.lims.referral.valueholder.ReferralResult;
import us.mn.state.health.lims.result.dao.ResultDAO;
import us.mn.state.health.lims.result.daoimpl.ResultDAOImpl;
import us.mn.state.health.lims.result.valueholder.Result;
import us.mn.state.health.lims.resultlimits.valueholder.ResultLimit;
import us.mn.state.health.lims.sample.dao.SampleDAO;
import us.mn.state.health.lims.sample.daoimpl.SampleDAOImpl;
import us.mn.state.health.lims.sample.valueholder.Sample;
import us.mn.state.health.lims.samplehuman.dao.SampleHumanDAO;
import us.mn.state.health.lims.samplehuman.daoimpl.SampleHumanDAOImpl;
import us.mn.state.health.lims.test.dao.TestDAO;
import us.mn.state.health.lims.test.daoimpl.TestDAOImpl;
import us.mn.state.health.lims.test.valueholder.Test;
import us.mn.state.health.lims.testresult.dao.TestResultDAO;
import us.mn.state.health.lims.testresult.daoimpl.TestResultDAOImpl;
import us.mn.state.health.lims.testresult.valueholder.TestResult;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
public class ReferredOutUpdateAction extends BaseAction {
private List<ReferralSet> referralSetList;
private List<ReferralResult> removableReferralResults;
private List<ReferralItem> modifiedItems;
private List<ReferralItem> canceledItems;
private Set<Sample> parentSamples;
private List<Sample> modifiedSamples;
private ActionMessages errors;
private final ReferralDAO referralDAO = new ReferralDAOImpl();
private final ReferralResultDAO referralResultDAO = new ReferralResultDAOImpl();
private final OrganizationDAO organizationDAO = new OrganizationDAOImpl();
private final ResultDAO resultDAO = new ResultDAOImpl();
private final SampleDAO sampleDAO = new SampleDAOImpl();
private final AnalysisDAO analysisDAO = new AnalysisDAOImpl();
private final NoteDAO noteDAO = new NoteDAOImpl();
private final TestResultDAO testResultDAO = new TestResultDAOImpl();
private static final String RESULT_SUBJECT = "Result Note";
private TestDAO testDAO = new TestDAOImpl();
private SampleHumanDAO sampleHumanDAO = new SampleHumanDAOImpl();
@Override
protected String getPageSubtitleKey() {
return "referral.out.manage";
}
@Override
protected String getPageTitleKey() {
return "referral.out.manage";
}
@SuppressWarnings("unchecked")
@Override
protected ActionForward performAction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws Exception {
parentSamples = new HashSet<Sample>();
modifiedSamples = new ArrayList<Sample>();
errors = new ActionMessages();
request.getSession().setAttribute(SAVE_DISABLED, TRUE);
DynaActionForm dynaForm = (DynaActionForm) form;
List<ReferralItem> referralItems = (List<ReferralItem>) PropertyUtils.getProperty(dynaForm, "referralItems");
selectModifiedAndCanceledItems(referralItems);
validateModifedItems();
if (errors.size() > 0) {
saveErrors(request, errors);
request.setAttribute(Globals.ERROR_KEY, errors);
return mapping.findForward(IActionConstants.FWD_VALIDATION_ERROR);
}
try {
createReferralSets();
} catch (LIMSRuntimeException e) {
saveErrors(request, errors);
request.setAttribute(Globals.ERROR_KEY, errors);
return mapping.findForward(IActionConstants.FWD_VALIDATION_ERROR);
}
Transaction tx = HibernateUtil.getSession().beginTransaction();
try {
for (ReferralSet referralSet : referralSetList) {
referralDAO.updateData(referralSet.referral);
for (ReferralResult referralResult : referralSet.updatableReferralResults ) {
Result result = referralResult.getResult();
if (result != null) {
if (result.getId() == null) {
resultDAO.insertData(result);
} else {
result.setSysUserId( currentUserId );
resultDAO.updateData(result);
}
}
if( referralResult.getId() == null){
referralResultDAO.insertData(referralResult);
}else{
referralResultDAO.updateData( referralResult );
}
}
if (referralSet.note != null) {
if (referralSet.note.getId() == null) {
noteDAO.insertData(referralSet.note);
} else {
noteDAO.updateData(referralSet.note);
}
}
}
for (ReferralResult referralResult : removableReferralResults) {
referralResult.setSysUserId(currentUserId);
referralResultDAO.deleteData(referralResult);
if (referralResult.getResult() != null && referralResult.getResult().getId() != null) {
referralResult.getResult().setSysUserId(currentUserId);
resultDAO.deleteData(referralResult.getResult());
}
}
setStatusOfParentSamples();
for (Sample sample : modifiedSamples) {
sampleDAO.updateData(sample);
}
tx.commit();
} catch (LIMSRuntimeException lre) {
tx.rollback();
ActionError error;
if (lre.getException() instanceof StaleObjectStateException) {
error = new ActionError("errors.OptimisticLockException", null, null);
} else {
lre.printStackTrace();
error = new ActionError("error.system", null, null);
}
errors.add(ActionMessages.GLOBAL_MESSAGE, error);
saveErrors(request, errors);
request.setAttribute(Globals.ERROR_KEY, errors);
request.setAttribute(ALLOW_EDITS_KEY, "false");
return mapping.findForward(FWD_FAIL);
} finally {
HibernateUtil.closeSession();
}
return mapping.findForward(IActionConstants.FWD_SUCCESS);
}
private void selectModifiedAndCanceledItems(List<ReferralItem> referralItems) {
modifiedItems = new ArrayList<ReferralItem>();
canceledItems = new ArrayList<ReferralItem>();
for (ReferralItem item : referralItems) {
if (item.isCanceled()) {
canceledItems.add(item);
} else if (item.isModified()) {
modifiedItems.add(item);
}
}
}
private void validateModifedItems() {
for (ReferralItem referralItem : modifiedItems) {
validateModifedItem(referralItem);
}
}
private void validateModifedItem(ReferralItem referralItem) {
// if an institution has not been entered then there may not be a test
if (!institutionEntered(referralItem) && testEntered(referralItem)) {
ActionError error = new ActionError("error.referral.missingInstitution", referralItem.getAccessionNumber(), null);
errors.add(ActionErrors.GLOBAL_MESSAGE, error);
}
// if a test has not been entered then there can not be a result or
// report date
if (!testEntered(referralItem) && (reportDateEntered(referralItem) || resultEntered(referralItem))) {
ActionError error = new ActionError("error.referral.missingTest", referralItem.getAccessionNumber(), null);
errors.add(ActionErrors.GLOBAL_MESSAGE, error);
}
}
private boolean institutionEntered(ReferralItem referralItem) {
return !"0".equals(referralItem.getReferredInstituteId());
}
private boolean testEntered(IReferralResultTest resultTest) {
return !"0".equals(resultTest.getReferredTestId());
}
private boolean reportDateEntered(IReferralResultTest resultTest) {
return !GenericValidator.isBlankOrNull(resultTest.getReferredReportDate());
}
private boolean resultEntered(IReferralResultTest resultTest) {
return !(GenericValidator.isBlankOrNull(resultTest.getReferredResult()) && "0".equals(resultTest.getReferredDictionaryResult()));
}
private void createReferralSets() throws LIMSRuntimeException {
referralSetList = new ArrayList<ReferralSet>();
removableReferralResults = new ArrayList<ReferralResult>();
for (ReferralItem item : canceledItems) {
referralSetList.add(createCanceledReferralSet(item));
}
for (ReferralItem item : modifiedItems) {
referralSetList.add(createModifiedSet(item));
}
}
private ReferralSet createCanceledReferralSet(ReferralItem item) {
ReferralSet referralSet = new ReferralSet();
Referral referral = referralDAO.getReferralById(item.getReferralId());
referralSet.referral = referral;
referral.setSysUserId(currentUserId);
referral.setCanceled(true);
setStatusForCanceledReferrals(referral);
return referralSet;
}
@SuppressWarnings("unchecked")
private void setStatusForCanceledReferrals(Referral referral) {
Analysis analysis = referral.getAnalysis();
analysis.setReferredOut(false);
Sample sample = analysis.getSampleItem().getSample();
parentSamples.add(sample);
}
private ReferralSet createModifiedSet(ReferralItem referralItem) throws LIMSRuntimeException {
// place all existing referral results in list
ReferralSet referralSet = new ReferralSet();
referralSet.setExistingReferralResults( referralResultDAO.getReferralResultsForReferral( referralItem.getReferralId() ) );
Referral referral = referralDAO.getReferralById(referralItem.getReferralId());
referral.setCanceled(false);
referral.setSysUserId(currentUserId);
referral.setOrganization(organizationDAO.getOrganizationById(referralItem.getReferredInstituteId()));
referral.setSentDate(DateUtil.convertStringDateToTruncatedTimestamp(referralItem.getReferredSendDate()));
referral.setRequesterName(referralItem.getReferrer());
referralSet.referral = referral;
referralSet.note = new NoteService(referral.getAnalysis()).createSavableNote( NoteService.NoteType.INTERNAL, referralItem.getNote(),RESULT_SUBJECT,currentUserId );
createReferralResults(referralItem, referralSet);
if (referralItem.getAdditionalTests() != null) {
for (ReferredTest existingAdditionalTest : referralItem.getAdditionalTests()) {
if (!existingAdditionalTest.isRemove()) {
// nothing to do if isRemove, because on insert we reused what we could
// then deleted all old referralResults (see below).
// removableReferralResults.add(getRemovableReferralableResults(existingAdditionalTest));
createReferralResults(existingAdditionalTest, referralSet);
}
}
}
List<ReferredTest> newAdditionalTests = getNewTests(referralItem.getAdditionalTestsXMLWad());
for (ReferredTest newReferralTest : newAdditionalTests) {
newReferralTest.setReferralId(referralItem.getReferralId());
createReferralResults(newReferralTest, referralSet);
}
// any leftovers get deleted
this.removableReferralResults.addAll(referralSet.getExistingReferralResults());
return referralSet;
}
/**
* Reuse any existing referrableResults, placing the submitted results in
* them. Then any remaining referral results are removable.
***/
private void createReferralResults(IReferralResultTest referralItem, ReferralSet referralSet) {
if( referralItem.getReferredTestIdShadow() != null && !referralItem.getReferredTestId().equals( referralItem.getReferredTestIdShadow() )){
referralSet.updateTest( referralItem.getReferredTestIdShadow(), referralItem.getReferredTestId(),currentUserId );
}else{
String referredResultType = getReferredResultType( referralItem, null );
if( TypeOfTestResultService.ResultType.isMultiSelectVariant( referredResultType ) ){
if( !GenericValidator.isBlankOrNull( referralItem.getMultiSelectResultValues() ) && !"{}".equals( referralItem.getMultiSelectResultValues() ) ){
JSONParser parser = new JSONParser();
try{
JSONObject jsonResult = ( JSONObject ) parser.parse( referralItem.getMultiSelectResultValues() );
for( Object key : jsonResult.keySet() ){
String[] ids = ( ( String ) jsonResult.get( key ) ).trim().split( "," );
//This will populate a result for each item in the multiselect referral result
for( String id : ids ){
ReferralResult referralResult = referralSet.getNextReferralResult();
referralItem.setReferredDictionaryResult( id ); // move particular multi result into (single) dictionary result.
fillReferralResultResult( referralItem, referralResult, Integer.parseInt( ( String ) key ) );
}
}
}catch( ParseException e ){
e.printStackTrace();
}
}else{
ReferralResult referralResult = referralSet.getNextReferralResult();
fillReferralResultResult( referralItem, referralResult, 0 );
}
}else{
ReferralResult referralResult = referralSet.getNextReferralResult();
fillReferralResultResult( referralItem, referralResult, 0 );
}
}
}
private void fillReferralResultResult( IReferralResultTest referralItem, ReferralResult referralResult, int grouping ) {
referralResult.setSysUserId(currentUserId);
setReferredResultReportDate(referralItem, referralResult);
setReferredResultTestId(referralItem, referralResult);
referralResult.setReferralId(referralItem.getReferralId());
Result result = referralResult.getResult();
if (result == null && !GenericValidator.isBlankOrNull(referralItem.getReferredResultType())) {
result = new Result();
}
if (result != null) {
setResultValuesForReferralResult(referralItem, result, grouping);
referralResult.setResult(result);
}
}
/**
* If the referredTest.referredResultType is "M" the particular value to
* translate into the result should already be loaded in
* referredTest.referredDictionaryResult
*
*/
private void setResultValuesForReferralResult( IReferralResultTest referredTest, Result result, int grouping ) {
result.setSysUserId(currentUserId);
result.setSortOrder("0");
Test test = testDAO.getTestById(referredTest.getReferredTestId());
Sample sample = referralDAO.getReferralById(referredTest.getReferralId()).getAnalysis().getSampleItem().getSample();
Patient patient = sampleHumanDAO.getPatientForSample(sample);
ResultLimit limit = new ResultLimitService().getResultLimitForTestAndPatient(test, patient);
result.setMinNormal(limit != null ? limit.getLowNormal() : 0.0);
result.setMaxNormal(limit != null ? limit.getHighNormal() : 0.0);
result.setGrouping( grouping );
String referredResultType = getReferredResultType(referredTest, test);
result.setResultType(referredResultType);
if ( TypeOfTestResultService.ResultType.isDictionaryVariant( referredResultType )) {
String dicResult = referredTest.getReferredDictionaryResult();
if (!(GenericValidator.isBlankOrNull(dicResult) || "0".equals(dicResult))) {
result.setValue(dicResult);
}
} else {
result.setValue(referredTest.getReferredResult());
}
}
private String getReferredResultType(IReferralResultTest referredTest, Test test) {
//N.B. this should not be corrected here. It should be done on load
/* referredTest.getReferredResultType() is not always accurate
* alpha-numeric and numeric are not differentiated
*/
String referredResultType = referredTest.getReferredResultType();
if ( !TypeOfTestResultService.ResultType.isDictionaryVariant( referredResultType ) && test != null) {
@SuppressWarnings("unchecked")
List<TestResult> testResults = testResultDAO.getAllActiveTestResultsPerTest( test );
if( !testResults.isEmpty()){
referredResultType = testResults.get(0).getTestResultType();
}
}
return referredResultType;
}
private void setReferredResultTestId(IReferralResultTest referralTest, ReferralResult referralResult) {
if (!"0".equals(referralTest.getReferredTestId())) {
referralResult.setTestId(referralTest.getReferredTestId());
}
}
private void setReferredResultReportDate(IReferralResultTest referralTest, ReferralResult referralResult) throws LIMSRuntimeException {
if (!GenericValidator.isBlankOrNull(referralTest.getReferredReportDate())) {
try {
referralResult.setReferralReportDate(DateUtil.convertStringDateToTruncatedTimestamp(referralTest.getReferredReportDate()));
} catch (LIMSRuntimeException e) {
ActionError error = new ActionError("errors.date", referralTest.getReferredReportDate(), null);
errors.add(ActionErrors.GLOBAL_MESSAGE, error);
throw e;
}
}
}
@SuppressWarnings("unchecked")
private List<ReferredTest> getNewTests(String xml) {
List<ReferredTest> newTestList = new ArrayList<ReferredTest>();
if (GenericValidator.isBlankOrNull(xml)) {
return newTestList;
}
try {
Document testsDom = DocumentHelper.parseText(xml);
for (Iterator<Element> i = testsDom.getRootElement().elementIterator("test"); i.hasNext();) {
Element testItem = i.next();
String testId = testItem.attribute("testId").getValue();
ReferredTest referralTest = new ReferredTest();
referralTest.setReferredTestId(testId);
referralTest.setReferredResultType(new TestService( testId ).getResultType());
referralTest.setReferredResult("");
referralTest.setReferredDictionaryResult("");
referralTest.setReferredMultiDictionaryResult("");
referralTest.setReferredReportDate("");
newTestList.add(referralTest);
}
} catch (DocumentException e) {
e.printStackTrace();
throw new LIMSRuntimeException(e);
}
return newTestList;
}
private void setStatusOfParentSamples() {
for (Sample sample : parentSamples) {
List<Analysis> analysisList = analysisDAO.getAnalysesBySampleId(sample.getId());
String finalizedId = StatusService.getInstance().getStatusID(AnalysisStatus.Finalized);
boolean allAnalysisFinished = true;
if (analysisList != null) {
for (Analysis childAnalysis : analysisList) {
Referral referral = referralDAO.getReferralByAnalysisId(childAnalysis.getId());
List<ReferralResult> referralResultList;
if (referral == null || referral.getId() == null) {
referralResultList = new ArrayList<ReferralResult>();
} else {
referralResultList = referralResultDAO.getReferralResultsForReferral(referral.getId());
}
if (referralResultList.isEmpty()) {
if (!finalizedId.equals(childAnalysis.getStatusId())) {
allAnalysisFinished = false;
break;
}
} else {
for (ReferralResult referralResult : referralResultList) {
if (referralResult.getResult() == null || GenericValidator.isBlankOrNull(referralResult.getResult().getValue())) {
if (!(referral.isCanceled() && finalizedId.equals(childAnalysis.getStatusId()))) {
allAnalysisFinished = false;
break;
}
}
}
}
}
}
if (allAnalysisFinished) {
sample.setStatusId(StatusService.getInstance().getStatusID(OrderStatus.Finished));
sample.setSysUserId(currentUserId);
modifiedSamples.add(sample);
}
}
}
static class ReferralSet {
Referral referral;
Note note;
List<ReferralResult> updatableReferralResults = new ArrayList<ReferralResult>();
private List<ReferralResult> existingReferralResults = new ArrayList<ReferralResult>();
public List<ReferralResult> getExistingReferralResults() {
return existingReferralResults;
}
public void setExistingReferralResults( List<ReferralResult> existingReferralResults ) {
this.existingReferralResults = existingReferralResults;
}
ReferralResult getNextReferralResult() {
ReferralResult referralResult = existingReferralResults.isEmpty() ? new ReferralResult() : existingReferralResults.remove( 0 );
updatableReferralResults.add( referralResult );
return referralResult;
}
public void updateTest( String oldTestId, String newTestId, String currentUserId){
ReferralResult updatedReferralResult = null;
for( ReferralResult referralResult : existingReferralResults){
if( referralResult.getTestId().equals( oldTestId )){
Result result = referralResult.getResult();
result.setSysUserId( currentUserId );
if( updatedReferralResult == null){
referralResult.setTestId( newTestId );
referralResult.setSysUserId( currentUserId );
result.setResultType( new TestService( newTestId ).getResultType() );
result.setValue( "" );
updatedReferralResult = referralResult;
updatableReferralResults.add(referralResult);
}
}
}
existingReferralResults.remove( updatedReferralResult );
}
}
}