Tuesday, July 31, 2012

Setting Up Coupons : ATG


ATG Commerce treats coupons as a type of promotion that customers can claim. The customer types in a specific code, and the system adds the corresponding promotion to the customer’s profile. Most of the code for handling coupons is included in the ClaimableManager component and the standard promotion architecture, with a FormHandler to connect these two systems. The process for handling a coupon is as follows:

1.Obtain a coupon code.

2.Try to claim the coupon from the ClaimableRepository.

   Note that coupon codes are case-sensitive. For example, COUP100 and coup100 are two different  
   coupon codes.

3.Add the resulting promotion to the activePromotions list in the user profile.

Use the /atg/commerce/promotion/CouponFormHandler component to obtain a coupon code and add it to a customer’s list of promotions in the customer’s activePromotions profile property. Create an input field on an appropriate site page (for example, a Checkout page) and hook it up to the couponClaimCode property of the CouponFormHandler component. Then, have the form submit to the handleClaimCoupon method of the form handler. This method uses the ClaimableManager component to attempt to get a coupon from the Claimable repository. Then it extracts the promotion from the coupon and uses the PromotionTools component to place the promotion into the customer’s user profile.

The following example shows the JSP code for using the CouponFormHandler component:

<%@ taglib uri="http://www.atg.com/dsp.tld" prefix="dsp" %>
<dsp:page>


<dsp:form method="post">
<!-- Where to go to on success or failure -->
<dsp:input bean="CouponFormHandler.claimCouponSuccessURL"
value="CouponClaim.jsp" type="hidden"/>
<dsp:input bean="CouponFormHandler.claimCouponSuccessURL"
value="CouponClaim.jsp" type="hidden"/>


<!-- Get the coupon claim code -->
Coupon code: <dsp:input bean="CouponFormHandler.couponClaimCode"
type="text"/>
<dsp:input bean="CouponFormHandler.claimCoupon" type="submit"/>
</dsp:form>


</dsp:page>




When a user enters a coupon code on a Checkout page, ATG Commerce checks that the coupon is active and the promotion associated with it is not expired. If both conditions are met, the user “claims” the coupon, which means that the promotion is added to the user’s activePromotions profile property. During order pricing, ATG Commerce determines whether the order qualifies for the coupon’s promotion by checking that:

The order meets the requirements of the promotion

The promotion has not expired

This double-checking capability ensures that if a user claims a coupon as part of one order, discontinues that order, then creates a second one, the promotion applies to the second order, as long as the promotion is active and applicable.

A promotion given by a coupon persists on the user profile, not as part of the order. A claimed coupon is automatically applied to any order to which it qualifies; there’s no need to claim a coupon twice. You can persist a coupon code with an order by adding a new property to the Order object and storing the coupon code in the new property. For information on how to extend the commerce object hierarchy to include a new property, refer to Extending the Purchase Process in the Customizing Purchase Process Externals chapter.

The other step to consider when you set up coupons is to make sure that there are coupons in the Claimable repository for a customer to claim. The following example shows the default item-descriptor for coupons:

<!-- Promotion Claimable object -->
<item-descriptor name="PromotionClaimable" super-type="claimable"
                 sub-type-value="PromotionClaimable">
 <table name="dcspp_coupon" type="auxiliary" id-column-name="coupon_id">
    <property name="promotion" column-name="promotion_id"
item-type="promotion" repository="/atg/commerce/pricing/Promotions"/>
 </table>
</item-descriptor>

The coupon item-descriptor is defined in /atg/commerce/claimable/claimableRepository.xml, which is located in a .jar file at <ATG9dir>/DCS/config/config.jar. The item-descriptor defines a claim code ID and a link to a promotion object in the Promotions repository. If your Web site requires multiple types of coupons, you can define additional item-descriptor types by editing the claimableRepository.xml file and then specifying the valid coupon types in the validCouponItemTypes property in the CouponFormHandler properties file. When a coupon is claimed, the CouponFormHandler.checkPromotionType method checks the item type of the coupon corresponding to the given claim code against the array of acceptable item types in the CouponFormHandler.validCouponItemTypes property.

