The advanced checkout process builds on the basic checkout process by giving the user the ability to ship to multiple locations as well as to pay with multiple forms of payment. While the user can elect to ship/pay with one method in the advanced checkout process, we do not discuss that here since it mirrors that of the basic checkout process. The ability to ship and pay with multiple methods are examined.
Ability to Ship to Multiple Locations
The ability to ship items to multiple locations is defined as the ability to take an order and split the items up into multiple shipping groups. For example, a customer with five bikes and five water bottles in his shopping cart can choose to send the bikes to his house using over night delivery and the water bottles to his work address using second day mail. Or, he could send one bike and two water bottles to his summer house and the remainder to another address.
Two different pages compose provide this functionality: ship_to_multiple.jsp
and shipping_info_multiple.jsp
. Both of these files can be found in <ATG2007.3dir>/PioneerCyclingJSP/j2ee-apps/pioneer/web-app/en/checkout/full
.
ship_to_multiple.jsp
creates new shipping groups in the order and assigns each commerceItem
to them. shipping_info_multiple.jsp
populates any missing address information to the shipping groups/profile.
ship_to_multiple.jsp
allows the user to do several things. Its primary function is to reassign commerceItems
from one shipping address to another. Its secondary function is the ability to create a new nicknamed address in the user’s address book.
Reassigning Items to Shipping Addresses
Reassigning items from one shipping group to another first requires that the current division of commerce items among shipping groups be displayed to the user. The JSP iterates through all the commerce items in the order. Then, it determines how each commerce item is being shipped and displays its destination address and relevant quantity. This is the JSP that displays the current information:
<!--For each CommerceItem in the Shopping Cart do the following: --> <!-----------------------------------------------------------------> <dsp:droplet name="ForEach"> <dsp:param bean="ShoppingCartModifier.order.commerceItems" name="array"/> <dsp:param name="elementName" value="CommerceItem"/> <dsp:oparam name="output"> <!-For each ShippingGroupRelationship for one CommerceItem do the following:-> <!---------------------------------------------------------------------------> <dsp:droplet name="ForEach"> <dsp:param name="array" param="CommerceItem.ShippingGroupRelationships"/> <dsp:param name="elementName" value="ShippingGroupRelationship"/> <dsp:oparam name="output"> <dsp:droplet name="Switch"> <dsp:param name="value" param="ShippingGroupRelationship.shippingGroup.shippingGroupClassType"/> <dsp:oparam name="electronicShippingGroup"> <%/**----------------------------------- * Users can not move things to be shipped via * electronic shipping groups to another type * of shipping group, so don't display goods for * electronic shipping group. */ %> </dsp:oparam> <dsp:oparam name="hardgoodShippingGroup"> <tr valign=top> <!-- Display the QTY value: --> <td align=center> <dsp:valueof param="ShippingGroupRelationship.Quantity"/> </td> <td></td> <!-- Display PRODUCT SKU: --> <td> <dsp:valueof param="CommerceItem.auxiliaryData.catalogRef.displayName"/> </td> <td></td>
Notice that this JSP checks whether the shipping group is of type electronic or hard good. If it is electronic, no information is displayed since electronic goods are delivered via e-mail unlike tangible goods.
After displaying the current delivery information, the site allows the user to make changes. For instance, if five bikes are currently going to “My Shipping Address” the user might want to change the destination to be “My Work Address”. Here is the JSP that does this:
<!-- Each MOVE button will be surrounded by its own "<dsp:form ... action </form>" so that only the values for this one MOVE are saved to the handler: --> <dsp:form action="ship_to_multiple.jsp" method="post"> Ship <!-- Display a textbox containing the current product quantity: --> <!-- Save value they enter in QuantityToMove property on handler: --> <dsp:input bean="ShoppingCartModifier.QuantityToMove" paramvalue="ShippingGroupRelationship.Quantity" size="2" maxlength="2" type="text"/> <!-- Store CommerceItem ID being modified: --> <dsp:input bean="ShoppingCartModifier.CommerceItemIdToEdit" paramvalue="CommerceItem.id" type="hidden"/> <!-- Store OriginalShippingAddressName --> <dsp:input bean="ShoppingCartModifier.originalShippingAddressName" paramvalue="ShippingGroupRelationship.ShippingGroup.Description" name="3" type="hidden"/> of these to <!-- Create a drop-down list with all possible addresses. Save the value they selected in the NewShippingAddressName property on the Handler: --> <dsp:select bean="ShoppingCartModifier.newShippingAddressName"> <%-- <dsp:select bean="ShoppingCartModifier.newShippingAddressName" nodefault="<%=true%>"> --%> <!-- Add each ProfileAddressName to the dropdown list: --> <!-- We want to automatically select the address that the relationship --> <!-- exists for. --> <dsp:droplet name="ForEach"> <dsp:param bean="ShoppingCartModifier.profileAddressNames" name="array"/> <dsp:param name="elementName" value="ProfileAddressName"/> <dsp:oparam name="output"> <!-- SET THE DEFAULT IN THE DROP DOWN LIST --> <dsp:droplet name="Switch"> <dsp:param name="value" param="ProfileAddressName"/> <!-- if this is the address this ShippingGroupRelationship is for, select this address in the drop down list: --> <dsp:getvalueof id="nameval4" param="ShippingGroupRelationship.ShippingGroup.Description" idtype="java.lang.String"> <dsp:oparam name="<%=nameval4%>"> <dsp:getvalueof id="option233" param="ProfileAddressName" idtype="java.lang.String"> <dsp:option selected="<%=true%>" value="<%=option233%>"/> </dsp:getvalueof> </dsp:oparam> </dsp:getvalueof> <!- Otherwise, don't select this address in dropdown list: --> <dsp:oparam name="default"> <dsp:getvalueof id="option241" param="ProfileAddressName" idtype="java.lang.String"> <dsp:option selected="<%=false%>" value="<%=option241%>"/> </dsp:getvalueof> </dsp:oparam> </dsp:droplet> <dsp:valueof param="ProfileAddressName"/> </dsp:oparam> </dsp:droplet> <!-- ForEach ProfileAddress --> </dsp:select> <!-- Dropdown list of ProfileAddressNames --> <!-- MOVE NOW button --> <!-----------------> <dsp:getvalueof id="itemId" param="CommerceItem.id" idtype="java.lang.String"> <dsp:input submitvalue="<%=itemId%>" bean="ShoppingCartModifier.MoveToNewShippingAddress" name="<%=itemId%>" type="submit" value="save this change"/> <!-- NOTE: Because we'll have m ultiple buttons on the same page, we need to give them each a unique NAME or correct values aren't stored in the handler: --> </dsp:getvalueof> <!-- Goto this URL if NO errors are found during the MOVE NOW button processing: --> <dsp:input bean="ShoppingCartModifier.moveToNewShippingAddressSuccessURL" type="hidden" value="ship_to_multiple.jsp"/> <!--stay on this page--> <!-- Goto this URL if errors are found during the MOVE NOW button processing: --> <dsp:input bean="ShoppingCartModifier.moveToNewShippingAddressErrorURL" type="hidden" value="ship_to_multiple.jsp"/> <!-- stay on this page -->
This JSP shows all of the variables necessary for moving items among shipping groups as well as how the site displays the address where items are currently being sent.
There are four properties in the ShoppingCartModifier
that must be set in order to perform a move from one shipping group to another: quantityToMove
, commerceItemIdToEdit
, originalShippingAddressName
, and newShippingAddressName
. The JSP above sets all four of them. quantityToMove
defaults to the current quantity in the particular shipping group, although the user can change this number. The originalShippingAddressName
is automatically set to the current shipping group name. The newShippingAddressName
is set to the address selected by the user out of their list of addresses. Finally, the commerceItemIdToEdit
indicates the commerce item to be moved from one shipping group to another. The description
of the shipping group identifies each shipping group. It is set to the nickname of the address associated with the shipping group.
Finally, we need to submit the form to the ShoppingCartModifier
to instantiate the new shipping group. ship_to_multiple.jsp
has multiple form elements on one page. That is, each line listing a commerce item and its associated shipping group is surrounded by its own form. If this is not done, then the properties of the ShoppingCartModifier
being set, such as quantityToMove,
will be written over many times since each listed commerce item would try to set this property.
The JSP submits the form to the handleMoveToNewShippingAddress()
method of the ShoppingCartModifier
component. It also sets the success and error URLs.
Creating New Nicknamed Addresses
Users can create new nicknamed addresses in their address books on ship_to_multiple.jsp
. If the user creates a new nicknamed address, when the page reloads he has the option of sending his goods to this nicknamed address. He then can associate an actual address with this nickname.
The handleCreateAddress()
method of the ShoppingCartModifier
handles creating a new nickname in the address book. Here is the JSP to create a new address in the address book:
<!-- The user can enter the new address in this text box: --> <dsp:input bean="ShoppingCartModifier.newShippingAddressName" size="20" type="text" value=""/><br> <!-- Pushing the CREATE ADDRESS button will add the address to the user's Profile under the secondaryAddress attribute. The new nickname will also be added to the list of addresses in the drop-down list. --> <dsp:input bean="ShoppingCartModifier.createAddress" type="submit" value="Create this address nickname"/> <!-- GoTo this URL if NO errors are found during the CREATE ADDRESS button processing: --> <dsp:input bean="ShoppingCartModifier.createAddressSuccessURL" type="hidden" value="ship_to_multiple.jsp"/> <!-- stay on same page --> <!-- GoTo this URL if errors are found during the CREATE ADDRESS button processing: --> <dsp:input bean="ShoppingCartModifier.createAddressErrorURL" type="hidden" value="ship_to_multiple.jsp"/> <!-- stay on same page -->
The newShippingAddressName
property must be set for handleCreateNewAddress
to work properly. Then, when the user submits the form the address is automatically added to the user’s address book.
Populating Missing Address Information
Finally, users must enter any missing address information. For example, if a user creates a new nickname address on the ship_to_multiple.jsp
named “Summer House,” this address does not contain any information other than the name “Summer House”. If the user elects to send a bike there, shipping_info_multiple.jsp
needs to obtain the actual address.
There are several things that are useful to note about the process for capturing this information. First, when a user enters a new address, it needs to be inserted into two places: the shipping group that is part of the order and the user’s address book. Second, if the address information is filled in, it is displayed; if not, a form appears asking the user to provide it. Finally, to display the current arrangement of commerce items among shipping groups, it is necessary to iterate through the shipping groups in the order and list the commerce items for each one. This is done just as on ship_to_multiple.jsp
.
First, the code determines if the address information is filled in, by testing for the presence of firstName
. (We decided that firstName
is present in virtually any address so it is a good indicator that the address is filled in.)
<dsp:droplet name="IsEmpty"> <dsp:param bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress.firstName" name="value"/>
If the address is missing, the user must supply it. The address is copied into the shipping group of the order object and into the user’s address book by adding the name of the address (held in the description property) to the addressesToCopy
array property of the ShoppingCartModifier
. When the user submits the form, all addresses in this array get copied from the shipping groups in the order object to the user’s address book.
<%-- Mark this address to be copied from the Order to the Profile so we can persist it --%> <dsp:input bean="ShoppingCartModifier.AddressesToCopy" paramvalue="ShippingGroup.Description" type="hidden"/> <%-- Set the ownerId field of the new address so that we know that this address belongs to the profile. --%> <dsp:input bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress.ownerId" beanvalue="Profile.id" type="hidden"/> Name<br> <dsp:input bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress.firstName" size="15" type="text"/> <dsp:input bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress.middleName" size="10" type="text"/> <dsp:input bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress.lastName" size="15" type="text"/><br> Street address <br> <dsp:input bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress.address1" size="40" type="text"/><br> <dsp:input bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress.address2" size="40" type="text"/><br> City, State, Postal Code<Br> <dsp:input bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress.city" size="20" type="text"/> <dsp:select bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress.state"> <%@ include file="../../user/StatePicker.jspf" %> </dsp:select> <dsp:input bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress.postalCode" size="10" type="text"/><br> Country<br> <dsp:select bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress.country"> <%@ include file="../../user/CountryPicker.jspf" %> </dsp:select> <br>
If the address already exists, the page displays it unless it is private and owned by someone else. For example, if the user is buying something for another person from a gift list, only the city and state of the address are displayed. Please refer to the Gift Registry section of the Merchandising chapter of this guide for more information. The following JSP code determines whether or not the address is private.
<dsp:droplet name="Switch"> <dsp:param name="value" param="ShippingGroup.shippingAddress.ownerId"/> <dsp:getvalueof id="nameval4" bean="Profile.id" idtype="java.lang.String"> <dsp:oparam name="<%=nameval4%>"> <dsp:include page="../../user/DisplayAddress.jsp" flush="true"> <dsp:param name="address" bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress"/> <dsp:param name="private" value="false"/> </dsp:include> </dsp:oparam> </dsp:getvalueof> <dsp:oparam name="default"> <dsp:include page="../../user/DisplayAddress.jsp" flush="true"> <dsp:param name="address" bean="ShoppingCartModifier.Order.ShippingGroups [param:shippingGroupIndex].shippingAddress"/> <dsp:param name="private" value="true"/> </dsp:include> </dsp:oparam> </dsp:droplet>
The last piece of information needed to create a shipping group is the shipping method. For example, customers can choose Next Day delivery, Two Day delivery, etc. For instructions on setting the shipping method, see the Basic Checkout section.
The final part of this process is the submission of the ship_info_multiple.jsp
form and redirecting the user to the payment screens. ship_info_multiple.jsp
submits to handleShipToDone()
, a method of the ShoppingCartModifier
that copies addresses from the order object to the profile. The submit fields look like this:
<!-- CONTINUE button: --> <!----------------------> <!-- Pushing the CONTINUE button will move all commerce items to their new shipping groups, and move on to next page: --> <dsp:input bean="ShoppingCartModifier.ShipToDone" type="submit" value="Continue---> "/> <!-- Goto this URL if NO errors are found during the CONTINUE button processing: --> <dsp:input bean="ShoppingCartModifier.ShipToDoneSuccessURL" type="hidden" value="payment_info_returning.jsp"/> <!-- Goto this URL if errors are found during the CONTINUE button processing: --> <dsp:input bean="ShoppingCartModifier.ShipToDoneErrorURL" type="hidden" value="shipping_info_multiple.jsp"/> <!-- stay on same page -->
Multiple Payment Methods
The advanced checkout process supports payment with multiple methods. For example, a customer can pay with a combination of a credit card and a gift certificate. The payment screen allows a user to select from the saved credit card list in his profile. The following section shows how users enter credit cards and gift certificates.
Entering a Credit Card
When a user enters a credit card he can either elect to use a credit card from the list of credit cards he saved in his Profile or enter a new credit card. If he chooses to use an existing one, the ShoppingCartModifier
component copies all the fields for the credit card from the Profile to the payment group. The JSP to select an existing credit card is:
<dsp:droplet name="ForEach"> <dsp:param bean="Profile.creditCards" name="array"/> <dsp:param name="elementName" value="creditCard"/> <dsp:oparam name="output"> <dsp:droplet name="Switch"> <dsp:param name="value" param="count"/> <dsp:oparam name="1"> <dsp:input bean="ShoppingCartModifier.selectedCreditCardName" paramvalue="key" name="creditCardToUse" type="radio" checked="<%=true%>"/> </dsp:oparam> <dsp:oparam name="default"> <dsp:input bean="ShoppingCartModifier.selectedCreditCardName" paramvalue="key" name="creditCardToUse" type="radio"/> </dsp:oparam> </dsp:droplet> <b><dsp:valueof converter="creditcard" param="key"/></b><br> </dsp:oparam> </dsp:droplet>
This JSP sets the value of the selectedCreditCardName
property of the ShoppingCartModifier
to be the selected credit card from the Profile. When the customer submits an order, the credit card information is obtained from the Profile, using the nickname supplied in the selectedCreditCardName
property.
When the user uses a new credit card, the information is inserted directly into the payment group associated with the order and also copied to the Profile list of credit cards. There are two steps. First, the selectedCreditCardName
property of the ShoppingCartModifier
must be set to the value new
to flag the ShoppingCartModifier
that the card is a new one and should be copied to the user’s Profile. Second, the credit card information is placed into the payment group. This includes the billing address, credit card number, etc.
The following JSP snippet shows how we asked the user for payment information for each payment group in the order. This code can be found in <ATG2007.3dir>/PioneerCyclingJSP/
.
j2ee-apps/pioneer/web-app/en/checkout/full/payment_info_returning.jsp
<dsp:droplet name="ForEach"> <dsp:param bean="ShoppingCartModifier.creditCardPaymentGroups" name="array"/> <dsp:oparam name="output"> <p><dsp:input bean="ShoppingCartModifier.selectedCreditCardName" name="creditCardToUse" type="radio" value="new"/> <b>New card below</b><p> <b>Billing Address</b><p> Name<br> <dsp:input bean="ShoppingCartModifier.creditCardPaymentGroups[param:index] .billingAddress.firstName" beanvalue="Profile.billingAddress.firstName" size="20" type="text"/> <dsp:input bean="ShoppingCartModifier.creditCardPaymentGroups[param:index] .billingAddress.middleName" beanvalue="Profile.billingAddress.middleName" size="10" type="text"/> <dsp:input bean="ShoppingCartModifier.creditCardPaymentGroups[param:index] .billingAddress.lastName" beanvalue="Profile.billingAddress.lastName" size="20" type="text"/><br> Street address <br> <dsp:input bean="ShoppingCartModifier.creditCardPaymentGroups[param:index] .billingAddress.address1" beanvalue="Profile.billingAddress.address1" size="40" type="text"/><br> <dsp:input bean="ShoppingCartModifier.creditCardPaymentGroups[param:index] .billingAddress.address2" beanvalue="Profile.billingAddress.address2" size="40" type="text"/><br> City, State, Postal Code<br> <dsp:input bean="ShoppingCartModifier.creditCardPaymentGroups[param:index] .billingAddress.city" beanvalue="Profile.billingAddress.city" size="20" type="text"/> <%/* ------------------------------------------------------------ * The setvalue is a used to preload the value from * Profile.billingAddress into the address we are modifying. * After the form is submitted the actual value from the form * will be entered into the address. -------------------------------------------------------*/%> <dsp:setvalue bean="ShoppingCartModifier.creditCardPaymentGroups[param:index] .billingAddress.state" beanvalue="Profile.billingAddress.state"/> <dsp:select bean="ShoppingCartModifier.creditCardPaymentGroups[param:index] .billingAddress.state"> <%@ include file="../../user/StatePicker.jspf" %> </dsp:select> <dsp:input bean="ShoppingCartModifier.creditCardPaymentGroups[param:index] .billingAddress.postalCode" beanvalue="Profile.billingAddress.postalCode" size="10" type="text"/><br> Country<br> <dsp:setvalue bean="ShoppingCartModifier.creditCardPaymentGroups[param:index] .billingAddress.country" beanvalue="Profile.billingAddress.country"/> <dsp:select bean="ShoppingCartModifier.creditCardPaymentGroups[param:index] .billingAddress.country"> <%@ include file="../../user/CountryPicker.jspf" %> </dsp:select> <br> Phone Number<br> <dsp:input bean="ShoppingCartModifier.creditCardPaymentGroups[param:index] .billingAddress.phoneNumber" beanvalue="Profile.billingAddress.phoneNumber" size="20" type="text"/><br> <p> <b>Credit Card</b> <p> <!-- Set the type of card --> New card type <dsp:select bean="ShoppingCartModifier.creditCardPaymentGroups[0].creditCardType" required="<%=true%>"> <dsp:option value="Visa"/>Visa <dsp:option value="MasterCard"/>Master Card <dsp:option value="AmericanExpress"/>American Express <dsp:option value="Discover"/>Discover </dsp:select><br> <!-- Set card type and expiration date --> New card number and expiration date<br> <dsp:input bean="ShoppingCartModifier.creditCardPaymentGroups[0].creditCardNumber" maxsize="20" size="20" type="text"/><br> <!-- Set the month that the card will expire on --> Month: <dsp:select bean="ShoppingCartModifier.creditCardPaymentGroups[0].expirationMonth"> <dsp:option value="1"/>January <dsp:option value="2"/>February <dsp:option value="3"/>March <dsp:option value="4"/>April <dsp:option value="5"/>May <dsp:option value="6"/>June <dsp:option value="7"/>July <dsp:option value="8"/>August <dsp:option value="9"/>September <dsp:option value="10"/>October <dsp:option value="11"/>November <dsp:option value="12"/>December </dsp:select><br> <!-- Set the year that the card will expire on --> Year: <dsp:select bean="ShoppingCartModifier.creditCardPaymentGroups[0].expirationYear"> <dsp:option value="2002"/>2002 <dsp:option value="2003"/>2003 <dsp:option value="2004"/>2004 <dsp:option value="2005"/>2005 <dsp:option value="2006"/>2006 <dsp:option value="2007"/>2007 <dsp:option value="2008"/>2008 <dsp:option value="2009"/>2009 <dsp:option value="2010"/>2010 <dsp:option value="2011"/>2011 <dsp:option value="2012"/>2012 </dsp:select> </dsp:oparam> </dsp:droplet>
Note that credit card information is not inserted directly into ShoppingCartModifier.paymentGroup
because customers may use a combination of payment methods. The ShoppingCartModifier
has a CreditCard
payment group as one of its properties. After the values for the new credit card are copied to this location, the ShoppingCartModifier
merges this new payment group into the right place in the order. The property of the ShoppingCartModifier
that contains these payment groups is the creditCardPaymentGroups
. This is an array property of credit card payment groups that defaults to a size of one. This credit card is copied to the order as well as placed into the user’s Profile property creditCards
. The nickname for the credit card in the creditCards
property of the Profile is the credit card number.
There are two final points about adding credit cards to an order that should be discussed. First, when a credit card is added to the order, it always is given a relationship to the Order
object of OrderAmountRemaining
. This means that the credit card is used to pay for any part of the order that is not accounted for by other payment methods. For a discussion of relationships between payment groups and orders, consult the section on Using Relationship Objects in Working with Purchase Process Objects chapter in the ATG Commerce Programming Guide.
ATG Consumer Commerce allows you to implement multiple credit card payment. However, the Pioneer Cycling store only supports one credit card per order.
Paying with Gift Certificates
Paying with gift certificates is a relatively straightforward process. The single string property ShoppingCartModifier.giftCertificateNumbers
can hold any number of gift certificates. That is, the user can enter as many gift certificate numbers as desired as long as they are delimited by white space. These gift certificates are incorporated into new payment groups and added to the order in the following manner:
If you have gift certificates, type their codes below<br> <dsp:input bean="ShoppingCartModifier.giftCertificateNumbers" size="50" type="text" value=""/><br>
Users obtain gift certificate claim numbers by purchasing them in the store. Refer to the section on Gift Certificates in the Merchandising chapter in this guide for more information.
Form Submission
Finally, all of these new payment methods must be submitted to the ShoppingCartModifier
. The JSP to do this is.
<dsp:input bean="ShoppingCartModifier.MoveToConfirmation" type="submit" value=" Continue -->" />
This code submits the form and the handleMoveToConfirmation()
method creates and inserts payment methods in the order.