Oracle ATG Web Commerce provides several form handlers to support a checkout process that uses any number or type of shipping group and payment group. If your sites have this type of complex checkout process, then you should use the form handlers described in this section instead of ExpressCheckoutFormHandler. (For more information on ExpressCheckoutFormHandler, see Preparing a Simple Order for Checkout.)

The form handlers described in this section manage different subprocesses in the pre-checkout process, which makes it easier for you to extend them when necessary. Separate form handlers exist to support the following tasks:

Creating Shipping Groups

Oracle ATG Web Commerce provides two implementations of the CreateShippingGroupFormHandler interface to support the form-driven creation of hard good and electronic shipping groups. These form handler classes create the ShippingGroups and optionally add them to the ShippingGroupMapContainer. Once the shipping groups are added to the ShippingGroupMapContainer, the user can then select from among them for use in the current Order.

The two default implementations of CreateShippingGroupFormHandler are:

You can also create Profile-derived ShippingGroups and add them to the ShippingGroupMapContainer by using the ShippingGroupDroplet servlet bean (class atg.commerce.order.purchase.ShippingGroupDroplet). The input parameters passed into ShippingGroupDroplet determine what types of ShippingGroups are created (hard good, electronic, or both) and whether the ShippingGroupMapContainer is cleared before they are created. For a detailed list of these input parameters, as well as output parameters, open parameters, and a code example, see the Adding Shipping Information to Shopping Carts section of the Implementing Order Retrieval chapter of the ATG Commerce Guide to Setting Up a Store.

To initialize the ShippingGroup objects, the service method of ShippingGroupDroplet calls initializeUsersShippingMethods(), which initializes one or more ShippingGroups for the current user and adds them to the ShippingGroupMapContainer. For each entry in ShippingGroupDroplet.shippingGroupTypes (which is supplied via an input parameter), its corresponding ShippingGroupInitializer is obtained from the ServiceMap in ShippingGroupDroplet.shippingGroupInitializers (keyed by ShippingGroup type). The initializeShippingGroups() method of the ShippingGroupInitializer is then used to initialize the ShippingGroup and add it to the ShippingGroupMapContainer.

Note that Oracle ATG Web Commerce provides two implementations of the ShippingGroupInitializer interface, namely HardgoodShippingGroupInitializer and ElectronicShippingGroupInitializer. The former creates HardgoodShippingGroups based on their existence in the user’s Profile, and the latter creates ElectronicShippingGroups based on the existence of an e-mail address in the user’s Profile.

To use this framework with a new ShippingGroup type that you create, first, write a new ShippingGroupInitializer implementation. Its initializeShippingGroups() method should gather the user’s ShippingGroups by type and add them to the ShippingGroupMapContainer referenced by the ShippingGroupFormHandler. For example, the ElectronicShippingGroupInitializer queries the Profile’s email property and applies the result to a new ElectronicShippingGroup, which is subsequently added to the ShippingGroupMapContainer. Second, register a Nucleus component for the new ShippingGroupInitializer implementation and add it to the ServiceMap in ShippingGroupDroplet.shippingGroupInitializers, which is keyed by ShippingGroup type. Finally, include the new ShippingGroup type in the ShippingGroupDroplet.shippingGroupTypes parameter on those site pages where the new ShippingGroup type is utilized.

Associating Shipping Groups with an Order and Its Items

When the user has supplied the shipping information for an Order, the ShippingGroupFormHandler can be used to create and manage the associations between the ShippingGroups and the items in the Order. Oracle ATG Web Commerce provides a request-scoped instance of atg.commerce.order.purchase.ShippingGroupFormHandler, which is located in Nucleus at /atg/commerce/order/purchase/ShippingGroupFormHandler.

The ShippingGroupFormHandler works in conjunction with the ShippingGroupDroplet to manipulate the relationships between CommerceItems and ShippingGroups in the order. Handling Instructions and their relationships to CommerceItems and ShippingGroups are also manipulated based on the relationship between each CommerceItem and the ShippingGroups.