You can populate the Claimable repository through either the ATG Control Center or the atg.commerce.promotion.CouponDroplet. The CouponDroplet servlet bean takes either a promotion or promotion ID and then generates a coupon for it in the repository. The value of the output parameter in the CouponDroplet is the coupon object. You can obtain the claim code for the coupon using coupon.id. The following example shows the JSP code for the CouponDroplet:

<dsp:importbean bean="/atg/commerce/promotion/CouponDroplet"/>
<h2>here is a coupon that was created: </h2>
<dsp:droplet name="CouponDroplet">
<dsp:param value="promo60001" name="promoId"/>
<dsp:oparam name="output">
  <dsp:valueof param="coupon.id">no value</dsp:valueof>
</dsp:oparam>
<dsp:oparam name="error">
</dsp:oparam>
</dsp:droplet>


You could include the CouponDroplet in a targeted e-mail JSP, thereby creating a coupon code that is ready to send to a customer.

Friday, July 27, 2012

Setting up Price List Functionality in ATG Consumer Commerce


ATG Consumer Commerce users do not have a price list functionality available by default. To add price list functionality, you should:



1.Add the following code to /atg/userprofiling/userProfile.xml in your localconfig:


<gsa-template>


  <header>
    <name>Commerce Related Profile Changes</name>
    <author>DCS Team</author>
     <version>$Id: userProfile.xml,v 1.1 2001/04/26 </version>
   </header>


  <item-descriptor name="user" default="true"
      sub-type-property="userType">


    <table name="dcs_user" type="auxiliary" id-column-name="user_id">
      <property category-resource="categoryCommerceContract"
         name="priceList"
         item-type="priceList"
         display-name-resource="priceList"
         column-name="price_list"
         repository="/atg/commerce/pricing/priceLists/PriceLists"/>
     </table>


   </item-descriptor>


 </gsa-template>


2.Add a price_list column to dcs_user table.


3.Configure the ItemPricingEngine to use the appropriate precalculator. There are price list-specific
   versions of each of the precalculators used by the ItemPricingEngine.ItemPriceListCalculator 
   is the precalculator for list pricing. ConfigurableItemPriceListCalculator is the precalculator for 
   configurable item pricing.



The following code example shows how the /atg/commerce/pricing/ItemPricingEngine.properties file should change to use the priceList calculators


preCalculators=\
        calculators/ItemPriceListCalculator,\
        calculators/ConfigurableItemPriceListCalculator



Note: The configurable item calculator is optional. It only needs to be used if your site supports configurable commerce items.

When an item is priced, the pricing calculators will use the price lists defined here to determine what price to use.

Sunday, July 15, 2012

Creating a New Fulfiller : ATG


You can create a new fulfiller if your site requires fulfillment functionality different from that of the HardgoodFulfiller or ElectronicFulfiller that ship with ATG Commerce. For example, you could create a new fulfiller if your customers can purchase a research report. Instead of allocating this report from inventory and shipping it to the customer via UPS or Federal Express, you send them the report as an attachment via e-mail. There is no need to check inventory since the report is automatically in stock. Shipment can be done immediately since your newly created fulfiller can interface directly with an e-mail system. This section will describe how to implement and configure this new simpler fulfiller. In this example, the new fulfiller is called MyOwnFulfiller.

JMS messages connect the new fulfiller and the rest of ATG Commerce. Specifically, fulfillment of a shipping group begins with a FulfillOrderFragment message. To receive these messages, the new fulfiller must implement atg.dms.patchbay.MessageSink.

In addition to receiving the FulfillOrderFragment messages, MyOwnFulfiller must send out messages to inform the rest of ATG Commerce about changes made to each order. To send these messages, MyOwnFulfiller must implement atg.dms.patchbay.MessageSource. There is a class in atg.commerce.messaging that provides most of the functionality MyOwnFulfiller will need to send and receive messages. This class is called SourceSinkTemplate. It implements both MessageSource and MessageSink. MyOwnFulfiller will be defined as follow:

