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:

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.