By default, this form handler invokes the validateShippingInfo pipeline chain to validate ShippingGroup information. To skip validation, set the validateShippingGroups property to false. To learn more about the pipeline chain, see the validateShippingInfo Pipeline Chain section.

It should be noted that ShippingGroupFormHandler does not reprice the given Order. Consequently, if you enable customers to make order changes that affect order price through this form handler, you should then reprice the given Order using the RepriceOrderDroplet servlet bean before displaying its price to the customer. For more information on RepriceOrderDroplet, see Repricing Orders section of the ATG Commerce Guide to Setting Up a Store.

The ShippingGroupFormHandler is composed of the following containers:

Additionally, the ShippingGroupFormHandler uses the following helper classes:

With these helper classes and containers, the ShippingGroupFormHandler adds the necessary ShippingGroups to the Order, establishes their relationships to the CommerceItems, performs validation, and updates the Order. The following table describes the handle methods used in these processes:

Method

Description of Functionality

handleSplitShippingInfos

This handle method splits the quantities of CommerceItems across several CommerceItemShippingInfo objects.

The handle method calls splitShippingInfos(), which retrieves the list of CommerceItemShippingInfo objects from the CommerceItemShippingInfoContainer. The method then iterates through the list. For each CommerceItemShippingInfo, it retrieves the quantity and the splitQuantity. If the splitQuantity is greater than zero and not greater than the quantity, then the method calls splitCommerceIdentifierShippingInfoByQuantity(). In turn, splitCommerceIdentifierShippingInfoByQuantity() creates a new CommerceIdentifierShippingInfo object, adjusts the properties of both the new and existing objects, and adds the new object to the CommerceItemShippingInfoContainer.

handleSpecifyDefault
ShippingGroup

This handle method is used to let the user specify a default ShippingGroup to use for shipping. The method calls specifyDefaultShippingGroup(), which sets the defaultShippingGroupName in the ShippingGroupMapContainer.

Setting the default ShippingGroup can facilitate simpler applications that permit only one ShippingGroup per Order, as well as advanced applications that apply a default ShippingGroup to any remaining items not explicitly covered by other ShippingGroups.

handleApplyShippingGroups

This handle method adds the ShippingGroups to the Order. It is used when the customer has supplied the necessary shipping information for the Order and is ready to proceed with the next checkout phase.

The handle method calls applyShippingGroups(), which first calls ShippingGroupManager.removeAllShippingGroupsFromOrder() to remove any existing ShippingGroups from the Order. This ensures a clean Order.

The applyShippingGroups() method then calls applyCommerceItemShippingInfo(), which applies all CommerceItemShippingInfo objects to the Order. The applyCommerceItemShippingInfo() method iterates through the list of CommerceItemShippingInfo objects in the CommerceItemShippingInfoContainer. For each CommerceItemShippingInfo object, the associated ShippingGroup is retrieved and added to the Order (if it isn’t already in the Order). Then the method retrieves the Relationship type of the current CommerceItemShippingInfo object and calls either CommerceItemManager.addItemQuantityToShippingGroup() or CommerceItemManager.addRemainingItemQuantityToShipping(), depending on the relationshipType (SHIPPINGQUANTITY OR SHIPPINGQUANTITYREMAINING). This adds the appropriate quantity of the CommerceItem to the ShippingGroup.

Next, if the form handler’s applyDefaultShippingGroup property is True, then the applyShippingGroups() method checks for a default shipping group in the ShippingGroupMapContainer. If one exists, then the remaining quantity of all CommerceItems in the Order is added to the default shipping group.

Then, the handle method calls runProcessValidateShippingGroups() to validate the ShippingGroups in the Order. This executes the shipping validation pipeline specified in ShippingGroupFormHandler.validateShippingGroupsChainId; by default, this property is set to validateShippingInfo. For information on the validateShippingInfo pipeline, see Appendix F, Pipeline Chains.

