diff --git a/frontend/src/App.js b/frontend/src/App.js index 9089bf434..f1e73c6c0 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -24,7 +24,8 @@ import AddOrder from "./components/addOrder/Index"; import ModifyOrder from "./components/modifyOrder/Index"; import RoutineReports from "./components/Reports/Routine"; import StudyReports from "./components/Reports/Study"; -import StudyValidation from "./components/validation/Study"; +// import StudyValidation from "./components/validation/Study"; +import StudyValidation from "./components/validation/Index"; import PathologyDashboard from "./components/pathology/PathologyDashboard"; import PathologyCaseView from "./components/pathology/PathologyCaseView"; import ImmunohistochemistryDashboard from "./components/immunohistochemistry/ImmunohistochemistryDashboard" @@ -291,7 +292,7 @@ export default function App() { } role="Global Administrator" config={appConfig} onAuth={onAuth} logout={logout} isLoggedIn={isLoggedIn} /> } role="Global Administrator" config={appConfig} onAuth={onAuth} logout={logout} isLoggedIn={isLoggedIn} /> } role="Global Administrator" config={appConfig} onAuth={onAuth} logout={logout} isLoggedIn={isLoggedIn} /> - } role="Global Administrator" config={appConfig} onAuth={onAuth} logout={logout} isLoggedIn={isLoggedIn} /> + } role="Global Administrator" config={appConfig} onAuth={onAuth} logout={logout} isLoggedIn={isLoggedIn} /> diff --git a/frontend/src/components/formModel/innitialValues/ValidationSearchFormValues.js b/frontend/src/components/formModel/innitialValues/ValidationSearchFormValues.js new file mode 100644 index 000000000..64fa5e884 --- /dev/null +++ b/frontend/src/components/formModel/innitialValues/ValidationSearchFormValues.js @@ -0,0 +1,95 @@ +export default { + resultList: [ + { + accessionNumber: "", + analysisId: "", + analysisMethod: "", + analysisStatusId: "", + childReflex: "", + considerRejectReason: "", + defaultResultValue: "", + dictionaryResults: [], + displayResultAsLog: "", + enumResultType: "", + failedValidation: "", + forceTechApproval: "", + hasQualifiedResult: "", + initialSampleCondition: "", + isGroupSeparator: "", + isModified: "", + lowerAbnormalRange: "", + lowerNormalRange: "", + multiSelectResultValues: "", + nationalId: "", + nextVisitDate: "", + nonconforming: "", + normal: "", + normalRange: "", + notIncludedInWorkplan: "", + note: "", + pastNotes: "", + patientInfo: "", + patientName: "", + qualifiedDictionaryId: "", + qualifiedResultId: "", + qualifiedResultValue: "", + rawResultDisplayType: "", + readOnly: "", + receivedDate: "", + refer: "", + referralCanceled: "", + referralId: "", + referralItem: "", + referralReasonId: "", + referredOut: "", + reflexGroup: "", + reflexJSONResult: "", + reflexParentGroup: "", + rejectReasonId: "", + rejected: "", + remarks: "", + remove: "", + removed: "", + reportable: "", + result: "", + resultDisplayType: "", + resultId: "", + resultLimitId: "", + resultType: "", + resultValue: "", + sampleGroupingNumber: "", + sampleSource: "", + sampleType: "", + sequenceAccessionNumber: "", + sequenceNumber: "", + servingAsTestGroupIdentifier: "", + shadowReferredOut: "", + shadowRejected: "", + shadowResultValue: "", + showSampleDetails: "", + siblingReflexKey: "", + significantDigits: "", + technician: "", + technicianSignatureId: "", + testDate: "", + testId: "", + testKit1InventoryId: "", + testKitId: "", + testKitInactive: "", + testKitInventoryId: "", + testMethod: "", + testName: "", + testSortOrder: "", + thisReflexKey: "", + unitsOfMeasure: "", + upperAbnormalRange: "", + upperNormalRange: "", + userChoiceReflex: "", + valid: "", + }], + accessionNumber: "", + methods: [{ + id: "", + value: "", + }], +} diff --git a/frontend/src/components/validation/Index.js b/frontend/src/components/validation/Index.js new file mode 100644 index 000000000..067fd33a6 --- /dev/null +++ b/frontend/src/components/validation/Index.js @@ -0,0 +1,15 @@ +import React, {useEffect, useState} from 'react' +import SearchForm from "./SearchForm"; +import Validation from "./Validation"; + +const Index = () => { + const [results, setResults] = useState(); + return ( + <> + + + + ) +} + +export default Index; diff --git a/frontend/src/components/validation/SearchForm.js b/frontend/src/components/validation/SearchForm.js new file mode 100644 index 000000000..3f5a2a2b9 --- /dev/null +++ b/frontend/src/components/validation/SearchForm.js @@ -0,0 +1,112 @@ +import React, {useState, useEffect} from 'react' +import {Button, Column, Form, FormLabel, Heading, Row, Section, Stack, TextInput} from "@carbon/react"; +import {FormattedMessage} from "react-intl"; +import {Formik, Field} from "formik"; +import ValidationSearchFormValues from "../formModel/innitialValues/ValidationSearchFormValues"; +import {getFromOpenElisServer} from "../utils/Utils"; + +const SearchForm = (props) => { + const [searchResults, setSearchResults] = useState(); + const validationResults = (data) => { + if (data) { + setSearchResults(data); + if (data.resultList) { + const newResultsList = data.resultList.map((data, idx) => { + let tempData = {...data} + tempData.id = idx + return tempData + }); + setSearchResults(prevState => ({ + ...prevState, + resultList: newResultsList + })); + } + } else { + props.setResults?.({resultList: []}); + } + } + + useEffect(() => { + props.setResults(searchResults) + }, [searchResults]); + + const handleSubmit = (values) => { + let searchEndPoint = "/rest/accessionValidationByRange?" + + "accessionNumber=" + values.accessionNumber + getFromOpenElisServer(searchEndPoint, validationResults); + } + + const handleChange = () => { + + } + + + return ( + <> + + {({ + values, + errors, + touched, + handleChange, + //handleBlur, + handleSubmit + }) => ( + +
+ + + +
+
+
+ + + +
+
+
+
+ +
+ + + {({field}) => + + } + +
+ +
+ + + + + +
+ +
+ )} +
+ + + ); + +} + +export default SearchForm; diff --git a/frontend/src/components/validation/Validation.js b/frontend/src/components/validation/Validation.js new file mode 100644 index 000000000..d4b485351 --- /dev/null +++ b/frontend/src/components/validation/Validation.js @@ -0,0 +1,366 @@ +import React, {useState} from 'react' +import {Field, Formik} from "formik"; +import { + Button, + Checkbox, + Column, + DatePicker, + DatePickerInput, + Form, + Grid, + Pagination, + Select, + SelectItem, + TextArea, + TextInput +} from "@carbon/react"; +import DataTable from "react-data-table-component"; +import {FormattedMessage} from "react-intl"; +import ValidationSearchFormValues from "../formModel/innitialValues/ValidationSearchFormValues"; +import {NotificationKinds} from "../common/CustomNotification"; +import {stringify} from "qs"; +import jp from "jsonpath"; +import {postToOpenElisServer} from "../utils/Utils"; + +const Validation = (props) => { + + const [page, setPage] = useState(0); + const [pageSize, setPageSize] = useState(0); + + const columns = [ + { + name: 'Sample Info', + cell: (row, index, column, id) => { + return renderCell(row, index, column, id); + }, + sortable: true, + width: "19rem" + }, + { + name: 'Test Name', + selector: row => row.testName, + sortable: true, + width: "10rem", + }, + { + name: 'Normal Range', + selector: row => row.normalRange, + sortable: true, + width: "7rem", + }, + { + name: 'Result', + cell: (row, index, column, id) => { + return renderCell(row, index, column, id); + }, + width: "8rem", + }, + { + name: 'Save', + cell: (row, index, column, id) => { + return renderCell(row, index, column, id); + }, + width: "8rem", + }, + { + name: 'Retest', + cell: (row, index, column, id) => { + return renderCell(row, index, column, id); + }, + width: "8rem", + }, + { + name: 'Notes', + cell: (row, index, column, id) => { + return renderCell(row, index, column, id); + }, + width: "16rem", + }, + + + ]; + + const handleSave = (values) => { + postToOpenElisServer("/rest/accessionValidationByRangeUpdate", + JSON.stringify(props.results), handleResponse); + } + const handleResponse = (response) => { + console.log(response); + } + + const handlePageChange = () => { + + } + + const handleChange = (e, rowId) => { + const {name, id, value} = e.target; + let form = props.results; + var jp = require('jsonpath'); + jp.value(form, name, value); + } + + const handleDatePickerChange = (date, rowId) => { + console.log("handleDatePickerChange:" + date) + const d = new Date(date).toLocaleDateString('fr-FR'); + var form = props.results; + var jp = require('jsonpath'); + jp.value(form, "resultList[" + rowId + "].sentDate_", d); + } + const handleCheckBox = (e, rowId) => { + handleChange(e, rowId) + } + const validateResults = (e, rowId) => { + handleChange(e, rowId) + } + + const renderCell = (row, index, column, id) => { + switch (column.name) { + case "Sample Info": + return ( + <> +
+ +
+ + ); + + case "Save": + return ( + <> + + {({field}) => + handleCheckBox(e, row.id)} + /> + } + + + ); + + case "Retest": + return ( + <> + + {({field}) => + handleCheckBox(e, row.id)} + /> + } + + + ); + + case "Notes": + return ( + <> +
+ +
+ + ); + + case "Result": + switch (row.resultType) { + case "D": + return + + case "N": + + return handleChange(e, row.id)} + /> + default: + return row.result + } + + } + return row.result; + } + const renderReferral = ({data}) => { + return ( +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ + handleDatePickerChange(date, data.id)} + > + + + +
+
+ ) + + } + return ( + <> + + {({ + values, + errors, + touched, + handleChange, + //handleBlur, + handleSubmit + }) => ( + +
+ + + + + + +
)} +
+ + ) +} + +export default Validation; diff --git a/src/main/java/org/openelisglobal/resultvalidation/action/util/ResultValidationItem.java b/src/main/java/org/openelisglobal/resultvalidation/action/util/ResultValidationItem.java index 86040a154..b83efb8f4 100644 --- a/src/main/java/org/openelisglobal/resultvalidation/action/util/ResultValidationItem.java +++ b/src/main/java/org/openelisglobal/resultvalidation/action/util/ResultValidationItem.java @@ -84,6 +84,8 @@ public class ResultValidationItem implements ResultItem, Serializable { private String qualificationResultId; private boolean hasQualifiedResult = false; private boolean normalResult; + private String normalRange; + private String patientName; private double lowerCritical; private double higherCritical; @@ -452,6 +454,22 @@ public void setNormalResult(boolean normalResult) { this.normalResult = normalResult; } + public String getPatientName() { + return patientName; + } + + public void setPatientName(String patientName) { + this.patientName = patientName; + } + + public String getNormalRange() { + return normalRange; + } + + public void setNormalRange(String normalRange) { + this.normalRange = normalRange; + } + public double getLowerCritical() { return lowerCritical; } diff --git a/src/main/java/org/openelisglobal/resultvalidation/bean/AnalysisItem.java b/src/main/java/org/openelisglobal/resultvalidation/bean/AnalysisItem.java index 7dc9ac02a..56b160932 100644 --- a/src/main/java/org/openelisglobal/resultvalidation/bean/AnalysisItem.java +++ b/src/main/java/org/openelisglobal/resultvalidation/bean/AnalysisItem.java @@ -36,7 +36,9 @@ public class AnalysisItem { @ValidAccessionNumber(groups = { ResultValidationForm.ResultValidation.class }) private String accessionNumber; + private String patientName; + private String patientInfo; @SafeHtml(level = SafeHtml.SafeListLevel.NONE, groups = { ResultValidationForm.ResultValidation.class }) private String result; @@ -75,6 +77,7 @@ public class AnalysisItem { private String resultId; private double lowerCritical; private double higherCritical; + private String normalRange; @SafeHtml(level = SafeHtml.SafeListLevel.NONE, groups = { ResultValidationForm.ResultValidation.class }) private String resultType; @@ -146,6 +149,10 @@ public class AnalysisItem { private boolean showAcceptReject = true; + private List methods; + private List referralOrganizations; + private List referralReasons; + private List dictionaryResults; private boolean isMultipleResultForSample = false; @@ -232,6 +239,13 @@ public String getResult() { return result; } + public String getNormalRange() { + return normalRange; + } + + public void setNormalRange(String normalRange) { + this.normalRange = normalRange; + } public void setReceivedDate(String receivedDate) { this.receivedDate = receivedDate; } @@ -537,6 +551,29 @@ public List getDictionaryResults() { return dictionaryResults; } + public List getMethods() { + return methods; + } + + public void setMethods(List methods) { + this.methods = methods; + } + + public List getReferralOrganizations() { + return referralOrganizations; + } + + public void setReferralOrganizations(List referralOrganizations) { + this.referralOrganizations = referralOrganizations; + } + + public List getReferralReasons() { + return referralReasons; + } + + public void setReferralReasons(List referralReasons) { + this.referralReasons = referralReasons; + } public void setAnalysisId(String analysisId) { this.analysisId = analysisId; } @@ -744,4 +781,20 @@ public double getHigherCritical() { public void setHigherCritical(double higherCritical) { this.higherCritical = higherCritical; } + + public String getPatientName() { + return patientName; + } + + public void setPatientName(String patientName) { + this.patientName = patientName; + } + + public String getPatientInfo() { + return patientInfo; + } + + public void setPatientInfo(String patientInfo) { + this.patientInfo = patientInfo; + } } \ No newline at end of file diff --git a/src/main/java/org/openelisglobal/resultvalidation/controller/rest/AccessionValidationRestController.java b/src/main/java/org/openelisglobal/resultvalidation/controller/rest/AccessionValidationRestController.java new file mode 100644 index 000000000..6a9daa83b --- /dev/null +++ b/src/main/java/org/openelisglobal/resultvalidation/controller/rest/AccessionValidationRestController.java @@ -0,0 +1,623 @@ +package org.openelisglobal.resultvalidation.controller.rest; + +import org.openelisglobal.analysis.service.AnalysisService; +import org.openelisglobal.analysis.valueholder.Analysis; +import org.openelisglobal.common.action.IActionConstants; +import org.openelisglobal.common.constants.Constants; +import org.openelisglobal.common.exception.LIMSRuntimeException; +import org.openelisglobal.common.log.LogEvent; +import org.openelisglobal.common.services.DisplayListService; +import org.openelisglobal.common.services.DisplayListService.ListType; +import org.openelisglobal.common.services.IResultSaveService; +import org.openelisglobal.common.services.IStatusService; +import org.openelisglobal.common.services.ResultSaveService; +import org.openelisglobal.common.services.StatusService.AnalysisStatus; +import org.openelisglobal.common.services.beanAdapters.ResultSaveBeanAdapter; +import org.openelisglobal.common.services.registration.ValidationUpdateRegister; +import org.openelisglobal.common.services.registration.interfaces.IResultUpdate; +import org.openelisglobal.common.services.serviceBeans.ResultSaveBean; +import org.openelisglobal.common.util.ConfigurationProperties; +import org.openelisglobal.common.util.IdValuePair; +import org.openelisglobal.common.util.validator.GenericValidator; +import org.openelisglobal.common.validator.BaseErrors; +import org.openelisglobal.dataexchange.orderresult.OrderResponseWorker.Event; +import org.openelisglobal.internationalization.MessageUtil; +import org.openelisglobal.note.service.NoteService; +import org.openelisglobal.note.service.NoteServiceImpl.NoteType; +import org.openelisglobal.note.valueholder.Note; +import org.openelisglobal.patient.service.PatientService; +import org.openelisglobal.patient.valueholder.Patient; +import org.openelisglobal.referencetables.service.ReferenceTablesService; +import org.openelisglobal.reports.service.DocumentTrackService; +import org.openelisglobal.reports.service.DocumentTypeService; +import org.openelisglobal.reports.valueholder.DocumentTrack; +import org.openelisglobal.result.action.util.ResultSet; +import org.openelisglobal.result.valueholder.Result; +import org.openelisglobal.resultvalidation.action.util.ResultValidationPaging; +import org.openelisglobal.resultvalidation.bean.AnalysisItem; +import org.openelisglobal.resultvalidation.controller.BaseResultValidationController; +import org.openelisglobal.resultvalidation.form.ResultValidationForm; +import org.openelisglobal.resultvalidation.service.ResultValidationService; +import org.openelisglobal.resultvalidation.util.ResultValidationSaveService; +import org.openelisglobal.resultvalidation.util.ResultsValidationUtility; +import org.openelisglobal.role.service.RoleService; +import org.openelisglobal.sample.valueholder.Sample; +import org.openelisglobal.samplehuman.service.SampleHumanService; +import org.openelisglobal.search.service.SearchResultsService; +import org.openelisglobal.spring.util.SpringContext; +import org.openelisglobal.systemuser.service.SystemUserService; +import org.openelisglobal.systemuser.service.UserService; +import org.openelisglobal.systemuser.valueholder.SystemUser; +import org.openelisglobal.test.beanItems.TestResultItem; +import org.openelisglobal.test.service.TestSectionService; +import org.openelisglobal.test.valueholder.TestSection; +import org.openelisglobal.testresult.service.TestResultService; +import org.openelisglobal.testresult.valueholder.TestResult; +import org.openelisglobal.typeoftestresult.service.TypeOfTestResultServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.validation.Errors; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.InvocationTargetException; +import java.util.*; + +import static org.apache.commons.validator.GenericValidator.isBlankOrNull; + +@Controller +@RequestMapping(value = "/rest/") +public class AccessionValidationRestController extends BaseResultValidationController { + @Autowired + private UserService userService; + @Autowired + private RoleService roleService; + + @Autowired + SearchResultsService searchService; + + + private static final String[] ALLOWED_FIELDS = new String[]{"testSectionId", "paging.currentPage", "testSection", + "testName", "resultList*.accessionNumber", "resultList*.analysisId", "resultList*.testId", + "resultList*.sampleId", "resultList*.resultType", "resultList*.sampleGroupingNumber", "resultList*.noteId", + "resultList*.resultId", "resultList*.hasQualifiedResult", "resultList*.sampleIsAccepted", + "resultList*.sampleIsRejected", "resultList*.result", "resultList*.qualifiedResultValue", + "resultList*.multiSelectResultValues", "resultList*.isAccepted", "resultList*.isRejected", + "resultList*.note"}; + + // autowiring not needed, using constructor injection + private AnalysisService analysisService; + private TestResultService testResultService; + private SampleHumanService sampleHumanService; + private DocumentTrackService documentTrackService; + private TestSectionService testSectionService; + private SystemUserService systemUserService; + private ResultValidationService resultValidationService; + private NoteService noteService; + + private final String RESULT_SUBJECT = "Result Note"; + private final String RESULT_TABLE_ID; + private final String RESULT_REPORT_ID; + + public AccessionValidationRestController(AnalysisService analysisService, TestResultService testResultService, + SampleHumanService sampleHumanService, DocumentTrackService documentTrackService, + TestSectionService testSectionService, SystemUserService systemUserService, + ReferenceTablesService referenceTablesService, DocumentTypeService documentTypeService, + ResultValidationService resultValidationService, NoteService noteService) { + + this.analysisService = analysisService; + this.testResultService = testResultService; + this.sampleHumanService = sampleHumanService; + this.documentTrackService = documentTrackService; + this.testSectionService = testSectionService; + this.systemUserService = systemUserService; + this.resultValidationService = resultValidationService; + this.noteService = noteService; + + RESULT_TABLE_ID = referenceTablesService.getReferenceTableByName("RESULT").getId(); + RESULT_REPORT_ID = documentTypeService.getDocumentTypeByName("resultExport").getId(); + } + + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.setAllowedFields(ALLOWED_FIELDS); + } + + // @RequestMapping(value = { "/AccessionValidationRange", "/ResultValidationByTestDate" }, method = RequestMethod.GET) + @GetMapping(value = "accessionValidationByRange", produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public ResultValidationForm showAccessionValidationRange(HttpServletRequest request, + @ModelAttribute("form") @Validated(ResultValidationForm.ResultValidation.class) ResultValidationForm oldForm) + throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { + + ResultValidationForm newForm = new ResultValidationForm(); + if (request.getParameter("accessionNumber") != null) { + newForm.setAccessionNumber(request.getParameter("accessionNumber")); + } else if (request.getParameter("date") != null) { + newForm.setTestDate(request.getParameter("date")); + } + newForm.setTestSectionId(oldForm.getTestSectionId()); + newForm.setTestSection(oldForm.getTestSection()); + return getResultValidation(request, newForm); + } + + private ResultValidationForm getResultValidation(HttpServletRequest request, ResultValidationForm form) + throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { + + + String patientName = ""; + String patientInfo = ""; + Patient patient = null; + List filteredresultList = new ArrayList<>(); + + request.getSession().setAttribute(SAVE_DISABLED, "true"); + + ResultValidationPaging paging = new ResultValidationPaging(); + String newPage = request.getParameter("page"); + + TestSection ts = null; + form.setSearchFinished(false); + + if (GenericValidator.isBlankOrNull(newPage)) { + + // load testSections for drop down + String resultsRoleId = roleService.getRoleByName(Constants.ROLE_VALIDATION).getId(); + List testSections = userService.getUserTestSections(getSysUserId(request), resultsRoleId); + form.setTestSections(testSections); + form.setTestSectionsByName(DisplayListService.getInstance().getList(ListType.TEST_SECTION_BY_NAME)); + + if (!GenericValidator.isBlankOrNull(form.getTestSectionId())) { + ts = testSectionService.get(form.getTestSectionId()); + } + + List resultList; + + ResultsValidationUtility resultsValidationUtility = SpringContext.getBean(ResultsValidationUtility.class); + if (request.getRequestURI().contains("AccessionValidationRange")) { + setRequestType(ts == null ? MessageUtil.getMessage("validation.range.title") : ts.getLocalizedName()); + } else if (request.getRequestURI().contains("ResultValidationByTestDate")) { + setRequestType(ts == null ? MessageUtil.getMessage("validation.date.title") : ts.getLocalizedName()); + } + if (!(GenericValidator.isBlankOrNull(form.getTestSectionId()) + && GenericValidator.isBlankOrNull(form.getAccessionNumber()) + && GenericValidator.isBlankOrNull(form.getTestDate()))) { + + resultList = resultsValidationUtility.getResultValidationList(getValidationStatus(), + form.getTestSectionId(), form.getAccessionNumber(), form.getTestDate()); + + filteredresultList = userService.filterAnalysisResultsByLabUnitRoles(getSysUserId(request), resultList, + Constants.ROLE_VALIDATION); + request.setAttribute("pageSize", filteredresultList.size()); + form.setSearchFinished(true); + } else { + resultList = new ArrayList<>(); + } + paging.setDatabaseResults(request, form, filteredresultList); + } else { + paging.page(request, form, Integer.parseInt(newPage)); + } + + addFlashMsgsToRequest(request); + + for (AnalysisItem analysisItem : filteredresultList) { + analysisItem.setPatientName(patientName); + analysisItem.setMethods(DisplayListService.getInstance().getList(ListType.METHODS)); + analysisItem.setReferralOrganizations( + DisplayListService.getInstance().getList(ListType.REFERRAL_ORGANIZATIONS)); + analysisItem.setReferralReasons( + DisplayListService.getInstance().getList(DisplayListService.ListType.REFERRAL_REASONS)); + + } + + return form; + } + + public List getValidationStatus() { + List validationStatus = new ArrayList<>(); + validationStatus.add(Integer + .parseInt(SpringContext.getBean(IStatusService.class).getStatusID(AnalysisStatus.TechnicalAcceptance))); + if (ConfigurationProperties.getInstance() + .isPropertyValueEqual(ConfigurationProperties.Property.VALIDATE_REJECTED_TESTS, "true")) { + validationStatus.add(Integer.parseInt( + SpringContext.getBean(IStatusService.class).getStatusID(AnalysisStatus.TechnicalRejected))); + } + + return validationStatus; + } + + + @PostMapping(value = "accessionValidationByRangeUpdate", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public ResultValidationForm showAccessionValidationRangeSave(HttpServletRequest request, + @Validated(ResultValidationForm.ResultValidation.class) + @RequestBody ResultValidationForm form, + BindingResult result) + throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { + + System.out.println("Post:LogbookResultsRestController:SUCCESS"); + System.out.println("Post:LogbookResultsRestController:" + form); + + if ("true".equals(request.getParameter("pageResults"))) { + return getResultValidation(request, form); + } + form.setSearchFinished(false); + + if (result.hasErrors()) { + saveErrors(result); + } + List updaters = ValidationUpdateRegister.getRegisteredUpdaters(); + boolean areListeners = !updaters.isEmpty(); + + request.getSession().setAttribute(SAVE_DISABLED, "true"); + + List checkPagedResults = (List) request.getSession() + .getAttribute(IActionConstants.RESULTS_SESSION_CACHE); + List checkResults = (List) checkPagedResults.get(0); + if (checkResults.size() == 0) { + System.out.println("Operation failed"); + LogEvent.logDebug(this.getClass().getName(), "ResultValidation()", "Attempted save of stale page."); +// Errors errors = new BaseErrors(); +// errors.reject("alert.error", "An error occured while saving"); +// saveErrors(errors); +// redirectAttributes.addFlashAttribute(FWD_FAIL_INSERT, true); +// return findForward(FWD_SUCCESS_INSERT, form); + return form; +// return new ModelAndView("redirect:/ResultValidation?blank=true"); + } + + ResultValidationPaging paging = new ResultValidationPaging(); + paging.updatePagedResults(request, form); + List resultItemList = paging.getResults(request); + + String testSectionName = form.getTestSection(); + String testName = form.getTestName(); + setRequestType(testSectionName); + // ---------------------- + String url = request.getRequestURL().toString(); + + Errors errors = validateModifiedItems(resultItemList); + + if (errors.hasErrors()) { + saveErrors(errors); +// return findForward(FWD_VALIDATION_ERROR, form); + return form; + } + + createSystemUser(); + + // Update Lists + List analysisUpdateList = new ArrayList<>(); + ArrayList sampleUpdateList = new ArrayList<>(); + ArrayList noteUpdateList = new ArrayList<>(); + ArrayList resultUpdateList = new ArrayList<>(); + List deletableList = new ArrayList<>(); + + // wrapper object for holding modifedResultSet and newResultSet + IResultSaveService resultSaveService = new ResultValidationSaveService(); + +// if (testSectionName.equals("serology")) { +// createUpdateElisaList(resultItemList, analysisUpdateList); +// } else { + createUpdateList(resultItemList, analysisUpdateList, resultUpdateList, noteUpdateList, deletableList, + resultSaveService, areListeners); +// } + + try { + resultValidationService.persistdata(deletableList, analysisUpdateList, resultUpdateList, resultItemList, + sampleUpdateList, noteUpdateList, resultSaveService, updaters, getSysUserId(request)); + } catch (LIMSRuntimeException e) { + LogEvent.logErrorStack(e); + } + + for (IResultUpdate updater : updaters) { + +// updater.postTransactionalCommitUpdate(resultSaveService); + } + + // route save back to RetroC specific ResultValidationRetroCAction + // if + // (ConfigurationProperties.getInstance().isPropertyValueEqual(Property.configurationName, + // "CI RetroCI")) + System.out.println("Operation success"); +// redirectAttributes.addFlashAttribute(FWD_SUCCESS, true); + if (isBlankOrNull(testSectionName)) { +// return findForward(forward, form); + return form; + } else { + Map params = new HashMap<>(); + params.put("type", testSectionName); + params.put("test", testName); +// return getForwardWithParameters(findForward(forward, form), params); + } + + + return (form); + } + + private Errors validateModifiedItems(List resultItemList) { + Errors errors = new BaseErrors(); + + for (AnalysisItem item : resultItemList) { + Errors errorList = new BaseErrors(); + validateQuantifiableItems(item, errorList); + + if (errorList.hasErrors()) { + StringBuilder augmentedAccession = new StringBuilder(item.getAccessionNumber()); + augmentedAccession.append(" : "); + augmentedAccession.append(item.getTestName()); + String errorMsg = "errors.followingAccession"; + errors.reject(errorMsg, new String[]{augmentedAccession.toString()}, errorMsg); + errors.addAllErrors(errorList); + + } + } + + return errors; + } + + public void validateQuantifiableItems(AnalysisItem analysisItem, Errors errorList) { + if (analysisItem.isHasQualifiedResult() && isBlankOrNull(analysisItem.getQualifiedResultValue()) + && analysisItemWillBeUpdated(analysisItem)) { + errorList.reject("errors.missing.result.details", new String[]{"Result"}, + "errors.missing.result.details"); + } + // verify that qualifiedResultValue has been entered if required + if (!isBlankOrNull(analysisItem.getQualifiedDictionaryId())) { + String[] qualifiedDictionaryIds = analysisItem.getQualifiedDictionaryId().replace("[", "").replace("]", "") + .split(","); + Set qualifiedDictIdsSet = new HashSet<>(Arrays.asList(qualifiedDictionaryIds)); + + if (qualifiedDictIdsSet.contains(analysisItem.getResult()) + && isBlankOrNull(analysisItem.getQualifiedResultValue())) { + errorList.reject("errors.missing.result.details", new String[]{"Result"}, + "errors.missing.result.details"); + + } + + } + + } + + private void createUpdateList(List analysisItems, List analysisUpdateList, + List resultUpdateList, List noteUpdateList, List deletableList, + IResultSaveService resultValidationSave, boolean areListeners) { + + List analysisIdList = new ArrayList<>(); + + for (AnalysisItem analysisItem : analysisItems) { + if (!analysisItem.isReadOnly() && analysisItemWillBeUpdated(analysisItem)) { + + Analysis analysis = analysisService.get(analysisItem.getAnalysisId()); + analysis.setSysUserId(getSysUserId(request)); + + if (!analysisIdList.contains(analysis.getId())) { + + if (analysisItem.getIsAccepted()) { + analysis.setStatusId( + SpringContext.getBean(IStatusService.class).getStatusID(AnalysisStatus.Finalized)); + analysis.setReleasedDate(new java.sql.Date(Calendar.getInstance().getTimeInMillis())); + analysisIdList.add(analysis.getId()); + analysisUpdateList.add(analysis); + } + + if (analysisItem.getIsRejected()) { + analysis.setStatusId(SpringContext.getBean(IStatusService.class) + .getStatusID(AnalysisStatus.BiologistRejected)); + analysisIdList.add(analysis.getId()); + analysisUpdateList.add(analysis); + } + } + + createNeededNotes(analysisItem, analysis, noteUpdateList); + + if (areResults(analysisItem)) { + List results = createResultFromAnalysisItem(analysisItem, analysis, analysis, + noteUpdateList, deletableList); + for (Result result : results) { + resultUpdateList.add(result); + + if (areListeners) { + addResultSets(analysis, result, resultValidationSave); + } + } + } + } + } + } + + private void createNeededNotes(AnalysisItem analysisItem, Analysis analysis, List noteUpdateList) { + if (analysisItem.getIsRejected()) { + Note note = noteService.createSavableNote(analysis, NoteType.INTERNAL, + MessageUtil.getMessage("validation.note.retest"), RESULT_SUBJECT, getSysUserId(request)); + noteUpdateList.add(note); + } + + if (!GenericValidator.isBlankOrNull(analysisItem.getNote())) { + NoteType noteType = analysisItem.getIsAccepted() ? NoteType.EXTERNAL : NoteType.INTERNAL; + Note note = noteService.createSavableNote(analysis, noteType, analysisItem.getNote(), RESULT_SUBJECT, + getSysUserId(request)); + noteUpdateList.add(note); + } + } + + private void addResultSets(Analysis analysis, Result result, IResultSaveService resultValidationSave) { + Sample sample = analysis.getSampleItem().getSample(); + Patient patient = sampleHumanService.getPatientForSample(sample); + if (finalResultAlreadySent(result)) { + result.setResultEvent(Event.CORRECTION); + resultValidationSave.getModifiedResults() + .add(new ResultSet(result, null, null, patient, sample, null, false)); + } else { + result.setResultEvent(Event.FINAL_RESULT); + resultValidationSave.getNewResults().add(new ResultSet(result, null, null, patient, sample, null, false)); + } + } + + // TO DO bug falsely triggered when preliminary result is sent, fails, retries + // and succeeds + private boolean finalResultAlreadySent(Result result) { + List documents = documentTrackService.getByTypeRecordAndTable(RESULT_REPORT_ID, RESULT_TABLE_ID, + result.getId()); + return documents.size() > 0; + } + + private boolean analysisItemWillBeUpdated(AnalysisItem analysisItem) { + return analysisItem.getIsAccepted() || analysisItem.getIsRejected(); + } + + private void createUpdateElisaList(List resultItems, List analysisUpdateList) { + + for (AnalysisItem resultItem : resultItems) { + + if (resultItem.getIsAccepted()) { + + List acceptedAnalysisList = createAnalysisFromElisaAnalysisItem(resultItem); + + for (Analysis analysis : acceptedAnalysisList) { + analysis.setStatusId( + SpringContext.getBean(IStatusService.class).getStatusID(AnalysisStatus.Finalized)); + analysisUpdateList.add(analysis); + } + } + + if (resultItem.getIsRejected()) { + List rejectedAnalysisList = createAnalysisFromElisaAnalysisItem(resultItem); + + for (Analysis analysis : rejectedAnalysisList) { + analysis.setStatusId( + SpringContext.getBean(IStatusService.class).getStatusID(AnalysisStatus.BiologistRejected)); + analysisUpdateList.add(analysis); + } + + } + } + } + + private List createAnalysisFromElisaAnalysisItem(AnalysisItem analysisItem) { + + List analysisList = new ArrayList<>(); + + Analysis analysis = new Analysis(); + + if (!isBlankOrNull(analysisItem.getMurexResult())) { + analysis = getAnalysisFromId(analysisItem.getMurexAnalysisId()); + analysisList.add(analysis); + } + if (!isBlankOrNull(analysisItem.getBiolineResult())) { + analysis = getAnalysisFromId(analysisItem.getBiolineAnalysisId()); + analysisList.add(analysis); + } + if (!isBlankOrNull(analysisItem.getIntegralResult())) { + analysis = getAnalysisFromId(analysisItem.getIntegralAnalysisId()); + analysisList.add(analysis); + } + if (!isBlankOrNull(analysisItem.getVironostikaResult())) { + analysis = getAnalysisFromId(analysisItem.getVironostikaAnalysisId()); + analysisList.add(analysis); + } + if (!isBlankOrNull(analysisItem.getGenieIIResult())) { + analysis = getAnalysisFromId(analysisItem.getGenieIIAnalysisId()); + analysisList.add(analysis); + } + if (!isBlankOrNull(analysisItem.getGenieII10Result())) { + analysis = getAnalysisFromId(analysisItem.getGenieII10AnalysisId()); + analysisList.add(analysis); + } + if (!isBlankOrNull(analysisItem.getGenieII100Result())) { + analysis = getAnalysisFromId(analysisItem.getGenieII100AnalysisId()); + analysisList.add(analysis); + } + if (!isBlankOrNull(analysisItem.getWesternBlot1Result())) { + analysis = getAnalysisFromId(analysisItem.getWesternBlot1AnalysisId()); + analysisList.add(analysis); + } + if (!isBlankOrNull(analysisItem.getWesternBlot2Result())) { + analysis = getAnalysisFromId(analysisItem.getWesternBlot2AnalysisId()); + analysisList.add(analysis); + } + if (!isBlankOrNull(analysisItem.getP24AgResult())) { + analysis = getAnalysisFromId(analysisItem.getP24AgAnalysisId()); + analysisList.add(analysis); + } + if (!isBlankOrNull(analysisItem.getInnoliaResult())) { + analysis = getAnalysisFromId(analysisItem.getInnoliaAnalysisId()); + analysisList.add(analysis); + } + + analysisList.add(analysis); + + return analysisList; + } + + private Analysis getAnalysisFromId(String id) { + Analysis analysis = analysisService.get(id); + analysis.setSysUserId(getSysUserId(request)); + + return analysis; + } + + private List createResultFromAnalysisItem(AnalysisItem analysisItem, Analysis analysis, Analysis analysis2, + List noteUpdateList, List deletableList) { + + ResultSaveBean bean = ResultSaveBeanAdapter.fromAnalysisItem(analysisItem); + ResultSaveService resultSaveService = new ResultSaveService(analysis, getSysUserId(request)); + List results = resultSaveService.createResultsFromTestResultItem(bean, deletableList); + if (analysisService.patientReportHasBeenDone(analysis) && resultSaveService.isUpdatedResult()) { + analysis.setCorrectedSincePatientReport(true); + noteUpdateList.add(noteService.createSavableNote(analysis, NoteType.EXTERNAL, + MessageUtil.getMessage("note.corrected.result"), RESULT_SUBJECT, getSysUserId(request))); + } + return results; + } + + protected TestResult getTestResult(AnalysisItem analysisItem) { + TestResult testResult = null; + if (TypeOfTestResultServiceImpl.ResultType.DICTIONARY.matches(analysisItem.getResultType())) { + testResult = testResultService.getTestResultsByTestAndDictonaryResult(analysisItem.getTestId(), + analysisItem.getResult()); + } else { + List testResultList = testResultService.getActiveTestResultsByTest(analysisItem.getTestId()); + // we are assuming there is only one testResult for a numeric type + // result + if (!testResultList.isEmpty()) { + testResult = testResultList.get(0); + } + } + return testResult; + } + + private boolean areResults(AnalysisItem item) { + return !(isBlankOrNull(item.getResult()) + || (TypeOfTestResultServiceImpl.ResultType.DICTIONARY.matches(item.getResultType()) + && "0".equals(item.getResult()))) + || (TypeOfTestResultServiceImpl.ResultType.isMultiSelectVariant(item.getResultType()) + && !isBlankOrNull(item.getMultiSelectResultValues())); + } + + private SystemUser createSystemUser() { + return systemUserService.get(getSysUserId(request)); + } + + @Override + protected String findLocalForward(String forward) { + if (FWD_SUCCESS.equals(forward)) { + return "accessionValidationRangeDefinition"; + } else if (FWD_FAIL.equals(forward)) { + return "homePageDefinition"; + } else if (FWD_SUCCESS_INSERT.equals(forward)) { + return "redirect:/AccessionValidationRange"; + } else if (FWD_FAIL_INSERT.equals(forward)) { + return "homePageDefinition"; + } else if (FWD_VALIDATION_ERROR.equals(forward)) { + return "accessionValidationRangeDefinition"; + } else { + return "PageNotFound"; + } + } + +} diff --git a/src/main/java/org/openelisglobal/resultvalidation/util/ResultsValidationUtility.java b/src/main/java/org/openelisglobal/resultvalidation/util/ResultsValidationUtility.java index 5cbf31e40..000054863 100644 --- a/src/main/java/org/openelisglobal/resultvalidation/util/ResultsValidationUtility.java +++ b/src/main/java/org/openelisglobal/resultvalidation/util/ResultsValidationUtility.java @@ -464,6 +464,9 @@ private void setResultLimitDependencies(ResultLimit resultLimit, ResultValidatio resultLimit.getLowCritical() == Double.NEGATIVE_INFINITY ? 0 : resultLimit.getLowCritical()); testItem.setHigherCritical( resultLimit.getHighCritical() == Double.POSITIVE_INFINITY ? 0 : resultLimit.getHighCritical()); + + testItem.setNormalRange(SpringContext.getBean(ResultLimitService.class).getDisplayReferenceRange( + resultLimit, testResults.isEmpty() ? "0" : testResults.get(0).getSignificantDigits(), " - ")); } } @@ -605,6 +608,8 @@ public final List testResultListToAnalysisItemList(List