/* * ACEVoidTransactionActionImpl * * 07/17/2003 * * Copyright: * Licensed Materials - Property of IBM * "Restricted Materials of IBM" * 5724-AEF * (C) Copyright IBM Corp. 2003. * * %W% %E% */ package com.ibm.retail.AEF.action; import com.ibm.retail.AEF.automation.*; import com.ibm.retail.AEF.util.*; import com.ibm.retail.si.util.*; import com.ibm.retail.si.Copyright; import com.ibm.retail.AEF.factory.*; import com.ibm.retail.AEF.thread.*; import com.ibm.retail.AEF.data.*; import com.ibm.retail.AEF.session.*; import java.util.*; import java.rmi.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * ACEVoidTransactionActionImpl is a class which the POSAutomationProvider uses to * void the current transaction. * */ public class ACEVoidTransactionActionImpl extends ACEActionImpl { static String copyright() { return com.ibm.retail.si.Copyright.IBM_COPYRIGHT_SHORT; } private static AEFPerfTrace perfTrace = AEFPerfTrace.getInstance(); /** * Constructor * * @param request The ActionRequest which contains a HashMap of arguments. * @exception AEFException * AEFException error codes: * <br>AEFConst.CONFIG_ERROR, AEFConst.FACTORY_ERROR */ public ACEVoidTransactionActionImpl(ActionRequest request) throws AEFException { super(request); if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter/-Exit constructor of ACEVoidTransactionActionImpl."); log.trace(tempAEFMessage); } } /** * Tries to void the current transaction and return the application to the MAIN state * and SELECT_PROCEDURE substate as defined in the configuration files. * * @param request The ActionRequest which contains the classname and arguments. * @return Object N/A (null). * @exception AEFException * AEFException Error Codes: * <br>AEFConst.PROCEDURE_NOT_ALLOWED, AEFConst.TRANSACTION_NOT_ACTIVE * <br>AEFConst.APPLICATION_NOT_IN_PROPER_STATE */ public Object performAction() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEVoidTransactionActionImpl.performAction()"); log.trace(tempAEFMessage); } // Call super to perform any common processing and clear any errors before we start. super.performAction(); // If app is in secured state, and options are set to automatically do a special // signon, then do a special signon first. checkForSpecialSignon(); boolean salesTranInProgress = false; boolean nonSalesTranInProgress = false; Transaction trans = null; ObjectDetector detector = null; try { // Check that we are in the middle of a transaction. salesTranInProgress = getBooleanProviderProperty(WorkstationStatusProperties.CATEGORY, WorkstationStatusProperties.SALES_TRANSACTION_IN_PROGRESS); nonSalesTranInProgress = getBooleanProviderProperty(WorkstationStatusProperties.CATEGORY, WorkstationStatusProperties.NONSALES_TRANSACTION_IN_PROGRESS); trans = automationProvider.getTransaction(); if (!salesTranInProgress && !nonSalesTranInProgress && trans == null) { // Not in the middle of the transaction. String tempString = "ACEVoidTransactionActionImpl.performAction(): Cannot void a transaction because no transaction is in progress."; AEFException tempException = new AEFException(AEFConst.PROCEDURE_NOT_ALLOWED, AEFConst.TRANSACTION_NOT_ACTIVE, tempString); tempAEFMessage.setMessage(tempString); log.error(tempAEFMessage, tempException); throw tempException; } // Check for a "partial" transaction which was started, but no items have been sold. if (trans != null) { if (trans.getTransactionInfo().getTransactionID() == null) { // Clear the partial transaction object. if (log.isDebugEnabled()) { log.debug("ACEVoidTransactionActionImpl clear partial transaction."); } thePartialTransactionFlag = true; trans.setIsActive(false); detector = ((DetectorAccess)(SessionContext.getSession())).getTransactionDetector(); detector.reset(); automationProvider.setTransaction(null); } } // Get all the states and substates from the config files. initializeStates(); initializeSubStates(); // theValidSubstates contains a list of all the substates for which // a transaction can be voided. This is a class static, so it is only // initialized once. if (theValidSubstates == null) { theValidSubstates = new Vector(); theValidSubstates.addElement(Substate.getSubstate("EXPECTING_ITEM")); theValidSubstates.addElement(Substate.getSubstate("EXPECTING_TENDER")); theValidSubstates.addElement(Substate.getSubstate("EXPECTING_COUPON")); theValidSubstates.addElement(Substate.getSubstate("ENTER_ITEM")); } String currentSubstate = getCurrentSubstate(); // If we are not in a substate where we can void the transaction, we will // attempt a CLEAR first for (int i = 0; i < 4 && !theValidSubstates.contains(currentSubstate); i++) { sendClearSequence(true, false); currentSubstate = getCurrentSubstate(); } // VOID TOTAL can be sent if - // a transaction has items and is in substate 1001 (EXPECTING_ITEM=1001) // a transaction has items and is in substate 1005 (EXPECTING_COUPON=1005) // a transaction has items, has been totalled and is in substate 1002 (EXPECTING_TENDER=1002) if (theValidSubstates.contains(currentSubstate)) { try { sendVoidSequence(); } catch (AEFException e) { // Check to see if we timed out. If so log the error but continue, // we may be in a state which we can fix below. if (e.getErrorCode() != AEFConst.OPERATION_TIMEOUT) { throw(e); } else { if (log.isDebugEnabled()) { log.debug("ACEVoidTransactionActionImp.performAction timeout after sendVoidSequence()."); } } } } // Get the current sub-state and see if we are in mainstate and mainsubstate // or in ID state. if (((!(getCurrentState().equalsIgnoreCase(theMainState))) || (!(getCurrentSubstate().equalsIgnoreCase(theMainSubState)))) && (!(getCurrentState().equalsIgnoreCase(theIdState)))) { String tempString = "ACEVoidTransactionActionImpl.performAction(): The application is in state " + getCurrentState() + " substate " + getCurrentSubstate() + " but should be in state " + theMainState + " substate " + theMainSubState + " or in state " + theIdState + "."; AEFException tempException = new AEFException(AEFConst.APPLICATION_NOT_IN_PROPER_STATE, 0, tempString); tempAEFMessage.setMessage(tempString); log.error(tempAEFMessage, tempException); throw tempException; } } catch (RemoteException re) { // Not expected to get here since we are calling locally. } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEVoidTransactionActionImpl.performAction()"); log.trace(tempAEFMessage); } return null; } /** * Sends the key sequence required to void a transaction when not in ITEMENTRY state. * * @param wait True to wait for a state transition to state ITEMENTRY. * @return int Integer value representing the result of the key sequence. * @exception AEFException * AEFException error codes: * <br>AEFConst.CONFIG_ERROR, AEFConst.FACTORY_ERROR */ public int sendVoidSequence(boolean wait) throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEVoidTransactionActionImpl.sendVoidSequence()"); log.trace(tempAEFMessage); } int retVal = -1; AEFErrorHandler errorHandler = null; args.clear(); args.put("SEQUENCE_ID", "voidTransaction"); theKeySequenceAction = (AEFAction) (actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args))); if (wait) { // Good state is state 10 and ss 11038 Condition andConds1[] = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("MAIN")), new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("SELECT_PROCEDURE")) }; Condition conditions[] = { new AndCondition(andConds1) }; Condition conditionsP[] = null; Condition goodConditions[] = null; if (thePartialTransactionFlag) { conditionsP = new Condition[1]; Condition newCond = new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("INVALID_KEY_SEQUENCE")); conditionsP[0] = newCond; } if(conditionsP != null) { goodConditions = new Condition[conditions.length + conditionsP.length]; int i = 0; for (; i < conditions.length; i++) { goodConditions[i] = conditions[i]; } goodConditions[i] = conditionsP[0]; } else { goodConditions = new Condition[conditions.length]; int i=0; for(; i< conditions.length; i++) { goodConditions[i] = conditions[i]; } } theLock = new ConditionLock(); if (perfTrace.isEnabled(AEFPerfTrace. COARSE)) { perfTrace.reportTimer(AEFPerfTrace. COARSE, sessionID, "voidTransaction", ">>>Sending void transaction key sequence to application."); } retVal = theLock.performActionAndWait("wait-for-state-main", theKeySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout()); if (log.isDebugEnabled()) { log.debug( new AEFMessage( sessionID, "ACEVoidTransactionActionImp.sendVoidSequence: " + "Return Value = " + retVal + " State = " + getCurrentState() + " Substate = " + getCurrentSubstate() + ".")); } if (retVal < 0) { errorHandler = new AEFErrorHandler("Send Void Sequence Error"); retVal = errorHandler.handleError(theLock, theKeySequenceAction, conditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout(), retVal); if (retVal < 0) { throw errorHandler.getAllExceptions(); } } else { String currentSubstate = getCurrentSubstate(); if (currentSubstate == Substate.getSubstate("INVALID_KEY_SEQUENCE") ) { // send a clear sendClearSequence(true, false); } } } else { if (perfTrace.isEnabled(AEFPerfTrace. COARSE)) { perfTrace.reportTimer(AEFPerfTrace. COARSE, sessionID, "voidTransaction", ">>>Sending void transaction key sequence to application."); } theKeySequenceAction.performAction(); } if (perfTrace.isEnabled(AEFPerfTrace. COARSE)) { perfTrace.reportTimer(AEFPerfTrace. COARSE, sessionID, "voidTransaction", "<<<Void transaction key sequence processed by application."); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEVoidTransactionActionImpl.sendVoidSequence()"); log.trace(tempAEFMessage); } return retVal; } /** * Sends the key sequence required to void the transaction when in EXPECTING_ITEM, * EXPECTING_COUPON or EXPECTING_TENDER state. * * * @return int An integer index representing the result of the key sequence. * @exception AEFException * AEFException error codes: * <br>AEFConst.CONFIG_ERROR, AEFConst.FACTORY_ERROR */ public int sendVoidSequence() throws AEFException { return sendVoidSequence(true); } /** * Initialize the sub-state variables for ACE. * */ private void initializeSubStates() { theMainSubState = Substate.getSubstate("SELECT_PROCEDURE"); } /** * Initialize the state variables for ACE. * */ private void initializeStates() { // Get the values for all the ACE application states. theIdState = State.getState("ID"); theOverrideState = State.getState("OVERRIDE"); theMainState = State.getState("ITEMENTRY"); theTenderCashingExchangeState = State.getState("TENDER_CASHING_EXCHANGE"); theCashierLoanPickupTenderCountState = State.getState("CASHIER_LOAN_PICKUP_TENDER_COUNT"); theTenderListState = State.getState("TENDER_LIST"); theTerminalTransferMonitorState = State.getState("TERMINAL_TRANSFER_MONITOR"); thePriceVerifyState = State.getState("PRICE_VERIFY_CHANGE"); } /** * Calls the Error Handler to try to clear an error. * * @return int Integer value representing the result of the key sequence. * @exception AEFException */ public int handleError() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter ACEVoidTransactionActionImpl.handleError()"); log.trace(tempAEFMessage); } int retVal = -1; AEFErrorHandler errorHandler = null; args.clear(); args.put("SEQUENCE_ID", "clear-error"); theKeySequenceAction = (AEFAction)(actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args))); AbstractPropertyCondition[] conditions = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, theMainState), new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, theIdState), new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, theOverrideState) }; theLock = new ConditionLock(); errorHandler = new AEFErrorHandler("There was an error in SAForcedLogoffActionImpl.sendClearSequence()"); retVal = errorHandler.handleError(theLock, theKeySequenceAction, conditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout(), retVal); if (retVal < 0) { throw errorHandler.getAllExceptions(); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit ACEVoidTransactionActionImpl.handleError()"); log.trace(tempAEFMessage); } return retVal; } // Instance Variables protected AEFAction theKeySequenceAction = null; protected ConditionLock theLock = null; protected boolean thePartialTransactionFlag = false; protected String theMainSubState = null; protected String theIdState = null; protected String theOverrideState = null; protected String theAcctOvrState = null; protected String theMainState = null; protected String theTenderCashingExchangeState = null; protected String theCashierLoanPickupTenderCountState = null; protected String theTenderListState = null; protected String theTerminalTransferMonitorState = null; protected String thePriceVerifyState = null; protected static Vector theValidSubstates; private static Log log = LogFactory.getLog(ACEVoidTransactionActionImpl.class); }