package myPackage;
import atg.commerce.fulfillment.*;
import atg.commerce.messaging.*;


public class MyOwnFulfiller extends SourceSinkTemplate
The only method in SourceSinkTemplate that MyOwnFulfiller needs to overwrite is receiveMessage.


public void receiveMessage (String pPortName, Message pMessage)
      throws JMSException
{

The Patch Bay system calls this method when a message is sent to MyOwnFulfiller. For more information, see the Dynamo Message System chapter in the ATG Programming Guide. At this time, the only message MyOwnFulfiller listens for is FulfillOrderFragment. The receiveMessage method can check the type of the object in the message. Only the interested code will be listed here, error checking will be assumed.

if(pMessage.getJMSType().equals(FulfillOrderFragment.TYPE))
     handlFulfillOrderFragment(pMessage);
} // end of receiveMessage


The handleFulfillOrderFragment method retrieves the order from the message and the list of shipping groups that need to be fulfilled. For this example, the necessary error checking will be listed here.

Retrieve the FulfillOrderFragmentCommerceMessage from the incoming message:

public void handleFulfillOrderFragment(ObjectMessage pMessage)
{
      FulfillOrderFragment fragment =
            (FulfillOrderFragment) pMessage.getObject();

Retrieve the order and the shipping groups IDs:

Order order = fragment.getOrder();
String[] shippingGroupIds = fragment.getShippingGroupIds();

Call a new method called processShippingGroup for each shipping group in the message.

for(int i=0; i<shippingGroupIds.length; i++) {
      ShippingGroup sg =
            order.getShippingGroup(shippingGroupIds[i]);
      processShippingGroup(order, shippingGroup);
}

One of the responsibilities of MyOwnFulfiller is to notify the rest of ATG Commerce what changes were made to the order included in this FulfillOrderFragment. To do this, MyOwnFulfiller needs to remember each modification made. Therefore, inside handleFulfillOrderFragment, declare a new List that will contain Modification objects. These objects are added to the list as changes are made. This list will need to be included in any method calls. The above code now looks like this:

List modifications = new ArrayList();
for(int i=0; i<shippingGroupIds.length; i++) {
      ShippingGroup sg =
            order.getShippingGroup(shippingGroupIds[i]);
      processShippingGroup(order, shippingGroup,
                            modifications);
}

After processing is complete, MyOwnFulfiller saves the order and include the modifications in a message. This is handled by a method in the OrderFulfillmentTools:

OrderManager orderManager = getOrderManager();
OrderFulfillmentTools tools = getOrderFulfillmentTools();

orderManager.updateOrder(order);
tools.sendModifyOrderNotification(order.getId(), // order
   modificationList, // modifications
   null,             // ModifyOrder
   this,             // MessageSource
   getModifyOrderNotificationPort(),// port
   null);            // original message
}  // end of handleFulfillOrderFragment



See the ATG API Reference for a detailed description of the OrderFulfillmentToolssendModifyOrderNotification method.

MyOwnFulfiller depends on a few properties being set to properly function. It will need an OrderManager, OrderFulfillmentTools, and a ModifyNotificationPort. This port is explained in the Configuring a New Fulfiller section.

The only method that has not been discussed is processShippingGroup. The following example is a simple example of the functions of processShippingGroup in order processing. The most important function is the manipulation of the object states. There are two more properties necessary for the fulfiller: ShippingGroupStates and ShipItemrRelationshipStates.