Finally, the handle method calls OrderManager.updateOrder() to save the Order in its present state to the Order Repository. For more information on OrderManager.updateOrder() and the updateOrder pipeline that it executes, see the Updating an Order with the OrderManager subsection of Saving Orders in this chapter.

As previously mentioned, the ShippingGroupDroplet servlet bean is used to initialize CommerceItemShippingInfo objects and add them to the CommerceItemShippingInfoContainer, so they can be used by the ShippingGroupFormHandler. To initialize the CommerceItemShippingInfo objects, the service method calls initializeCommerceItemShippingInfos() which, by default, creates and initializes a CommerceItemShippingInfo for each CommerceItem in the Order and adds them to the CommerceItemShippingInfoContainer. Each new CommerceItemShippingInfo references the default ShippingGroup in the ShippingGroupMapContainer.

The paragraph above describes the default behavior of the ShippingGroupDroplet. The droplet, however, has several input parameters that control whether and how CommerceItemShippingInfo objects are created. An additional parameter controls whether the CommerceItemShippingInfoContainer is cleared before the objects are created. For a detailed list of these input parameters, as well as ShippingGroupDroplet output parameters, open parameters, and a code example, see the Adding Shipping Information to Shopping Carts section of the Implementing Order Retrieval chapter of the ATG Commerce Guide to Setting Up a Store.

The HandlingInstructionInfo class makes it possible to split, merge, and apply handling information along with the CommerceItemShippingInfo objects with which it is associated. When the ShippingGroupDroplet initializes a container based on the current contents of an Order, HandlingInstructionInfo objects are automatically generated for any handling instructions currently in the Order. These HandlingInstructionInfo objects are then associated with the appropriate CommerceItemShippingInfo objects based on the CommerceItem referenced in the handling instruction.

Gift items in an order are identified by a special handling instruction (GiftHandlingInstruction), and therefore the ShippingGroupDroplet and ShippingGroupFormHandler automatically handle splitting and merging of gift items in the order.

If the CommerceItemShippingInfoTools includeGifts property is set to false (the default), it has the following effects:

  • CommerceItemShippingInfo objects don’t include the quantity of the items designated as gifts. For example, if an item is quantity 3, and 1 is a gift, a CommerceItemShippingInfo will be created for a quantity of 2.

  • GiftHandlingInstructions are not included in the HandlingInstructionInfos associated with the CommerceItemShippingInfos

  • ShippingGroups that contain only gifts are not added to the ShippingGroupMapContainer

The result is that none of the gift-related objects in the Order are added to the CommerceItemShippingInfoContainer and ShippingGroupMapContainer when initializing based on the Order, and after applying, they remain unchanged in the Order.

Creating Payment Groups

Oracle ATG Web Commerce provides two implementations of the CreatePaymentGroupFormHandler interface to support the form-driven creation of credit card and invoice payment groups. These form handler classes create the payment groups and optionally add them to the PaymentGroupMapContainer. Once the payment groups are added to the PaymentGroupMapContainer, the user can then select from among them for use in the current Order.

The default implementations of the CreatePaymentGroupFormHandler are:

You can also create Profile-derived PaymentGroups and add them to the PaymentGroupMapContainer by using the PaymentGroupDroplet servlet bean (class atg.commerce.order.purchase.PaymentGroupDroplet). The input parameters passed into PaymentGroupDroplet determine what types of PaymentGroups are created (credit card, store credit, gift certificate) and whether the PaymentGroupMapContainer is cleared before they are created. For a detailed list of these input parameters, as well as its output parameters, open parameters, and a code example, see the Adding Payment Information to Shopping Carts section of the Implementing Shopping Carts chapter of the ATG Commerce Guide to Setting Up a Store.

To initialize the PaymentGroup objects, the service method of PaymentGroupDroplet calls initializeUserPaymentMethods(), which initializes one or more PaymentGroups for the current user and adds them to the PaymentGroupMapContainer. For each entry in PaymentGroupDroplet.paymentGroupTypes (which is supplied via an input parameter), its corresponding PaymentGroupInitializer is obtained from the ServiceMap in PaymentGroupDroplet.paymentGroupInitializers (keyed by PaymentGroup type). The initializePaymentGroups() method of the PaymentGroupInitializer is then used to initialize the PaymentGroup and add it to the PaymentGroupMapContainer.

