/* * SACustomerEntryActionImpl * * 10/18/2002 * * 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; /** * SACustomerEntryActionImpl is a class which the POSAutomationProvider uses to * add a customer entry to a transaction on the POS application. * */ public class SACustomerEntryActionImpl extends SAActionImpl { 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 */ public SACustomerEntryActionImpl(ActionRequest request) throws AEFException { super(request); if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter SACustomerEntryActionImpl.SACustomerEntryActionImpl()."); log.trace(tempAEFMessage); } // theValidSubstates contains a list of all the substates for which // a customer may be entered. This is a class static, so it is only // initialized once. if (theValidSubstates == null) { theValidSubstates = new Vector(); theValidSubstates.addElement(Substate.getSubstate("SELECT_PROCEDURE")); theValidSubstates.addElement(Substate.getSubstate("EXPECTING_ITEM")); theValidSubstates.addElement(Substate.getSubstate("TRANS_TOTALLED")); theValidSubstates.addElement(Substate.getSubstate("CHANGE_OR_BAL_DUE")); theValidSubstates.addElement(Substate.getSubstate("TRAINING_MODE")); } LoyaltyIdentifier loyaltyId = (LoyaltyIdentifier)(request.getArguments()); theCustomerId = loyaltyId.getID(); theIDType = loyaltyId.getType(); if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit SACustomerEntryActionImpl.SACustomerEntryActionImpl()."); log.trace(tempAEFMessage); } } /** * Perform the action represented by the ActionRequest and return an ActionResult. * * @return Object The Customer instance. * @exception AEFException * Among the possible error codes are: * <br>AEFConst.APPLICATION_NOT_IN_PROPER_STATE, AEFConst.NONE * <br>AEFConst.UNSUPPORTED_OPERATION, AEFCONST.NONE */ public Object performAction() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter SACustomerEntryActionImpl.performAction()."); log.trace(tempAEFMessage); } // SA base EM does not support alternate ID, so we need to check for that. if (theIDType.equalsIgnoreCase(LoyaltyIdentifier.ALTERNATE_TYPE)) { String tempString = "SACustomerEntryActionImpl.performAction(): Base EM does not support alternate loyalty ids."; AEFException tempException = new AEFException(AEFConst.UNSUPPORTED_OPERATION, AEFConst.NONE, tempString); tempAEFMessage.setMessage(tempString); log.error(tempAEFMessage, tempException); throw tempException; } super.performAction(); // Call super to perform any common processing and clear any errors before we start. Object retVal = null; // If application is in secured state, and options are set to automatically do a // special signon, then create the logon action to do the special signon first. checkForSpecialSignon(); int seqResult = -1; // Check precondition that the application is in one of the substates which // is valid for customer entry. If not, then throw an exception. String currentSubstate = getCurrentSubstate(); AEFSession session = SessionContext.getSession(); theDetector = ((DetectorAccess) (session)).getCustomerEntryDetector(); if (theValidSubstates.contains(currentSubstate)) { try { SalesTransaction trans = (SalesTransaction)(session.getPOSAutomationProvider().getTransaction()); if (log.isDebugEnabled()) { tempAEFMessage.setMessage("Current state = EXPECTING_ITEM" + currentSubstate.equals(Substate.getSubstate("EXPECTING_ITEM"))); log.debug(tempAEFMessage); tempAEFMessage.setMessage("Customer = " + trans.getCustomer()); log.debug(tempAEFMessage); tempAEFMessage.setMessage("Trans has items = " + trans.hasItems()); log.debug(tempAEFMessage); } // If current substate is EXPECTING_ITEM, and there is already a customer and // there are unvoided items in the transaction, we have to send a TOTAL first. if (currentSubstate.equals(Substate.getSubstate("EXPECTING_ITEM")) && trans.getCustomer() != null && trans.hasItems()) { seqResult = sendTotalSequence(); } } catch (RemoteException re) { // Can't get here. tempAEFMessage.setMessage("There was a remote exception thrown in performAction of SACustomerEntryActionImpl."); log.error(tempAEFMessage, re); } // In a valid state for customer number entry seqResult = sendCustomerEntrySequence(); if (log.isDebugEnabled()) { tempAEFMessage.setMessage("SACustomerEntryActionImpl.performAction seqResult = " + seqResult); log.debug(tempAEFMessage); } if (seqResult >= 0) { // Successfully entered customer number. retVal = waitForCustomer(); } } else { // Not in valid state for customer number entry String tempString = "SACustomerEntryActionImpl.performAction(): POS application not in proper state to perform customer entry.\n Application substate is " + currentSubstate + "."; AEFException tempException = new AEFException(AEFConst.APPLICATION_NOT_IN_PROPER_STATE, 0, tempString); tempAEFMessage.setMessage(tempString); log.error(tempAEFMessage, tempException); throw tempException; } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit SACustomerEntryActionImpl.performAction()."); log.trace(tempAEFMessage); } return retVal; } /** * Sends the key sequence which will cause the customer number to be entered. * * @return int An integer value representing the result of the key sequence. * @exception AEFException * Among the possible error codes are: * <br>AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_LOYALTY_NUMBER */ public int sendCustomerEntrySequence() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter SACustomerEntryActionImpl.sendCustomerEntrySequence()."); log.trace(tempAEFMessage); } int retVal = -1; // if all zeroes then an invalid argument. boolean nonZeroString = false; for (int i= 0; i < theCustomerId.length(); i++) { if (theCustomerId.charAt(i) != '0') { nonZeroString = true; } } if (! nonZeroString) { String tempString = "SACustomerEntryActionImpl.sendCustomerEntrySequence(): Invalid argument " + theCustomerId + "."; AEFException tempException = new AEFException(AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_LOYALTY_NUMBER, tempString); tempAEFMessage.setMessage(tempString); log.error(tempAEFMessage, tempException); throw tempException; } args.clear(); args.put("%0", theCustomerId); if (theIDType != null && theIDType.equals(LoyaltyIdentifier.ALTERNATE_TYPE)) { args.put("SEQUENCE_ID", "alternateCustomer"); } else { args.put("SEQUENCE_ID", "customer"); } theKeySequenceAction = (AEFAction) (actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args))); Condition[] goodConditions = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("EXPECTING_ITEM")), new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("SELECT_PROCEDURE")), new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("CHANGE_OR_BAL_DUE")) }; theLock = new ConditionLock(); // Save any current customer instance number so we are sure to only get an operator // created after this key sequence is sent. theInstanceNumber = theDetector.getInstanceNumber(); if (perfTrace.isEnabled(AEFPerfTrace. COARSE)) { perfTrace.reportTimer(AEFPerfTrace. COARSE, sessionID, "addCustomer", ">>>Sending customer id key sequence to application."); } retVal = theLock.performActionAndWait("wait-for-expecting-item-substate", theKeySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout()); if (retVal < 0) { AEFErrorHandler errorHandler = new AEFErrorHandler("Send Customer Entry Sequence Error"); retVal = errorHandler.handleError(theLock, theKeySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout(), retVal); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit SACustomerEntryActionImpl.sendCustomerEntrySequence()."); log.trace(tempAEFMessage); } return retVal; } /** * Sends the total key sequence. * * @return int An integer value representing the result of the key sequence. * @exception AEFException */ public int sendTotalSequence() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter SACustomerEntryActionImpl.sendTotalSequence()."); log.trace(tempAEFMessage); } int retVal = -1; args.clear(); args.put("SEQUENCE_ID", "total"); theKeySequenceAction = (AEFAction) (actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args))); Condition[] goodConditions = { new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_SUB_STATE, Substate.getSubstate("TRANS_TOTALLED")), }; theLock = new ConditionLock(); if (perfTrace.isEnabled(AEFPerfTrace. COARSE)) { perfTrace.reportTimer(AEFPerfTrace. COARSE, sessionID, "addCustomer", ">>>Sending customer id key sequence to application."); } retVal = theLock.performActionAndWait("wait-for-trans-totalled-substate", theKeySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout()); if (retVal < 0) { AEFErrorHandler errorHandler = new AEFErrorHandler("Send Customer Entry TOTAL Sequence Error"); retVal = errorHandler.handleError(theLock, theKeySequenceAction, goodConditions, BadConditionsImpl.getInstance().getBadConditions(), getTimeout(), retVal); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit SACustomerEntryActionImpl.sendTotalSequence()."); log.trace(tempAEFMessage); } return retVal; } /** * Waits for customer to be entered * * @return Customer The customer created by the action. * @exception AEFException */ public Customer waitForCustomer() throws AEFException { if (log.isTraceEnabled()) { tempAEFMessage.setMessage("+Enter SACustomerEntryActionImpl.waitForCustomer()."); log.trace(tempAEFMessage); } Customer retVal = null; // Successfully entered customer. Wait for the operator object to be created. ObjectDetectorLock objLock = new ObjectDetectorLock(); retVal = (Customer) (objLock.waitForNewObject("wait-for-customer-entry", theDetector, theInstanceNumber, getTimeout())); if (perfTrace.isEnabled(AEFPerfTrace. COARSE)) { perfTrace.reportTimer(AEFPerfTrace. COARSE, sessionID, "addCustomer", "<<<Customer id key sequence processed by application."); } if (log.isTraceEnabled()) { tempAEFMessage.setMessage("-Exit SACustomerEntryActionImpl.waitForCustomer()."); log.trace(tempAEFMessage); } return retVal; } /* Instance Variables */ protected AEFAction theKeySequenceAction; protected String theCustomerId; protected String theIDType; protected ConditionLock theLock = null; protected ObjectDetector theDetector = null; protected int theInstanceNumber; protected static Vector theValidSubstates; private static Log log = LogFactory.getLog(SACustomerEntryActionImpl.class); }