public void processShippingGroup(Order pOrder,
                ShippingGroup pShippingGroup,
                List pModificationList)
{
   ShippingGroupStates sgStates = getShippingGroupStates();
   ShipItemRelationshipStates sirStates =
     getShipItemRelationshipStates();
   OrderFulfillmentTools tools =
     getOrderFulfillmentTools();


. . . get each item relationship in the shipping group


. . . for each item


  . . . send the report via e-mail using the orders
       profile
     // set the state to DELIVERED
     tools.setItemRelationshipState(shipItemRel,
        sirStates.getStateValue(sirStates.DELIVERED),
        "Report has been e-mailed to customer",
        pModificationList);
. . . end for loop


// the shipping groups is finished
  tools.setShippingGroupState(pShippingGroup,
     sgStates.getStateValue(sgStates.NO_PENDING_ACTION),
     "This shipping group has finished shipping",
     pModificationList);
}




The methods in OrderFulfillmentTools create the appropriate modifications, which are sent in a ModifyOrderNotification message by handleFulfillOrderFragment. The new fulfiller is now ready to be configured into ATG Commerce.

It is possible that the e-mail cannot be sent because of some error. For example, if a message is sent out because the shipping group cannot be shipped and the message contains an invalid e-mail address. One possibility for dealing with this error is to set the ShippingGroup to PENDING_MERCHANT_ACTION. If you implement your fulfiller to do this, then the Customer Service Representative must correct the order and tell the fulfillment system to reprocess that shipping group with a ShippingGroupUpdate Modification sent within a ModifyOrderNotification message.

To facilitate this, MyOwnFulfiller.receiveMessage should be configured to listen for ModifyOrderNotification messages and call handleModifyOrderNotification if one of these messages is received. That method can then call processShippingGroup for each shipping group and send a new ModifyOrderNotification with all modifications that were made.

A new fulfiller must be configured within Nucleus before it can be used by the fulfillment system.

Creating a New Fulfiller : ATG


A new fulfiller must be configured within Nucleus before it can be used by the fulfillment system. This section uses the example of configuring MyOwnFulfiller, the fulfiller created in the Creating a New Fulfiller section.

Use the ATG Control Center to edit the Configuration component located in atg/commerce/fulfillment/.

Change the property fulfillerPortNameMap to include the name of this new fulfiller.

Configure the port on which messages will be sent to this fulfiller. This is the port on which the OrderFulfiller component will send JMS messages for this fulfiller.

For example, add the following to Configuration.properties:

fulfillerPortNameMap+=\
   MyOwnFulfiller=MyOwnFulfillerPort

You will also need to define which types of shipping groups can be handled by your fulfiller. OrderFulfiller uses this information to verify that a shipping group can be fulfilled by its fulfiller. For example, add the following to Configuration.properties:

fulfillerShippingGroupMap+=\
   MyOwnFulfiller=mypackage.MyShippingGroup

In this example, the fulfiller being added is called MyOwnFulfiller. The component using an instance of HardgoodFulfiller should make the name property of the HardgoodFulfiller MyOwnFulfiller

For example, add the following to MyOwnFulfiller.properties:

fulfillerName=MyOwnFulfiller

In addition, add the following properties to MyOwnFulfiller.properties:

orderManager^=Configuration.orderManager
orderFulfillmentTools^=Configuration.orderFulfillmentTools
messageSourceName=MyOwnFulfiller
modifyNotificationPort=ModifyNotificationPort
shippingGroupStates=/atg/commerce/states/ShippingGroupStates
shipItemRelationshipStates=
        /atg/commerce/states/ShipItemRelationshipStates

Configure the MyOwnFulfillerPort in the dynamoMessagingSystem.xml file so that the OrderFulfiller component can send out the FulfillOrderFragment messages on this port.

For example, add the following dynamoMessagingSystem.xml for OrderFulfiller:

<message-filter>
      <nucleus-name>
        /atg/commerce/fulfillment/OrderFulfiller
      </nucleus-name>
       . . .
      <output-port>
        <port-name>
          MyOwnFulfillerPort
        </port-name>
        <output-destination>
          <provider-name>
            sqldms
          </provider-name>
          <destination-name>
            sqldms:/Fulfillment/MyOwnGoods
          </destination-name>
          <destination-type>
            Topic
          </destination-type>
        </output-destination>
      </output-port>
       . . .
</message-filter>

