/*
* GSAEFTCreditTenderActionImpl
*
* 08/05/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 com.ibm.retail.AEF.event.*;
import java.util.*;
import java.rmi.*;
import java.text.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* GSAEFTCreditTenderActionImpl is a class which the POSAutomationProvider uses to accomplish
* adding an EFT and credit tender into a transaction on the POS application.
*
*/
public class GSAEFTCreditTenderActionImpl extends GSAActionImpl
{
static String copyright()
{ return com.ibm.retail.si.Copyright.IBM_COPYRIGHT_SHORT;}
/**
* Constructor
*
* @param request The ActionRequest which contains a HashMap of arguments.
* @exception com.ibm.retail.AEF.util.AEFException
* AEFException return codes are:
*
AEFConst.INVALID_ARGUMENT, AEFConst.ACCOUNT_NUMBER_REQUIRED
*
AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_EXPIRY_DATE
*
AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_TENDER_TYPE
*
AEFConst.PROCEDURE_NOT_ALLOWED, AEFConst.NOT_IMPLEMENTED
*/
public GSAEFTCreditTenderActionImpl(ActionRequest request) throws AEFException
{
super(request);
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter GSAEFTCreditTenderActionImpl.GSAEFTCreditTenderActionImpl().");
log.trace(tempAEFMessage);
}
TenderIdentifier tenderID = (TenderIdentifier)(request.getArguments());
if (!(tenderID instanceof CreditIdentifier))
{
AEFException tempException = new AEFException(AEFConst.PROCEDURE_NOT_ALLOWED, AEFConst.NOT_IMPLEMENTED, "GSAEFTCreditTenderActionImpl(): ERROR: Tendering credit with MSR track data is not implemented.");
tempAEFMessage.setMessage("AN AEF Exception was thrown in GSAEFTCreditTenderActionImpl.GSAEFTCreditTenderActionImpl().");
log.error(tempAEFMessage, tempException);
throw tempException;
}
creditID = (CreditIdentifier) tenderID;
setAmount();
setAccountNumber();
setExpirationDate();
setCardType();
setTenderFuntionCode();
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit GSAEFTCreditTenderActionImpl.GSAEFTCreditTenderActionImpl().");
log.trace(tempAEFMessage);
}
}
/**
* Perform the action represented by the ActionRequest and return an ActionResult.
*
*
* @return Object The Tender instance.
* @exception com.ibm.retail.AEF.util.AEFException
* Among the possible AEFException error codes are:
*
AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_TENDER_TYPE
*
AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.ACCOUNT_TENDER_LIMIT
*
AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.CHANGE_AMOUNT_LIMIT
*
AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.NUMBER_OF_TENDERS_LIMIT
*
AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.STAND_IN_COUNT_LIMIT
*
AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.STAND_IN_AMOUNT_LIMIT
*
AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.TENDER_FLOOR_LIMIT
*
AEFConst.APPLICATION_LIMIT_EXCEEDED, AEFConst.CARD_EXPIRED
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.TENDER_NOT_AUTHORIZED
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.RISK_1
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.RISK_2
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.RISK_3
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.RISK_4
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.VERIFICATION_TIMEOUT
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.CREDIT_NOT_AVAILABLE
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.TOO_LONG_IN_STANDIN
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.PAYMENT_SYSTEM_OFFLINE
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.UNKNOWN_SERVICER
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.SERVICER_CLOSED
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.CARD_TYPE_UNKNOWN
*
AEFConst.INVALID_MANAGER_OVERRIDE_NUMBER
*
AEFConst.KEYLOCK_ERROR, AEFConst.MANAGER_KEY_REQUIRED
*
AEFConst.INVALID_ARGUMENT
*
AEFConst.PROCEDURE_NOT_ALLOWED, AEFConst.EXTERNAL_TENDER_AUTHORIZATION_SUSPENDED
*
AEFConst.TENDER_NOT_ACCEPTED, AEFConst.UNKNOWN_SERVICER
*
Common Errors
*/
public Object performAction() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter GSAEFTCreditTenderActionImpl.performAction().");
log.trace(tempAEFMessage);
}
super.performAction(); // Call super to perform any common processing and clear any errors before we start.
Object retVal = null;
Condition[] goodConditions =
{
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("ID")),
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("ENTER_TENDER_AMOUNT")),
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("TRANSACTION_SELECT"))
};
try
{
// Create the tender detector.
detector = ((DetectorAccess)(SessionContext.getSession())).getTenderDetector();
//Check to see if we need to send the Total Key Sequence
String currentState = getCurrentState();
if (currentState.equals(State.getState("ITEMENTRY")))
{
sendTotalSequence();
}
// Verify that we are in the tendering state.
currentState = getCurrentState();
if (currentState.equals(State.getState("ENTER_TENDER_AMOUNT")))
{
sendTenderSequence();
Object tmpRetVal = new Integer("1");
int dummyVal = 0;
while (tmpRetVal instanceof Integer)
{
tmpRetVal = waitForTender();
if (tmpRetVal instanceof Integer)
{
AEFErrorHandler errorHandler = new AEFErrorHandler("Wait for Tender or Error", creditID);
errorHandler.handleError(lock, keySequenceAction, GSANormalConditionsImpl.getInstance().getShortConditions(goodConditions),
BadConditionsImpl.getInstance().getBadConditions(), getTimeout(), dummyVal);
}
else
{
retVal = tmpRetVal;
}
}
}
else if (currentState.equals(State.getState("TRANSACTION_SELECT")) || currentState.equals(State.getState("ITEMENTRY")))
{
// We had a 0 balance and have gone back to TRANSACTION_SELECT or ITEMENTRY state.
throw new AEFException(AEFConst.APPLICATION_NOT_IN_PROPER_STATE, 0, "GSAEFTCreditTenderActionImpl.performAction(): Transaction balance is zero so the application went back to state " + currentState + ".");
}
else
{
// Not in valid state for tender entry.
throw new AEFException(AEFConst.APPLICATION_NOT_IN_PROPER_STATE, 0, "GSAEFTCreditTenderActionImpl.performAction(): POS application not in proper state to tender credit.\n Application state is " + currentState + ".");
}
}
catch (AEFException e)
{
tempAEFMessage.setMessage("There was an AEF exception thrown in performAction of GSAEFTCreditTenderActionImpl-.");
log.error(tempAEFMessage, e);
throw e;
}
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit GSAEFTCreditTenderActionImpl.performAction().");
log.trace(tempAEFMessage);
}
return retVal;
}
/**
* Sends the "total" key sequence.
*
* @exception com.ibm.retail.AEF.util.AEFException
* Among the possible AEFException error codes are:
*
AEFConst.OPERATION_TIMEOUT
*
AEFConst.WAIT_INTERRUPTED
*
AEFConst.CONFIG_ERROR, AEFConst.INVALID_KEY_SEQUENCE
*
Common Errors
*/
public void sendTotalSequence() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter GSAEFTCreditTenderActionImpl.sendTotalSequence().");
log.trace(tempAEFMessage);
}
int retVal = -1;
int currentAmount = Integer.valueOf(amount).intValue();
args.clear();
args.put("SEQUENCE_ID", "total");
keySequenceAction = (AEFAction)(actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args)));
if (currentAmount != 0)
{
Condition[] goodConditions =
{
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("ENTER_TENDER_AMOUNT"))
};
lock = new ConditionLock();
retVal = lock.performActionAndWait("wait-for-trans-total-substate",
keySequenceAction,
goodConditions,
BadConditionsImpl.getInstance().getBadConditions(),
getTimeout());
if (retVal < 0)
{
AEFErrorHandler errorHandler = new AEFErrorHandler("Send Total Sequence Error", creditID);
retVal = errorHandler.handleError(lock,
keySequenceAction,
goodConditions,
BadConditionsImpl.getInstance().getBadConditions(),
getTimeout(),
retVal);
}
}
else
{
AEFException tempException = new AEFException(AEFConst.TENDER_NOT_ACCEPTED, AEFConst.INVALID_TENDER_AMOUNT, "GSAEFTCreditTenderActionImpl.performAction(): The transaction balance is zero so the tender will not be accepted.");
tempAEFMessage.setMessage("AN AEF Exception was thrown in GSAEFTCreditTenderActionImpl.sendTotalSequence().");
log.error(tempAEFMessage, tempException);
throw tempException;
}
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit GSAEFTCreditTenderActionImpl.sendTotalSequence().");
log.trace(tempAEFMessage);
}
}
/**
* Waits for a new tender line item to be detected.
*
*
* @return Object The newly detected tender. (Note in this case, it's an ArrayList that
* contains the tender object).
* @exception com.ibm.retail.AEF.util.AEFException
* Among the possible AEFException error codes are:
*
AEFConst.OPERATION_TIMEOUT
*
AEFConst.WAIT_INTERRUPTED
*
Common Errors
*/
public Object waitForTender() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter GSAEFTCreditTenderActionImpl.waitForTender().");
log.trace(tempAEFMessage);
}
Object retVal = null;
ObjectDetectorLock objLock = new ObjectDetectorLock();
retVal = objLock.waitForNewObjectOrError("wait-for-tender", detector, instanceNumber, BadConditionsImpl.getInstance().getBadConditions(), true, getTimeout());
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit GSAEFTCreditTenderActionImpl.waitForTender().");
log.trace(tempAEFMessage);
}
return retVal;
}
/**
* Sets the amount of the credit.
*
* @exception AEFException
*/
public void setAmount() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter GSAEFTCreditTenderActionImpl.setAmount().");
log.trace(tempAEFMessage);
}
amount = creditID.getAmount();
amount = amount.trim();
// Strip out any non-numeric portion of the amount (currency symbol & decimal separator)
amount = AEFUtilities.formatNumericOnly(amount);
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit GSAEFTCreditTenderActionImpl.setAmount().");
log.trace(tempAEFMessage);
}
}
/**
* Sets the account number of the credit card.
*
* @exception AEFException
* Among the possible AEFException error codes are:
*
AEFConst.INVALID_ARGUMENT, AEFConst.ACCOUNT_NUMBER_REQUIRED
*/
public void setAccountNumber() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter GSAEFTCreditTenderActionImpl.setAccountNumber().");
log.trace(tempAEFMessage);
}
accountNumber = creditID.getAccountNumber();
if (accountNumber == null)
{
AEFException tempException = new AEFException(AEFConst.INVALID_ARGUMENT, AEFConst.ACCOUNT_NUMBER_REQUIRED, "GSAEFTCreditTenderActionImpl.setAccountNumber(): Account number argument is required.");
tempAEFMessage.setMessage("AN AEF Exception was thrown in GSAEFTCreditTenderActionImpl.setAccountNumber().");
log.error(tempAEFMessage, tempException);
throw tempException;
}
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit GSAEFTCreditTenderActionImpl.setAccountNumber().");
log.trace(tempAEFMessage);
}
}
/**
* Sets the expiration date of the credit card.
*
* @exception AEFException
* Among the possible AEFException error codes are:
*
AEFConst.INVALID_ARGUMENT, AEFConst.EXPIRATION_DATE_REQUIRED
*
AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_EXPIRY_DATE
*/
public void setExpirationDate() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter GSAEFTCreditTenderActionImpl.setExpirationDate().");
log.trace(tempAEFMessage);
}
expDate = creditID.getExpirationDate();
if (expDate == null)
{
AEFException tempException = new AEFException(AEFConst.INVALID_ARGUMENT, AEFConst.EXPIRATION_DATE_REQUIRED, "GSAEFTCreditTenderActionImpl.setExpirationDate(): Expiration date argument is required.");
tempAEFMessage.setMessage("AN AEF Exception was thrown in GSAEFTCreditTenderActionImpl.setExpirationDate().");
log.error(tempAEFMessage, tempException);
throw tempException;
}
try
{
FormatContext.getExpiryDateInstance().parse(expDate);
}
catch (ParseException pe)
{
AEFException tempException = new AEFException(AEFConst.INVALID_ARGUMENT, AEFConst.INVALID_EXPIRY_DATE, "GSAEFTCreditTenderActionImpl.setExpirationDate(): Invalid expiry date: " + expDate);
tempAEFMessage.setMessage("AN AEF Exception was thrown in GSAEFTCreditTenderActionImpl.setExpirationDate().");
log.error(tempAEFMessage, tempException);
throw tempException;
}
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit GSAEFTCreditTenderActionImpl.setExpirationDate().");
log.trace(tempAEFMessage);
}
}
/**
* Sets the card type of the credit card.
*
* @exception AEFException
* Among the possible AEFException error codes are:
*
AEFConst.INVALID_ARGUMENT, AEFConst.CREDIT_CARD_TYPE_REQUIRED
*/
public void setCardType() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter GSAEFTCreditTenderActionImpl.setCardType().");
log.trace(tempAEFMessage);
}
cardType = creditID.getCardType();
if (cardType == null)
{
AEFException tempException = new AEFException(AEFConst.INVALID_ARGUMENT, AEFConst.CREDIT_CARD_TYPE_REQUIRED, "GSAEFTCreditTenderActionImpl.setCardType(): Card type argument is required.");
tempAEFMessage.setMessage("AN AEF Exception was thrown in GSAEFTCreditTenderActionImpl.setCardType().");
log.error(tempAEFMessage, tempException);
throw tempException;
}
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit GSAEFTCreditTenderActionImpl.setCardType().");
log.trace(tempAEFMessage);
}
}
/**
* Sets the tender fuction code for this credit card.
*
* @exception AEFException
* Among the possible AEFException error codes are:
*
AEFConst.CONFIG_ERROR
*/
public void setTenderFuntionCode() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter GSAEFTCreditTenderActionImpl.setTenderFuntionCode().");
log.trace(tempAEFMessage);
}
TenderMapper tempMapper = TenderMapperImpl.getInstance();
String tenderKey = tempMapper.getKey(cardType);
tenderKey = tenderKey.toUpperCase();
tenderFuntionCode = FunctionCode.getFunctionCode(tenderKey);
if (tenderFuntionCode == null)
{
AEFException tempException = new AEFException(AEFConst.CONFIG_ERROR, 0, "No function code defined in " + AEFConst.FCODE_BUNDLE + " properties chain for " + tenderFuntionCode + ".");
tempAEFMessage.setMessage("AN AEF Exception was thrown in GSAEFTCreditTenderActionImpl.setTenderFuntionCode().");
log.error(tempAEFMessage, tempException);
throw tempException;
}
else
{
tenderFuntionCode = "<" + tenderFuntionCode + ">";
}
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit GSAEFTCreditTenderActionImpl.setTenderFuntionCode().");
log.trace(tempAEFMessage);
}
}
/**
* Sends the key sequence for the credit tender amount.
*
* @exception com.ibm.retail.AEF.util.AEFException
* Among the possible AEFException error codes are:
*
AEFConst.OPERATION_TIMEOUT
*
AEFConst.WAIT_INTERRUPTED
*
Common Errors
*/
public void sendTenderSequence() throws AEFException
{
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("+Enter GSAEFTCreditTenderActionImpl.sendTenderSequence().");
log.trace(tempAEFMessage);
}
int retVal = -1;
lock = new ConditionLock();
args.clear();
args.put("%0", amount);
args.put("%1", tenderFuntionCode);
args.put("SEQUENCE_ID", "tender");
keySequenceAction = (AEFAction)(actionFactory.makeAction(new ActionRequest("SimpleKeySequenceAction", args)));
Condition[] goodConditions =
{
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("ID")),
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("ENTER_TENDER_AMOUNT")),
new PropertyEqualsCondition(POSDeviceProperties.CATEGORY, POSDeviceProperties.POS_STATE, State.getState("TRANSACTION_SELECT"))
};
// Save any current item instance number so we are sure to only get an item created after this key sequence is sent.
instanceNumber = detector.getInstanceNumber();
// Report performance data.
if (perfTrace.isEnabled(AEFPerfTrace.COARSE))
{
perfTrace.reportTimer(AEFPerfTrace.COARSE, sessionID, "addTender", ">>>Sending credit tender sequence to application.");
}
// Send the key sequence to GSA.
retVal = lock.performActionAndWait("wait-after-send-tender",
keySequenceAction,
GSANormalConditionsImpl.getInstance().getShortConditions(goodConditions),
BadConditionsImpl.getInstance().getBadConditions(),
getTimeout());
if (retVal < 0)
{
AEFErrorHandler errorHandler = new AEFErrorHandler("Send Credit Tender Sequence Error", creditID);
retVal = errorHandler.handleError(lock,
keySequenceAction,
GSANormalConditionsImpl.getInstance().getShortConditions(goodConditions),
BadConditionsImpl.getInstance().getBadConditions(),
getTimeout(),
retVal);
}
if (log.isTraceEnabled())
{
tempAEFMessage.setMessage("-Exit GSAEFTCreditTenderActionImpl.sendTenderSequence().");
log.trace(tempAEFMessage);
}
}
/* Instance and Class Variables */
protected AEFAction keySequenceAction = null;
protected CreditIdentifier creditID = null;
protected ConditionLock lock = null;
protected ObjectDetector detector = null;
protected int instanceNumber = 0;
protected String amount = null;
protected String accountNumber = null;
protected String expDate = null;
protected String cardType = null;
protected String tenderFuntionCode = null;
private static Log log = LogFactory.getLog(GSAEFTCreditTenderActionImpl.class);
private static AEFPerfTrace perfTrace = AEFPerfTrace.getInstance();
}