package edu.ualberta.med.biobank.common.action.scanprocess; import java.text.MessageFormat; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.hibernate.Session; import edu.ualberta.med.biobank.common.action.ActionContext; import edu.ualberta.med.biobank.common.action.exception.ActionException; import edu.ualberta.med.biobank.common.action.scanprocess.data.AssignProcessInfo; import edu.ualberta.med.biobank.common.action.scanprocess.result.CellProcessResult; import edu.ualberta.med.biobank.common.action.scanprocess.result.ScanProcessResult; import edu.ualberta.med.biobank.common.action.specimen.SpecimenActionHelper; import edu.ualberta.med.biobank.common.action.specimen.SpecimenIsUsedInDispatchAction; import edu.ualberta.med.biobank.common.permission.specimen.SpecimenAssignPermission; import edu.ualberta.med.biobank.common.util.RowColPos; import edu.ualberta.med.biobank.model.ContainerType; import edu.ualberta.med.biobank.model.Specimen; public class SpecimenAssignProcessAction extends ServerProcessAction { private static final long serialVersionUID = 1L; private AssignProcessInfo data; // multiple cells assign process public SpecimenAssignProcessAction(AssignProcessInfo data, Integer currentWorkingCenterId, Map<RowColPos, CellInfo> cells, boolean isRescanMode, Locale locale) { super(currentWorkingCenterId, cells, isRescanMode, locale); this.data = data; } // single cell assign process public SpecimenAssignProcessAction(AssignProcessInfo data, Integer currentWorkingCenterId, CellInfo cell, Locale locale) { super(currentWorkingCenterId, cell, locale); this.data = data; } @Override protected ScanProcessResult getScanProcessResult( Map<RowColPos, CellInfo> cells, boolean isRescanMode) throws ActionException { ScanProcessResult res = new ScanProcessResult(); res.setResult(cells, internalProcessScanResult(session, cells, isRescanMode)); return res; } protected CellInfoStatus internalProcessScanResult(Session session, Map<RowColPos, CellInfo> cells, boolean rescanMode) throws ActionException { AssignProcessInfo assignData = data; CellInfoStatus currentScanState = CellInfoStatus.EMPTY; Map<RowColPos, Boolean> movedAndMissingSpecimensFromPallet = new HashMap<RowColPos, Boolean>(); for (int row = 0; row < assignData.getPalletRowCapacity(actionContext); row++) { for (int col = 0; col < assignData .getPalletColCapacity(actionContext); col++) { RowColPos rcp = new RowColPos(row, col); CellInfo cell = cells.get(rcp); if (!rescanMode || cell == null || cell.getStatus() == null || cell.getStatus() == CellInfoStatus.EMPTY || cell.getStatus() == CellInfoStatus.ERROR || cell.getStatus() == CellInfoStatus.MISSING) { Specimen expectedSpecimen = assignData .getExpectedSpecimen(session, row, col); if (expectedSpecimen != null) { if (cell == null) { cell = new CellInfo(rcp.getRow(), rcp.getCol(), null, null); cells.put(rcp, cell); } cell.setExpectedSpecimenId(expectedSpecimen.getId()); } if (cell != null) { internalProcessCellAssignStatus(cell, movedAndMissingSpecimensFromPallet); } } CellInfoStatus newStatus = CellInfoStatus.EMPTY; if (cell != null) { newStatus = cell.getStatus(); } currentScanState = currentScanState.mergeWith(newStatus); } } return currentScanState; } @Override protected CellProcessResult getCellProcessResult(CellInfo cell) throws ActionException { CellProcessResult res = new CellProcessResult(); internalProcessCellAssignStatus(cell, null); res.setResult(cell); return res; } /** * set the status of the cell */ protected CellInfoStatus internalProcessCellAssignStatus(CellInfo scanCell, Map<RowColPos, Boolean> movedAndMissingSpecimensFromPallet) throws ActionException { Specimen expectedSpecimen = null; if (scanCell.getExpectedSpecimenId() != null) { expectedSpecimen = actionContext.load(Specimen.class, scanCell.getExpectedSpecimenId()); } String value = scanCell.getValue(); String positionString = data .getPalletLabel(session) + data.getContainerType(session, actionContext) .getPositionString( new RowColPos( scanCell .getRow(), scanCell.getCol())); if (value == null) { // no specimen scanned updateCellAsMissing(positionString, scanCell, expectedSpecimen, movedAndMissingSpecimensFromPallet); } else { Specimen foundSpecimen = searchSpecimen(session, value); if (foundSpecimen == null) { updateCellAsNotFound(positionString, scanCell); } else if (!foundSpecimen.getCurrentCenter().getId() .equals(currentWorkingCenterId)) { updateCellAsInOtherSite(positionString, scanCell, foundSpecimen); } else if (expectedSpecimen != null && !foundSpecimen.equals(expectedSpecimen)) { updateCellAsPositionAlreadyTaken(positionString, scanCell, expectedSpecimen, foundSpecimen); } else { scanCell.setSpecimenId(foundSpecimen.getId()); if (expectedSpecimen != null) { // specimen scanned is already registered at this // position (everything is ok !) scanCell.setStatus(CellInfoStatus.FILLED); scanCell.setTitle(foundSpecimen.getCollectionEvent() .getPatient().getPnumber()); scanCell.setSpecimenId(expectedSpecimen.getId()); } else { ContainerType cType = data.getContainerType(session, actionContext); if (cType.getSpecimenTypes().contains( foundSpecimen.getSpecimenType())) { if (foundSpecimen.getSpecimenPosition() != null && foundSpecimen.getSpecimenPosition() .getContainer() != null) { // moved ? processCellWithPreviousPosition(session, scanCell, positionString, foundSpecimen, movedAndMissingSpecimensFromPallet); } else { // new in pallet if (new SpecimenIsUsedInDispatchAction( foundSpecimen.getId()).run(actionContext) .isTrue()) { updateCellAsDispatchedError( positionString, scanCell, foundSpecimen); } else { scanCell.setStatus(CellInfoStatus.NEW); scanCell.setTitle(foundSpecimen .getCollectionEvent().getPatient() .getPnumber()); } } } else { // pallet can't hold this specimen type updateCellAsTypeError(positionString, scanCell, foundSpecimen, cType); } } } } return scanCell.getStatus(); } /** * specimen missing */ private void updateCellAsMissing(String position, CellInfo scanCell, Specimen missingSpecimen, Map<RowColPos, Boolean> movedAndMissingSpecimensFromPallet) { RowColPos rcp = new RowColPos(scanCell.getRow(), scanCell.getCol()); Boolean posHasMovedSpecimen = movedAndMissingSpecimensFromPallet .get(rcp); if (!Boolean.TRUE.equals(posHasMovedSpecimen)) { scanCell.setStatus(CellInfoStatus.MISSING); scanCell.setInformation(MessageFormat.format(Messages.getString( "ScanAssign.scanStatus.specimen.missing", locale), //$NON-NLS-1$ missingSpecimen.getInventoryId())); scanCell.setTitle("?"); //$NON-NLS-1$ // MISSING in {0}\: specimen {1} from visit {2} (patient {3}) // missing appendNewLog(MessageFormat.format(Messages.getString( "ScanAssign.activitylog.specimen.missing", locale), //$NON-NLS-1$ position, missingSpecimen.getInventoryId(), missingSpecimen .getCollectionEvent().getVisitNumber(), missingSpecimen .getCollectionEvent().getPatient().getPnumber())); movedAndMissingSpecimensFromPallet.put(rcp, true); } else { movedAndMissingSpecimensFromPallet.remove(rcp); scanCell.setStatus(CellInfoStatus.EMPTY); } } /** * specimen not found in site (not yet linked ?) */ private void updateCellAsNotFound(String position, CellInfo scanCell) { scanCell.setStatus(CellInfoStatus.ERROR); scanCell.setInformation(Messages.getString( "ScanAssign.scanStatus.specimen.notfound", locale));//$NON-NLS-1$ appendNewLog(MessageFormat.format(Messages.getString( "ScanAssign.activitylog.specimen.notfound", locale), //$NON-NLS-1$ position, scanCell.getValue())); } /** * specimen found but another specimen already at this position */ private void updateCellAsPositionAlreadyTaken(String position, CellInfo scanCell, Specimen expectedSpecimen, Specimen foundSpecimen) { scanCell.setStatus(CellInfoStatus.ERROR); scanCell.setInformation(Messages.getString( "ScanAssign.scanStatus.specimen.positionTakenError", locale)); //$NON-NLS-1$ scanCell.setTitle("!"); //$NON-NLS-1$ appendNewLog(MessageFormat.format(Messages.getString( "ScanAssign.activitylog.specimen.positionTaken", locale), //$NON-NLS-1$ position, expectedSpecimen.getInventoryId(), expectedSpecimen .getCollectionEvent().getPatient().getPnumber(), foundSpecimen .getInventoryId(), foundSpecimen.getCollectionEvent() .getPatient().getPnumber())); } /** * this cell has already a position. Check if it was on the pallet or not * * @throws Exception */ private void processCellWithPreviousPosition(Session session, CellInfo scanCell, String positionString, Specimen foundSpecimen, Map<RowColPos, Boolean> movedAndMissingSpecimensFromPallet) { if (foundSpecimen.getSpecimenPosition() != null && foundSpecimen .getSpecimenPosition().getContainer().equals( data.getPallet(session))) { // same pallet RowColPos rcp = new RowColPos(scanCell.getRow(), scanCell.getCol()); RowColPos foundSpecPosition = new RowColPos(foundSpecimen .getSpecimenPosition().getRow(), foundSpecimen.getSpecimenPosition().getCol()); if (!foundSpecPosition.equals(rcp)) { // moved inside the same pallet updateCellAsMoved(positionString, scanCell, foundSpecimen); RowColPos movedFromPosition = foundSpecPosition; Boolean posHasMissing = movedAndMissingSpecimensFromPallet .get(movedFromPosition); if (Boolean.TRUE.equals(posHasMissing)) { // missing position has already been processed: remove // the MISSING flag // missingSpecimen.setStatus(UICellStatus.EMPTY); // missingSpecimen.setTitle(""); movedAndMissingSpecimensFromPallet .remove(movedFromPosition); } else { // missing position has not yet been processed movedAndMissingSpecimensFromPallet.put(movedFromPosition, true); } } } else { // old position was on another pallet updateCellAsMoved(positionString, scanCell, foundSpecimen); } } private void updateCellAsMoved(String position, CellInfo scanCell, Specimen foundSpecimen) { String expectedPosition = SpecimenActionHelper.getPositionString( foundSpecimen, true, false); if (expectedPosition == null) { expectedPosition = "none"; //$NON-NLS-1$ } scanCell.setStatus(CellInfoStatus.MOVED); scanCell.setTitle(foundSpecimen.getCollectionEvent().getPatient() .getPnumber()); scanCell.setInformation(MessageFormat.format( Messages.getString("ScanAssign.scanStatus.specimen.moved", locale), //$NON-NLS-1$ expectedPosition)); appendNewLog(MessageFormat .format(Messages.getString( "ScanAssign.activitylog.specimen.moved", locale), //$NON-NLS-1$ position, scanCell.getValue(), expectedPosition)); } private void updateCellAsInOtherSite(String position, CellInfo scanCell, Specimen foundSpecimen) { String currentPosition = SpecimenActionHelper.getPositionString( foundSpecimen, true, false); if (currentPosition == null) { currentPosition = "none"; //$NON-NLS-1$ } String siteName = foundSpecimen.getCurrentCenter().getNameShort(); scanCell.setStatus(CellInfoStatus.ERROR); scanCell.setTitle(foundSpecimen.getCollectionEvent().getPatient() .getPnumber()); scanCell.setInformation(MessageFormat.format(Messages.getString( "ScanAssign.scanStatus.specimen.otherSite", locale), //$NON-NLS-1$ siteName)); appendNewLog(MessageFormat.format(Messages.getString( "ScanAssign.activitylog.specimen.otherSite", locale), //$NON-NLS-1$ position, scanCell.getValue(), siteName, currentPosition)); } private void updateCellAsTypeError(String position, CellInfo scanCell, Specimen foundSpecimen, ContainerType containerType) { String palletType = containerType.getName(); String sampleType = foundSpecimen.getSpecimenType().getName(); scanCell.setTitle(foundSpecimen.getCollectionEvent().getPatient() .getPnumber()); scanCell.setStatus(CellInfoStatus.ERROR); scanCell.setInformation(MessageFormat.format(Messages.getString( "ScanAssign.scanStatus.specimen.typeError", locale), //$NON-NLS-1$ palletType, sampleType)); appendNewLog(MessageFormat.format(Messages.getString( "ScanAssign.activitylog.specimen.typeError", locale), //$NON-NLS-1$ position, palletType, sampleType)); } private void updateCellAsDispatchedError(String positionString, CellInfo scanCell, Specimen foundSpecimen) { scanCell.setTitle(foundSpecimen.getCollectionEvent().getPatient() .getPnumber()); scanCell.setStatus(CellInfoStatus.ERROR); scanCell.setInformation(Messages.getString( "ScanAssign.scanStatus.specimen.dispatchedError", locale)); //$NON-NLS-1$ appendNewLog(MessageFormat.format(Messages.getString( "ScanAssign.activitylog.specimen.dispatchedError", locale), //$NON-NLS-1$ positionString)); } @Override public boolean isAllowed(ActionContext context) throws ActionException { return new SpecimenAssignPermission(currentWorkingCenterId).isAllowed( context); } }