Configure the MyOwnFulfiller component to send messages on the modifyNotificationPort and listen for messages on the sqldms:/Fulfillment/MyOwnGoods topic. These topics are described above.

<message-filter>
      <nucleus-name>
           /myPackage/MyOwnFulfiller
      </nucleus-name>
      <output-port>
        <port-name>
          ModifyNotificationPort
        </port-name>
        <output-destination>
          <provider-name>
            sqldms
          </provider-name>
          <destination-name>
            sqldms:/Fulfillment/ModifyOrderNotification
          </destination-name>
          <destination-type>
            Topic
          </destination-type>
        </output-destination>
      </output-port>
</message-filter>


<message-sink>
   <nucleus-name>
     /myPackage/MyOwnFulfiller
   </nucleus-name>
   <input-port>
     <port-name>
       DEFAULT
     </port-name>


     <input-destination>
         <provider-name>
            sqldms
         </provider-name>
         <destination-name>
            sqldms:/Fulfillment/MyOwnGoods
         </destination-name>
         <destination-type>
            Topic
         </destination-type>
       </input-destination>
    </input-port>
</message-sink>

For more information, see the Dynamo Message System chapter of the ATG Programming Guide.

Set the MessageSourceName property of the MyOwnFulfiller to “MyOrderFulfiller” or another value that indicates who sent a message. This allows the component to ignore messages that it sent itself.

Add another value to the fulfiller property of the SKU in the product catalog. (Defined in /atg/commerce/catalog/productCatalog.xml) This should match the name of the fulfiller used to map to a port in OrderFulfillmentTools.fulfillerPortNameMap.

<item-descriptor name="sku" display-name="SKU"
     sub-type-property="type"
     display-property="displayName"
  . . .
  <property name="fulfiller" data-type="enumerated"
       column-name="fulfiller" queryable="false">
    <attribute name="useCodeForValue" value="false"/>
    <option value="HardgoodFulfiller" code="0"/>
    <option value="SoftgoodFulfiller" code="1"/>
    <option value="MyOwnFulfiller" code="2"/>
   </property>
   . . .
</item-descriptor>

The modificationHandler property can be modified to point to another component that extends atg.commerce.fulfillment.ModificationHandler to handle with different forms of modifications received by the fulfiller. The ModificationHandler class provides a simple framework for changing the handling of ModifyOrder and ModifyOrderNotifications. It is not necessary to use a separate ModificationHandler. In the example above, handleModifyOrderNotification was implemented directly within the fulfiller class MyOwnFulfiller.

Wednesday, July 11, 2012

Shipping Calculators : ATG

1.ShippingCalculatorImpl extends ShippingPricingCalculator

Methods:

a) getAvailablemethods(List pMethods, ShippingGroup pShippingGroup, RepositoryItem pPricingModel, Locale pLocale, RepositoryItem pProfile, Map pExtraParameters)

* Return type is void

* Getting the shipping methods inside it and calculate the shipping methods cost based on the method selection

b) getAmount(Order pOrder, ShippingPriceInfo pPriceQuote, ShippingGroup pShippingGroup,
 RepositoryItem pPricingModel, Locale pLocale, RepositoryItem pProfile, Map pExtraParameters
)

*. Return type is double

*. Getting the orders price, subtotals, subtotalprice,

c)haveItemsToShip(ShippingGroup pShippingGroup)

*. Return type is boolean,

*. Getting commerceItemRelationshipCount based on shippingGroup

d)performPricing(ShippingGroup pShippingGroup)

*. Return type is boolean,

*. Calculate the shipping price for each shipping methods in a shipping group


2.FixedPriceShippingCalculator extends ShippingCalculatorImpl

Methods:

a)getAmount(Order pOrder, ShippingPriceInfo pPriceQuote, ShippingGroup pShippingGroup,
 RepositoryItem pPricingModel, Locale pLocale, RepositoryItem pProfile, Map pExtraParameters
)

*. Return type is double

3.DoubleRangeShippingCalculator extends ShippingCalculatorImpl

