/** * 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.analyzerresults.action; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.validator.GenericValidator; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.DynaActionForm; import org.hibernate.Transaction; 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.analyzerimport.util.AnalyzerTestNameCache; import us.mn.state.health.lims.analyzerimport.util.MappedTestName; import us.mn.state.health.lims.analyzerresults.action.beanitems.AnalyzerResultItem; import us.mn.state.health.lims.analyzerresults.dao.AnalyzerResultsDAO; import us.mn.state.health.lims.analyzerresults.daoimpl.AnalyzerResultsDAOImpl; import us.mn.state.health.lims.analyzerresults.valueholder.AnalyzerResults; import us.mn.state.health.lims.common.action.BaseAction; import us.mn.state.health.lims.common.exception.LIMSRuntimeException; import us.mn.state.health.lims.common.formfields.FormFields; import us.mn.state.health.lims.common.formfields.FormFields.Field; import us.mn.state.health.lims.common.services.*; import us.mn.state.health.lims.common.services.QAService.QAObservationType; import us.mn.state.health.lims.common.util.StringUtil; import us.mn.state.health.lims.dictionary.dao.DictionaryDAO; import us.mn.state.health.lims.dictionary.daoimpl.DictionaryDAOImpl; import us.mn.state.health.lims.dictionary.valueholder.Dictionary; import us.mn.state.health.lims.hibernate.HibernateUtil; 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.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.sampleitem.valueholder.SampleItem; import us.mn.state.health.lims.sampleqaevent.dao.SampleQaEventDAO; import us.mn.state.health.lims.sampleqaevent.daoimpl.SampleQaEventDAOImpl; import us.mn.state.health.lims.sampleqaevent.valueholder.SampleQaEvent; import us.mn.state.health.lims.test.valueholder.Test; //import us.mn.state.health.lims.test.valueholder.TestSection; import us.mn.state.health.lims.testreflex.action.util.TestReflexUtil; import us.mn.state.health.lims.testreflex.dao.TestReflexDAO; import us.mn.state.health.lims.testreflex.daoimpl.TestReflexDAOImpl; import us.mn.state.health.lims.testreflex.valueholder.TestReflex; 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 us.mn.state.health.lims.typeofsample.dao.TypeOfSampleTestDAO; import us.mn.state.health.lims.typeofsample.daoimpl.TypeOfSampleTestDAOImpl; import us.mn.state.health.lims.typeofsample.valueholder.TypeOfSampleTest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.*; public class AnalyzerResultsAction extends BaseAction { private String analyzer; private AnalyzerResultsDAO analyzerResultsDAO = new AnalyzerResultsDAOImpl(); private DictionaryDAO dictionaryDAO = new DictionaryDAOImpl(); private TestResultDAO testResultDAO = new TestResultDAOImpl(); private SampleDAO sampleDAO = new SampleDAOImpl(); private TypeOfSampleTestDAO sampleTypeTestDAO = new TypeOfSampleTestDAOImpl(); private AnalysisDAO analysisDAO = new AnalysisDAOImpl(); private TestReflexUtil reflexUtil = new TestReflexUtil(); private TestReflexDAO testReflexDAO = new TestReflexDAOImpl(); private ResultDAO resultDAO = new ResultDAOImpl(); private static Map<String, String> analyzerNameToSubtitleKey = new HashMap<String, String>(); static{ analyzerNameToSubtitleKey.put(AnalyzerTestNameCache.COBAS_INTEGRA400_NAME, "banner.menu.results.cobas.integra"); analyzerNameToSubtitleKey.put(AnalyzerTestNameCache.SYSMEX_XT2000_NAME, "banner.menu.results.sysmex"); analyzerNameToSubtitleKey.put(AnalyzerTestNameCache.FACSCALIBUR, "banner.menu.results.facscalibur"); analyzerNameToSubtitleKey.put(AnalyzerTestNameCache.FACSCANTO, "banner.menu.results.facscanto"); analyzerNameToSubtitleKey.put(AnalyzerTestNameCache.EVOLIS, "banner.menu.results.evolis"); analyzerNameToSubtitleKey.put(AnalyzerTestNameCache.COBAS_TAQMAN, "banner.menu.results.cobas.taqman"); analyzerNameToSubtitleKey.put(AnalyzerTestNameCache.COBAS_DBS, "banner.menu.results.cobasDBS"); analyzerNameToSubtitleKey.put(AnalyzerTestNameCache.COBAS_C311, "banner.menu.results.cobasc311"); } protected ActionForward performAction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { String forward = FWD_SUCCESS; request.getSession().setAttribute(SAVE_DISABLED, TRUE); String page = request.getParameter("page"); String requestAnalyzerType = request.getParameter("type"); setAnalyzerRequest( requestAnalyzerType); DynaActionForm dynaForm = (DynaActionForm) form; PropertyUtils.setProperty(dynaForm, "analyzerType", requestAnalyzerType); AnalyzerResultsPaging paging = new AnalyzerResultsPaging(); if (GenericValidator.isBlankOrNull(page)) { // get list of AnalyzerData from table based on analyzer type List<AnalyzerResults> analyzerResultsList = getAnalyzerResults(); if (analyzerResultsList.isEmpty()) { PropertyUtils.setProperty(dynaForm, "resultList", new ArrayList<AnalyzerResultItem>()); String msg = StringUtil.getMessageForKey("result.noResultsFound"); PropertyUtils.setProperty(dynaForm, "notFoundMsg", msg); paging.setEmptyPageBean(request,dynaForm); } else { /* * The problem we are solving is that the accession numbers may * not be consecutive but we still want to maintain the order So * we will form the groups (by analyzer runs) by going in order * but if the accession number is in another group it will be * boosted to the first group */ boolean missingTest = false; resolveMissingTests(analyzerResultsList); List<List<AnalyzerResultItem>> accessionGroupedResultsList = groupAnalyzerResults(analyzerResultsList); List<AnalyzerResultItem> analyzerResultItemList = new ArrayList<AnalyzerResultItem>(); int sampleGroupingNumber = 0; for (List<AnalyzerResultItem> group : accessionGroupedResultsList) { sampleGroupingNumber++; AnalyzerResultItem groupHeader = null; for (AnalyzerResultItem resultItem : group) { if (groupHeader == null) { groupHeader = resultItem; setNonConformityStateForResultItem(resultItem); if(FormFields.getInstance().useField(Field.QaEventsBySection) ) resultItem.setNonconforming(getQaEventByTestSection(analysisDAO.getAnalysisById(resultItem.getAnalysisId()))); } resultItem.setSampleGroupingNumber(sampleGroupingNumber); // There are two reasons there may not be a test id, // 1. it could not be found due to missing mapping // 2. it may not be looked for if the results are read // only // we only want to capture 1. if (GenericValidator.isBlankOrNull(resultItem.getTestId()) && !resultItem.isReadOnly()) { groupHeader.setGroupIsReadOnly(true); missingTest = true; } else if (resultItem.getIsControl()) { groupHeader.setGroupIsReadOnly(true); } analyzerResultItemList.add(resultItem); } } PropertyUtils.setProperty(dynaForm, "missingTestMsg", new Boolean(missingTest)); paging.setDatabaseResults(request, dynaForm, analyzerResultItemList); } } else { paging.page(request, dynaForm, page); } return mapping.findForward(forward); } private void setNonConformityStateForResultItem(AnalyzerResultItem resultItem) { boolean nonconforming = false; Sample sample = sampleDAO.getSampleByAccessionNumber(resultItem.getAccessionNumber()); if( sample!= null){ nonconforming = QAService.isOrderNonConforming(sample); //The sample is nonconforming, now we have to check if any sample items are non_conforming and // if they are are they for this test //Note we only have to check one test since the sample item is the same for all the tests if( nonconforming ){ List<SampleItem> nonConformingSampleItems = QAService.getNonConformingSampleItems(sample); //If there is a nonconforming sample item then we need to check if it is the one for this //test if it is then it is nonconforming if not then it is not nonconforming if( !nonConformingSampleItems.isEmpty()){ TypeOfSampleTest typeOfSample = sampleTypeTestDAO.getTypeOfSampleTestForTest(resultItem.getTestId()); if( typeOfSample != null){ String sampleTypeId = typeOfSample.getTypeOfSampleId(); nonconforming = false; for( SampleItem sampleItem : nonConformingSampleItems ){ if( sampleTypeId.equals(sampleItem.getTypeOfSample().getId() )){ nonconforming = true; break; } } } } } } resultItem.setNonconforming(nonconforming); } private List<List<AnalyzerResultItem>> groupAnalyzerResults(List<AnalyzerResults> analyzerResultsList) { Map<String, Integer> accessionToAccessionGroupMap = new HashMap<String, Integer>(); List<List<AnalyzerResultItem>> accessionGroupedResultsList = new ArrayList<List<AnalyzerResultItem>>(); for (AnalyzerResults analyzerResult : analyzerResultsList) { AnalyzerResultItem resultItem = analyzerResultsToAnalyzerResultItem(analyzerResult); Integer groupIndex = accessionToAccessionGroupMap.get(resultItem.getAccessionNumber()); List<AnalyzerResultItem> group; if (groupIndex == null) { group = new ArrayList<AnalyzerResultItem>(); accessionGroupedResultsList.add(group); accessionToAccessionGroupMap.put(resultItem.getAccessionNumber(), accessionGroupedResultsList.size() - 1); } else { group = accessionGroupedResultsList.get(groupIndex.intValue()); } group.add(resultItem); } return accessionGroupedResultsList; } private void resolveMissingTests(List<AnalyzerResults> analyzerResultsList) { boolean reloadCache = true; List<AnalyzerResults> resolvedResults = new ArrayList<AnalyzerResults>(); for (AnalyzerResults analyzerResult : analyzerResultsList) { if (GenericValidator.isBlankOrNull(analyzerResult.getTestId())) { if (reloadCache) { AnalyzerTestNameCache.instance().reloadCache(); reloadCache = false; } } String analyzerTestName = analyzerResult.getTestName(); MappedTestName mappedTestName = AnalyzerTestNameCache.instance().getMappedTest(analyzer, analyzerTestName); if (mappedTestName != null) { analyzerResult.setTestName(mappedTestName.getOpenElisTestName()); analyzerResult.setTestId(mappedTestName.getTestId()); resolvedResults.add(analyzerResult); } } if (resolvedResults.size() > 0) { Transaction tx = HibernateUtil.getSession().beginTransaction(); try { for (AnalyzerResults analyzerResult : resolvedResults) { analyzerResult.setSysUserId(currentUserId); analyzerResultsDAO.updateData(analyzerResult); } tx.commit(); } catch (LIMSRuntimeException lre) { tx.rollback(); } finally { HibernateUtil.closeSession(); } } } private List<AnalyzerResults> getAnalyzerResults() { return analyzerResultsDAO.getResultsbyAnalyzer(AnalyzerTestNameCache.instance().getAnalyzerIdForName(analyzer)); } protected AnalyzerResultItem analyzerResultsToAnalyzerResultItem(AnalyzerResults result) { AnalyzerResultItem resultItem = new AnalyzerResultItem(); resultItem.setAccessionNumber(result.getAccessionNumber()); resultItem.setAnalyzerId(result.getAnalyzerId()); resultItem.setIsControl(result.getIsControl()); resultItem.setTestName(result.getTestName()); resultItem.setUnits(getUnits(result.getUnits())); resultItem.setId(result.getId()); resultItem.setTestId(result.getTestId()); resultItem.setCompleteDate(result.getCompleteDateForDisplay()); resultItem.setLastUpdated(result.getLastupdated()); resultItem.setReadOnly((result.isReadOnly() || result.getTestId() == null)); resultItem.setResult(getResultForItem(result)); resultItem.setSignificantDigits(getSignificantDigitsFromAnalyzerResults(result)); resultItem.setTestResultType(result.getResultType()); resultItem.setDictionaryResultList(getDictionaryResultList(result)); resultItem.setIsHighlighted(!GenericValidator.isBlankOrNull(result.getDuplicateAnalyzerResultId()) || GenericValidator.isBlankOrNull(result.getTestId())); resultItem.setUserChoiceReflex(giveUserChoice(result)); resultItem.setUserChoicePending(false); if (resultItem.isUserChoiceReflex()) { setChoiceForCurrentValue(resultItem, result); resultItem.setUserChoicePending(!GenericValidator.isBlankOrNull(resultItem.getSelectionOneText()) ); } return resultItem; } private boolean giveUserChoice(AnalyzerResults result) { /* * This is how we figure out if the user will be able to select * 1. Is the test involved with triggering a user selection * reflex * 2. If the reflex has sibs has the sample been entered yet * 3. If the sample has been entered have all of the sibling * tests been ordered */ if (!TestReflexUtil.isTriggeringUserChoiceReflexTestId(result.getTestId())) { return false; } if (!TestReflexUtil.testIsTriggeringReflexWithSibs(result.getTestId())) { return false; } Sample sample = getSampleForAnalyzerResult(result); if (sample == null) { return false; } List<TestReflex> reflexes = reflexUtil.getPossibleUserChoiceTestReflexsForTest(result.getTestId()); List<Analysis> analysisList = analysisDAO.getAnalysesBySampleId(sample.getId()); Set<String> analysisTestIds = new HashSet<String>(); for (Analysis analysis : analysisList) { analysisTestIds.add(analysis.getTest().getId()); } for (TestReflex reflex : reflexes) { if (!analysisTestIds.contains(reflex.getTest().getId())) { return false; } } return true; } private Sample getSampleForAnalyzerResult(AnalyzerResults result) { return sampleDAO.getSampleByAccessionNumber(result.getAccessionNumber()); } private void setChoiceForCurrentValue(AnalyzerResultItem resultItem, AnalyzerResults analyzerResult) { /* * If there are no siblings for the reflex then we just need to find if * there are choices for the current value * * If there are siblings then we need to find if they are currently * satisfied */ TestReflex selectionOne = null; TestReflex selectionTwo = null; if (!TestReflexUtil.testIsTriggeringReflexWithSibs(analyzerResult.getTestId())) { List<TestReflex> reflexes = reflexUtil.getTestReflexsForDictioanryResultTestId(analyzerResult.getResult(), analyzerResult.getTestId(), true); resultItem.setReflexSelectionId(null); for (TestReflex reflex : reflexes) { if (selectionOne == null) { selectionOne = reflex; } else { selectionTwo = reflex; } } } else { Sample sample = getSampleForAnalyzerResult(analyzerResult); List<Analysis> analysisList = analysisDAO.getAnalysesBySampleId(sample.getId()); List<TestReflex> reflexesForDisplayedTest = reflexUtil.getTestReflexsForDictioanryResultTestId(analyzerResult.getResult(), analyzerResult.getTestId(), true); for (TestReflex possibleTestReflex : reflexesForDisplayedTest) { if (TestReflexUtil.isUserChoiceReflex( possibleTestReflex )) { if (GenericValidator.isBlankOrNull(possibleTestReflex.getSiblingReflexId())) { if (possibleTestReflex.getActionScriptlet() != null) { selectionOne = possibleTestReflex; break; } else if (selectionOne == null) { selectionOne = possibleTestReflex; } else { selectionTwo = possibleTestReflex; break; } } else { // find if the sibling reflex is satisfied TestReflex sibTestReflex = new TestReflex(); sibTestReflex.setId(possibleTestReflex.getSiblingReflexId()); testReflexDAO.getData(sibTestReflex); TestResult sibTestResult = new TestResult(); sibTestResult.setId(sibTestReflex.getTestResultId()); testResultDAO.getData(sibTestResult); for (Analysis analysis : analysisList) { List<Result> resultList = resultDAO.getResultsByAnalysis(analysis); Test test = analysis.getTest(); for (Result result : resultList) { TestResult testResult = testResultDAO.getTestResultsByTestAndDictonaryResult(test.getId(), result.getValue()); if (testResult != null && testResult.getId().equals(sibTestReflex.getTestResultId())) { if (possibleTestReflex.getActionScriptlet() != null) { selectionOne = possibleTestReflex; break; } else if (selectionOne == null) { selectionOne = possibleTestReflex; } else { selectionTwo = possibleTestReflex; break; } } } } } } } } populateAnalyzerResultItemWithReflexes(resultItem, selectionOne, selectionTwo); } private void populateAnalyzerResultItemWithReflexes(AnalyzerResultItem resultItem, TestReflex selectionOne, TestReflex selectionTwo) { if (selectionOne != null) { if (selectionTwo == null && !GenericValidator.isBlankOrNull(selectionOne.getActionScriptletId()) && !GenericValidator.isBlankOrNull(selectionOne.getTestId())) { resultItem.setSelectionOneText(TestReflexUtil.makeReflexTestName(selectionOne)); resultItem.setSelectionOneValue(TestReflexUtil.makeReflexTestValue(selectionOne)); resultItem.setSelectionTwoText(TestReflexUtil.makeReflexScriptName(selectionTwo)); resultItem.setSelectionTwoValue(TestReflexUtil.makeReflexScriptValue(selectionOne)); } else if (selectionTwo != null) { if (selectionOne.getTest() != null) { resultItem.setSelectionOneText(TestReflexUtil.makeReflexTestName(selectionOne)); resultItem.setSelectionOneValue(TestReflexUtil.makeReflexTestValue(selectionOne)); } else { resultItem.setSelectionOneText(TestReflexUtil.makeReflexScriptName(selectionOne)); resultItem.setSelectionOneValue(TestReflexUtil.makeReflexScriptValue(selectionOne)); } if (selectionTwo.getTest() != null) { resultItem.setSelectionTwoText(TestReflexUtil.makeReflexTestName(selectionTwo)); resultItem.setSelectionTwoValue(TestReflexUtil.makeReflexTestValue(selectionOne)); } else { resultItem.setSelectionTwoText(TestReflexUtil.makeReflexScriptName(selectionTwo)); resultItem.setSelectionTwoValue(TestReflexUtil.makeReflexScriptValue(selectionOne)); } } } } private String getResultForItem(AnalyzerResults result) { if(TypeOfTestResultService.ResultType.NUMERIC.matches(result.getResultType()) ){ return getRoundedToSignificantDigits( result ); } if ( TypeOfTestResultService.ResultType.isTextOnlyVariant(result.getResultType()) || GenericValidator.isBlankOrNull(result.getResultType()) || GenericValidator.isBlankOrNull(result.getResult())) { return result.getResult(); } //If it's readonly or the selectlist can not be gotten then we want the result //otherwise we want the id so the correct selection will be choosen if( result.isReadOnly() || result.getTestId() == null || result.getIsControl()){ return dictionaryDAO.getDictionaryById(result.getResult()).getDictEntry() ; }else{ return result.getResult(); } } private String getSignificantDigitsFromAnalyzerResults(AnalyzerResults result) { List<TestResult> testResults = testResultDAO.getActiveTestResultsByTest(result.getTestId()); if (GenericValidator.isBlankOrNull(result.getResult()) || testResults.isEmpty()) { return result.getResult(); } TestResult testResult = testResults.get(0); return testResult.getSignificantDigits(); } private String getRoundedToSignificantDigits(AnalyzerResults result) { if( result.getTestId() != null) { Double results; try { results = Double.valueOf(result.getResult()); } catch (NumberFormatException e) { return result.getResult(); } String significantDigitsAsString = getSignificantDigitsFromAnalyzerResults(result); if (GenericValidator.isBlankOrNull(significantDigitsAsString) || "-1".equals(significantDigitsAsString)) { return result.getResult(); } Integer significantDigits; try { significantDigits = Integer.parseInt(significantDigitsAsString); } catch (NumberFormatException e) { return result.getResult(); } if (significantDigits == 0) { return String.valueOf(Math.round(results)); } double power = Math.pow(10, significantDigits); return String.valueOf(Math.round(results * power) / power); }else{ return result.getResult(); } } private String getUnits(String units) { if (GenericValidator.isBlankOrNull(units) || "null".equals(units)) { return ""; } return units; } private List<Dictionary> getDictionaryResultList(AnalyzerResults result) { if ("N".equals(result.getResultType()) || "A".equals(result.getResultType()) || "R".equals(result.getResultType()) || GenericValidator.isBlankOrNull(result.getResultType()) || result.getTestId() == null) { return null; } List<Dictionary> dictionaryList = new ArrayList<Dictionary>(); List<TestResult> testResults = testResultDAO.getActiveTestResultsByTest( result.getTestId() ); for (TestResult testResult : testResults) { dictionaryList.add(dictionaryDAO.getDictionaryById(testResult.getValue())); } return dictionaryList; } protected String getPageTitleKey() { return "banner.menu.results.analyzer"; } protected String getPageSubtitleKey() { String key = analyzerNameToSubtitleKey.get(analyzer); if( key == null){ key = PluginMenuService.getInstance().getKeyForAction("/AnalyzerResults.do?type=" + analyzer); } return key; } @Override protected String getActualMessage( String messageKey){ String actualMessage = null; if( messageKey != null){ actualMessage = PluginMenuService.getInstance().getMenuLabel(LocalizationService.getCurrentLocale(), messageKey); } return actualMessage == null ? analyzer : actualMessage; } protected void setAnalyzerRequest(String requestType) { if (!GenericValidator.isBlankOrNull(requestType)) { analyzer = AnalyzerTestNameCache.instance().getDBNameForActionName(requestType); } } private boolean getQaEventByTestSection(Analysis analysis){ if(analysis==null) return false; if (analysis.getTestSection()!=null && analysis.getSampleItem().getSample()!=null) { Sample sample=analysis.getSampleItem().getSample(); List<SampleQaEvent> sampleQaEventsList=getSampleQaEvents(sample); for(SampleQaEvent event : sampleQaEventsList){ QAService qa = new QAService(event); if(!GenericValidator.isBlankOrNull(qa.getObservationValue( QAObservationType.SECTION )) && qa.getObservationValue( QAObservationType.SECTION ).equals(analysis.getTestSection().getNameKey())) return true; } } return false; } public List<SampleQaEvent> getSampleQaEvents(Sample sample){ SampleQaEventDAO sampleQaEventDAO = new SampleQaEventDAOImpl(); return sampleQaEventDAO.getSampleQaEventsBySample(sample); } }