Note: You can also follow this process to extend shipping group validation.
If you have implemented a custom payment method, such as the StorePoints
payment method described in detail in the previous section, you may want to perform validation on the custom payment method during checkout. For example, for the StorePoints
payment method you might want to make sure that the number of points specified is greater than zero. You might also want to include other validation logic – for example, you might decide that users cannot apply more than 500 store points to any order, and that store points may not be used to pay for more than 25% of the order price. You can test all of these conditions in a custom validation component for the StorePoints
payment group.
When a user checks out an Order
, the Oracle ATG Web Commerce purchase process performs validation checks on all of the payment groups in the Order
by executing the validateForCheckout
pipeline, which is defined in commercepipeline.xml
. The validateForCheckout
pipeline includes a ValidatePaymentGroupsForCheckout
processor, which iterates over the payment groups in the Order
and calls the validatePaymentGroup
pipeline for each one to verify that the payment group is ready for checkout.
The validatePaymentGroup
pipeline begins with a processor that examines the type of the current PaymentGroup
and transfers control to a pipeline processor appropriate to that type. Credit cards are checked by one processor, gift certificates by another, store credits by still another. You can add your own pipeline processor to check the custom payment groups that you create.
Adding validation for your new payment method involves four steps:
This subsections that follow describe each step in detail, using the StorePoints
payment group that you created in the previous section as an example.
Step 1: Implement a validation pipeline processor
The first step in validating your custom payment method is to write a pipeline processor that examines a payment group and determines whether it meets the criteria for use in the Order
. Recall that your processor must implement the interface atg.service.pipeline.PipelineProcessor
, which consists of two methods:
public int[] getRetCodes();
public int runProcess(Object pParam, PipelineResult pResult) throws Exception;
A validation processor for StorePoints
might look similar to the following:
package store.checkout; import atg.service.pipeline.*; import atg.nucleus.GenericService; import atg.commerce.order.processor.ValidatePaymentGroupArgs; import store.payment.StorePoints; public class ValidateStorePoints extends GenericService implements PipelineProcessor { private static int SUCCESS_CODE = 1; private static int[] RETURN_CODES = { SUCCESS_CODE }; /** * Return the list of possible return values from this * processor. This processor always returns a single value * indicating success. In case of errors, it adds messages * to the pipeline result object. **/ public int[] getRetCodes() { return RETURN_CODES; } /** * Perform validation for a StorePoints payment group. **/ public int runProcess(Object pParam, PipelineResult pResult) { ValidatePaymentGroupPipelineArgs args; // Dynamo guarantees that the pipeline parameter object // passed to a payment group validation processor will be // of type ValidatePaymentGroupPipelineArgs. args = (ValidatePaymentGroupPipelineArgs)pParam; PaymentGroup pg = args.getPaymentGroup(); // Now try casting the payment group to the type we expect // and validating the fields. If the payment group is of // the wrong type, or if anything else goes wrong, add an // error to the pipeline result so the order manager will // abort the checkout process. try { StorePoints points = (StorePoints)pg; int nPoints = points.getNumberOfPoints(); Order order = args.getOrder(); double orderPrice = order.getPriceInfo().getTotal(); // Log some debugging info about the number of points // and the total order price. if (isLoggingDebug()) logDebug("Applying " + nPoints + " store points " + " to an order totaling " + orderPrice); // Are we using more than 500 points or trying to pay // for more than 25% of the order? If so, add an error // to the pipeline result before returning. if (nPoints <= 0) pResult.addError( "NoPointsUsed", "The number of points should be greater than zero."); else if (nPoints > 500) pResult.addError( "TooManyPointsUsed", "A maximum of 500 points can be used per order."); else if (nPoints > orderPrice * .25) pResult.addError( "PointsValueExceeded", "Store points cannot pay for more than 25% of an order."); } catch (ClassCastException cce) { pResult.addError( "ClassNotRecognized", "Expected a StorePoints payment group, but got " + pg.getClass().getName() + " instead."); } return SUCCESS_CODE; } }
Note the use of the ValidatePaymentGroupPipelineArgs
class in the runProcess()
method. When the OrderManager
validates payment groups, it guarantees that the pipeline arguments passed to your processor are an instance of this class. This provides you with a convenient way to retrieve items like the Order
, the OrderManager
, the PaymentGroup
, and the server’s Locale
from the pipeline parameter map.
Step 2: Create an instance of the processor
After implementing your pipeline processor, you must configure an instance of the processor in Nucleus. For the StorePoints
example, the validation processor might be located at /store/checkout/ValidateStorePoints
, and it is configured with the following properties file:
# Store Points validation processor $class=store.checkout.ValidateStorePoints loggingDebug=true
In this simple example the processor doesn’t require any additional property settings.
Step 3: Add the custom payment method to the ValidatePaymentGroupByType processor
Recall that payment groups are validated at checkout by invoking the validatePaymentGroup
pipeline for each payment group in the order. The validatePaymentGroup
pipeline begins with a pipeline processor called ValidatePaymentGroupByType
, which examines the type of each payment group and returns an Integer that identifies the payment method. The pipeline then dispatches control to one of a number of different processors based on this return code.
To add support for your payment method, you must add an entry to ValidatePaymentGroupByType
’s returnValues
property, which maps your payment method’s name (storePoints
in this example) to a unique return value. You can use any return value as long as it isn’t used by any other payment method. This example uses a value of 10. Configure the property by creating a file as follows in localconfig/atg/commerce/order/processor/ValidatePaymentGroupByType.properties
:
# Add a return code for the storePoints payment method returnValues+=\ storePoints=10
Note that the payment method name, storePoints
, is the name you added to the paymentTypeClassMap
in the OrderTools
component; it is not the name of your payment group’s implementation class.
Step 4: Add the custom payment method to the validatePaymentGroup pipeline
The final step in adding validation for your StorePoints
payment method is to reconfigure the validatePaymentGroup
pipeline so it invokes the ValidateStorePoints
processor when ValidatePaymentGroupByType
returns a value of 10. This requires two changes to the pipeline configuration.
First, add a new transition tag to the dispatchOnPGType
pipeline link in order to specify the pipeline link to use when ValidatePaymentGroupByType
returns a value of 10. Second, define the new pipeline link and configure it to invoke your ValidateStorePoints
component (in bold in the example that follows). You can do both steps using XML combination facilities. Modify the pipeline using the following code in localconfig/atg/commerce/commercepipeline.xml
:
<!-- Modify the validatePaymentGroup chain to include --> <!-- validation for payment groups of type storePoints --> <pipelinemanager> <pipelinechain name="validatePaymentGroup"> <pipelinelink name="dispatchOnPGType"> <transition returnvalue="10" link="validateStorePoints"/> </pipelinelink> <pipelinelink name="validateStorePoints"> <processor jndi="/store/checkout/ValidateStorePoints"/> </pipelinelink> </pipelinechain> </pipelinemanager>
Oracle ATG Web Commerce will now perform validation on your StorePoints
payment method.