Methods:

a)initializeRanges()

*. Its an Abstract class

*. synchronized by thread safety

*. Initializing all the price ranges like lowRanges, highRanges

4.WeightRangeShippingCalculator extends DoubleRangeShippingCalculator

Note : This calculator will calculate shipping costs based upon the total weight of an order. So, the total weight of an order will be calculated, then the range of weight values will be consulted to determine the cost

Methods:

a) getWeightTotal(ShippingGroup pShippingGroup)

*. Return type is double,

*. This method will calculate the total weight of the orders and calculate the cost depends on its weight

b) getWeight(CommerceItem pCommerceItem)

*.Return type is double

*.This method will getting the weight of the each items in an order

c)getQuantity(ShippingGroupCommerceItemRelationship pCommerceItemRelationship)

*. Return type is double

*.This method will getting the total quantity of the each items in an order

5.PriceRangeShippingCalculator extends DoubleRangeShippingCalculator

Note: A shipping calculator that determines the shipping price based on the subtotal of all the items in the shipping group. The service is configured through the ranges property.

Methods:

a) getSubTotal
(Order pOrder, ShippingGroup pShippingGroup)

*.Return type is double

*.This method will getting the subTotal of each orders

b)getRangeComparisonValue(ShippingGroup pShippingGroup)

*.Return type double

* . It will return the getRangeComparisonValue(null, pShippingGroup)

6.PropertyRangeShippingCalculator extends DoubleRangeShippingCalculator

Note: A shipping calculator that determines the shipping price based on the summing the values of a specific property of all the items in the shipping group. The service is configured through the ranges property.

Methods:

a)getRangeComparisonValue(ShippingGroup pShippingGroup)

*. Return type is double



Monday, July 9, 2012

Setting up Price List Functionality in ATG Consumer Commerce


ATG Consumer Commerce users do not have a price list functionality available by default. To add price list functionality, you should:




1.    Add the following code to /atg/userprofiling/userProfile.xml in your localconfig:


    <gsa-template>

      <header>
        <name>Commerce Related Profile Changes</name>
        <author>DCS Team</author>
         <version>$Id: userProfile.xml,v 1.1 2001/04/26 </version>
       </header>

      <item-descriptor name="user" default="true"
          sub-type-property="userType">
        <table name="dcs_user" type="auxiliary" id-column-name="user_id">
          <property category-resource="categoryCommerceContract"
             name="priceList"
             item-type="priceList"
             display-name-resource="priceList"
             column-name="price_list"
             repository="/atg/commerce/pricing/priceLists/PriceLists"/>
         </table>
       </item-descriptor>


     </gsa-template>




2.    Add a price_list column to dcs_user table.


3.    Configure the ItemPricingEngine to use the appropriate precalculator. There are price list-specific
       versions of each of the precalculators used by the ItemPricingEngine.          
       ItemPriceListCalculator is the precalculator for list
       pricing.ConfigurableItemPriceListCalculator 
       is the precalculator for configurable item pricing.

      The following code example shows how the
      /atg/commerce/pricing/ItemPricingEngine.properties

      file should change to use the priceList calculators


      preCalculators=\
            calculators/ItemPriceListCalculator,\
            calculators/ConfigurableItemPriceListCalculator



    Note: The configurable item calculator is optional. It only needs to be used if your site supports
              configurable commerce items.



When an item is priced, the pricing calculators will use the price lists defined here to determine what price to use.

Wednesday, July 4, 2012

Creating Orders : ATG


Creating An Order:


The first step in working with Commerce objects is to create an Order. A shopping cart is an implementation of the Order interface. To create an Order, you must have a reference to an OrderManager or SimpleOrderManager. Once you have the reference, use createOrder() to create the new Order.

There are many versions of the createOrder method, each of which takes a different set of parameters:

createOrder(String pProfileId)


createOrder(String pProfileId, String pOrderType)


createOrder(String pProfileId, String pOrderId, String pOrderType)