Note that Commerce provides four implementations of the PaymentGroupInitializer interface. They are:

To use this framework with a new PaymentGroup type that you create, first, write a new PaymentGroupInitializer implementation. Its initializePaymentGroups() method should gather the user’s PaymentGroups by type and add them to the PaymentGroupMapContainer referenced by the PaymentGroupFormHandler. For example, the StoreCreditInitializer queries the Claimable Repository for the user’s StoreCredit PaymentGroups, instantiates objects for them, and then adds them to the PaymentGroupMapContainer. Second, register a Nucleus component for the new PaymentGroupInitializer implementation and add it to the ServiceMap in PaymentGroupDroplet.paymentGroupInitializers, which is keyed by PaymentGroup type. Finally, include the new PaymentGroup type in the PaymentGroupDroplet.paymentGroupTypes parameter on those site pages where the new PaymentGroup type is utilized.

Associating Payment Groups with an Order and Its Items

When the user has supplied the payment information for an Order, the PaymentGroupFormHandler can used to create and manage the associations between the PaymentGroups and the various parts of the Order. Any Order that has been successfully processed by the PaymentGroupFormHandler is ready for the next phase of the purchase process, which is typically order confirmation. Oracle ATG Web Commerce provides a request-scoped instance of atg.commerce.order.purchase.PaymentGroupFormHandler, which is located in Nucleus at /atg/commerce/order/purchase/PaymentGroupFormHandler.

The PaymentGroupFormHandler adds the PaymentGroups to the Order, adds the CommerceItems, ShippingGroups, tax, cost amount and cost remaining information to the PaymentGroups, validates the PaymentGroup information, and finally saves the Order in its present state to the Order Repository. If you’d prefer for items to be priced according to a pricelist rather than the default behavior provided by the pricing engine, set the priceListId property to the appropriate pricelist. When it is finished, the Order is ready to proceed to the next step in the purchase process, which typically is Order checkout. (See Submitting an Order for Checkout.)

The PaymentGroupFormHandler is composed of the following containers:

Additionally, the PaymentGroupFormHandler uses the following helper classes:

With these helper classes and containers, the PaymentGroupFormHandler adds the necessary PaymentGroups to the Order, validates them, and updates the Order. The following table describes the handle methods used in these processes:

Method

Description of Functionality

handleSplitPaymentInfos

This handle method is used when the user wants to split a particular CommerceIdentifierPaymentInfo by amount across multiple PaymentGroups.

The handle method calls splitPaymentInfos(), which retrieves the list of CommeceIdentifierPaymentInfo objects from the CommerceIdentifierPaymentInfoContainer. The splitPaymentInfos() method then iterates through the list and calls splitCommerceIdentifierPaymentInfo() on each object. In turn, splitCommerceIdentifierPaymentInfo() calls splitCommerceIdentifierPaymentInfoByAmount() to split the CommerceIdentifierPaymentInfo object. The method creates a new CommerceIdentifierPaymentInfo object, adjusts the properties of both the existing and new objects, and adds the new object to the CommerceIdentifierPaymentInfoContainer.

In a form, the user might request to split $50 of an original CommerceIdentifier amount of $100 to a separate payment method. This creates a separate CommerceIdentifierPaymentInfo object, and adjusts the amount of both the original and the new CommerceIdentifierPaymentInfo objects to add up to the original CommerceIdentifier total amount.

handleSpecifyDefault
PaymentGroup

This handle method is used to let the user specify a default PaymentGroup to use for payment. The method calls specifyDefaultPaymentGroup(), which sets the defaultPaymentGroupName in the PaymentGroupMapContainer.

Setting the default PaymentGroup can facilitate simpler applications that permit only one PaymentGroup per Order, as well as advanced applications that apply a default PaymentGroup to any remaining Order amount not explicitly covered by other PaymentGroups.