createOrder(String pProfileId, OrderPriceInfo pOrderPriceInfo, TaxPriceInfo pTaxPriceInfo, ShippingPriceInfo pShippingPriceInfo)


createOrder(String pProfileId, OrderPriceInfo pOrderPriceInfo, TaxPriceInfo pTaxPriceInfo, ShippingPriceInfo pShippingPriceInfo, String pOrderType)


createOrder(String pProfileId, String pOrderId, OrderPriceInfo pOrderPriceInfo, TaxPriceInfo pTaxPriceInfo, ShippingPriceInfo pShippingPriceInfo, String pOrderType)

All methods create an Order object and assign it a unique ID. The type of Order created depends on the method used. If the method takes an orderType parameter, that parameter determines the type of object that is constructed. Otherwise, the defaultOrderType property of the OrderTools component defines the Order type.

By default, an Order contains one empty ShippingGroup and one empty PaymentGroup when it is created, and their types are determined by the defaultShippingGroupType and defaultPaymentGroupType properties of the OrderTools component.

Note: If you do not want to create an empty ShippingGroup and an empty PaymentGroup for every new Order, set the createDefaultShippingGroup and createDefaultPaymentGroup properties in the OrderTools component to false.

The following example demonstrates how to create an Order:

// Get a reference to the OrderManager
OrderManager orderManager = (OrderManager)
  request.resolveName("/atg/commerce/order/OrderManager");


// Create the Order
Order order = orderManager.createOrder(profileId);


By default, orders are persistent. To disable persistence, set the persistOrders property in the ShoppingCart component to false. The ShoppingCart component is located in Nucleus at /atg/commerce/.


Creating Multiple Orders


Customers can have an unlimited number of orders in existence at one time. They can place items in different shopping carts, switch between carts, retrieve a list of saved carts, delete carts, and can check out one cart’s contents while waiting until later to check out the contents of others.

Using multiple orders requires atg.commerce.order.OrderHolder in addition to atg.commerce.order.Order. This class maintains the current Order object as well as a collection of saved Order objects. The component that utilizes OrderHolder is /atg/commerce/ShoppingCart, a session-scoped component whose handleXXX methods add, delete, and switch between carts, as explained in the rest of this section.

You implement multiple shopping carts using the handleCreate method of the OrderHolder class. This method creates a new Order and sets it as the currentOrder in the OrderHolder. Any previously existing Order object is placed into the collection of saved carts. Refer to the following JSP example:

<dsp:form action="ShoppingCart.jsp" method="post">
  <dsp:input bean="ShoppingCart.create" value="Create" type="submit"/> another
   shopping cart.<BR>
</dsp:form>

The handleSwitch() method allows customers to switch between shopping carts. It switches the current Order object out to the saved collection of orders and sets the current Order to the Order identified by the handlerOrderId property. For example, if a customer has several shopping carts saved, you can allow them to switch between any of the Order objects using the following JSP code:

<dsp:form action="ShoppingCart.jsp" method="post">
 <dsp:select bean="ShoppingCart.handlerOrderId">
  <dsp:droplet name="ForEach">
   <dsp:param bean="ShoppingCart.saved" name="array"/>
   <dsp:param value="SavedOrder" name="elementName"/>
   <dsp:oparam name="output">
    <dsp:getvalueof id="option12" param="SavedOrder.id" idtype="java.lang.String">
<dsp:option value="<%=option12%>"/>
</dsp:getvalueof>
     <valueofparam="SavedOrder.id"></dsp:valueof>
    </dsp:oparam>
   </dsp:droplet>
 </dsp:select>
 <dsp:input bean="ShoppingCart.switch" value="Switch" type="submit"/>
</dsp:form>


The example iterates through the list of saved shopping carts, displays the shopping carts to the customer, and gives the customer the option to select one of the saved carts. The handlerOrderId property would be set to the selected Order ID, and the corresponding Order would be set as the current Order.

The handleDelete() and handleDeleteAll() methods remove a single Order or all orders (both current and saved), respectively.

Popular Posts