handleApplyPaymentGroups

This handle method adds the PaymentGroups to the Order. It is used when the user has supplied the necessary payment information for the Order and is ready to proceed with the next checkout phase.

The handle method calls applyPaymentGroups(), which first calls PaymentGroupManager.removeAllPaymentGroupsFromOrder() to remove any existing PaymentGroups from the Order. This ensures a clean Order.

Next, the applyPaymentGroups() method calls applyCommerceIdentifierPaymentInfo(), which applies the CommerceIdentierPaymentInfo objects to the Order. The applyCommerceIdentifierPaymentInfo() method iterates through the list of CommerceIdentifierPaymentInfo objects in the CommerceIdentifierPaymentInfoContainer. For each CommerceIdentifierPaymentInfo object, the associated PaymentGroup is retrieved and added to the Order (if it isn’t already in the Order). Then the method retrieves the Relationship type of the current CommerceIdentifierPaymentInfo object and calls the appropriate method in the appropriate “Manager” to add the amount to the PaymentGroup. For more information, see the Assigning Costs to Payment Groups section of the Working With Purchase Process Objects chapter.

Next, if the form handler’s applyDefaultPaymentGroup property is True, then the applyPaymentGroups() method checks for a default payment group in the PaymentGroupMapContainer. If one exists, then the remaining order amount is added to the default payment group.

Then, applyPaymentGroups() calls PaymentGroupManager.recalculatePaymentGroupAmount() to recalculate the payment groups.

Next, the handle method calls runProcessValidatePaymentGroups() to validate the PaymentGroups in the Order. This executes the payment validation pipeline specified in PaymentGroupFormHandler.validatePaymentInformationChainId; by default, this property is to moveToConfirmation. The moveToConfirmation pipeline both prices and validates a given Order. For more information, see Appendix F, Pipeline Chains.

Finally, the handle method calls OrderManager.updateOrder() to save the Order in its present state to the Order Repository. For more information on OrderManager.updateOrder() and the updateOrder pipeline that it executes, see the Updating an Order with the OrderManager subsection of Saving Orders in this chapter.

As previously mentioned, the PaymentGroupDroplet servlet bean is used to initialize CommerceIdentifierPaymentInfo objects and add them to the CommerceIdentifierPaymentInfoContainer, so they can be used by the PaymentGroupFormHandler. To initialize the CommerceIdentifierPaymentInfo objects, the service method of PaymentGroupDroplet calls initializePaymentInfos(), which creates and initializes CommerceIdentifierPaymentInfo objects for the Order, as well as the Order’s CommerceItems, ShippingGroups, and tax. These objects are then added to the CommerceIdentifierPaymentInfoContainer.

The input parameters passed into PaymentGroupDroplet determine whether the CommerceIdentifierPaymentInfo objects are created and whether the CommerceIdentifierPaymentInfoContainer is cleared before they are created. For a detailed list of these input parameters, as well as its output parameters, open parameters, and a code example, see the Adding Payment Information to Shopping Carts section of the Implementing Order Retrieval chapter of the ATG Commerce Guide to Setting Up a Store.

Submitting an Order for Checkout

The CommitOrderFormHandler (class atg.commerce.order.purchase.CommitOrderFormHandler) submits the user’s current Order for checkout. Oracle ATG Web Commerce includes an instance of CommitOrderFormHandler, which is located in Nucleus at /atg/commerce/order/purchase/CommitOrderFormHandler.

The form handler’s handleCommitOrder() method ensures that the user is not trying to double-submit the order by checking if the ID of the current Order is equal to the ID of the user’s last Order (in ShoppingCart.last). If the IDs are not equal, then the current Order can be submitted. The handle method then calls the OrderManager.processOrder() method, which executes the processOrder pipeline. (See Checking Out an Order below.)

If no errors occur during the validation or checkout of the Order, then handleCommitOrder() sets the submitted Order as the user’s last Order in ShoppingCart.last, and it constructs a new, empty Order and sets it as the user’s current Order in ShoppingCart.current.