Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
258 lines (195 sloc) 12.3 KB
= Shopping Trike
A simple shopping cart for RadiantCMS.
Version 0.1
Tobin Richard, Tricycle Developments
= Introduction
This RadiantCMS extension provides a simple shopping cart. It does not provide complete checkout, customer management or payment processing. Instead, it passes this work off to an external application so you can extend your existing system just far enough to capture the cart from Shopping Trike and take your customer's money (see the section on payment processing for details).
The cart created by Shopping Trike work fine in old browsers but also includes AJAX functionality for updating cart contents without reloading your store's pages.
= Installation
Installing Shopping Trike is just like any other radiant extension. Begin by exporting the project's SVN repository into your Radiant site's vendor/extensions/ directory.
cd vendor/extensions/
svn export
Now restart your web-server and login to Radiant's admin interface. Make sure that the Shopping Trike extension is enabled on the extensions admin page.
For the AJAXified shopping cart to work correctly, the layout used for Store pages
must include the prototype.js library. To include the library insert the following into the layout's head:
<script src="/javascripts/prototype.js" language="JavaScript" type="text/javascript"></script>
That's it! If you can see a "Products" tab in the admin interface then you've successfully installed the extension. You can now start creating your store.
= Entering and changing products
Open the products tab in the admin interface and you should see a list of all existing products as well as the option to create new ones.
= Creating a store page
After adding some products you probably want a way for customers to be able to view and buy them. Create a new Radiant page set its type to "Store".
The body of this page will be used as the store's main page. To iterate over your products use <r:shopping:product:each> ... </r:shopping:product:each> tags.
Within those tags you may use the following tags to display product information:
* <r:shopping:product:link> ... </r:shopping:product:link> - create a link to the current product's page.
* <r:shopping:product:code/> - the product's code.
* <r:shopping:product:addtocart/> - an add to cart form for the product.
* <r:shopping:product:description/> - the product's description.
* <r:shopping:product:price quantity="1"/> - the products price for the given quantity (default quantity=1).
So a simple store page body might contain the following:
<p>Welcome to our store!</p>
Here are our products:
<r:shopping:product:code/> - <r:shopping:product:price/><br />
<r:shopping:product:link>show details</r:shopping:product:link>
= Creating product pages
All products for given store page share the same format. To create such a format add a new part to your store page called "product". The contents of this page part will be used to display all products.
The tags you may use to create this page part are the same as those which may be used inside <r:shopping:product:each> ... </r:shopping:product:each> tags. So a simple product page part might look like the following:
= Express Purchase
<r:shopping:product:expresspurchase next_url="/purchase/payment" quantity=1 />
within a shopping:product:each loop.
To produce a button that immediately overrides the existing cart with the specified quantity of this product. If no quantity is specified, then an input field for the quantity is also produced. After processing the controller redirects back to the same page, or next_url if specified.
You can set next_url to point to the eula page or the payment page.
To use with a specific product instead of all products in the each loop, use the tags
<r:shopping:product:each only="prodcode anotherproduct"> ... </r:shopping:product:find>
Where there are multiple products to be selected, list them separated with blanks. Invalid product codes will be ignored.
= Displaying the cart contents
The above product page provides a form for adding a product to our cart but doesn't allow us to view the cart contents or checkout the cart.
Shopping carts in Shopping Trike are never viewed directly, they are always embedded in other pages. Why? We generally want to display a cart in a store's sidebar and again on the checkout page to allow the customer to review it's contents but we want a uniform appearance. So how do we create this embeddable cart? We create another page part, this time called "cart".
The main cart contents must appear between <r:shopping:cart:form> ... </r:shopping:cart:form> tags. The tags you may use to help you build the cart are:
* <r:shopping:cart:item:each> ... </r:shopping:cart:item:each> - Iterates over each cart item.
* <r:shopping:cart:total /> - The total cost of all items in the cart.
* <r:shopping:cart:empty /> - A button to remove all items from the cart.
* <r:shopping:cart:update /> - A button to update the quantities of items already in the cart (see the following item tags).
Within <r:shopping:cart:item:each> ... </r:shopping:cart:item:each> tags the following tags are available:
* <r:shopping:cart:item:code /> - The code of the item.
* <r:shopping:cart:item:unitcost /> - The price for each item at the current quantity.
* <r:shopping:cart:item:quantity /> - The quantity of the item in the cart.
* <r:shopping:cart:item:subtotal /> - The total cost for that quantity of that item in the cart.
* <r:shopping:cart:item:update /> - A textbox where customers may enter a new quantity for the item.
* <r:shopping:cart:item:remove /> - A button to remove the item from the cart.
So a simple cart page part might look like the following:
Your shopping cart:
<r:shopping:cart:item:code/> costs <r:shopping:cart:item:unitcost /> per unit<br/>
You have <r:shopping:cart:item:quantity/> of these<br/>
subtotal: <r:shopping:cart:item:subtotal /><br/>
Change quantity: <r:shopping:cart:item:update/><br/>
Remove from cart: <r:shopping:cart:item:remove/>
Update cart quantities: <r:shopping:cart:update />
Total cart price: <r:shopping:cart:total /><br/>
Empty cart: <r:shopping:cart:empty /><br />
To include the cart in any of the store page parts use Radiant's built in content tag like so:
<r:content part="cart" />
= Checking out the cart
How do we provide a way for users to checkout a cart? We create another page part of course! This time we need a page part called "checkout". The tags of interest when creating checkout page parts are:
* <r:shopping:checkout:process processor_url="" next_url=""> ... </r:shopping:checkout:process>
* <r:shopping:eula:link />
The first, <r:shopping:checkout:process> ... </r:shopping:checkout:process> tags create a form which will start the payment process using the external application (read the section on payment processing). You must specify a processor_url and next_url as tag attributes (read the section on payment processing). Inside the tags you may include information about your terms of sale or a link to your EULA. If the user does not check the box saying they agree to these then the payment process wont be started and the will be directed back to the checkout page.
The <r:shopping:eula:link /> tag generates a link that will display your license agreement or terms of sale (see the following section on EULA's).
If you don't want customers to be able to checkout their cart without first reading the EULA then you may exclude the <r:shopping:checkout:process> ... </r:shopping:checkout:process> tags but still use <r:shopping:eula:link /> to move customers through the checkout process.
So a simple checkout page part which displays a customer's cart and directs them the terms and conditions page might look like the following:
Review your cart contents:
<r:content part="cart"/>
To finalise and checkout this cart please proceed to the <r:shopping:eula:link />.
To include a "checkout" link in any of your store's pages use the <r:shopping:cart:checkout/> tag.
= EULAs and terms and conditions
The final page part of interest is the "eula". This contains the set of terms and conditions which your customers must agree with before a cart will be set to the payment processor. You may use the same tags in a eula page part as in a checkout page part.
So a simple eula page part that allows customers to agree to the conditions and proceed to the payment system might look like the following:
<li>Don't steal our stuff</li>
<li>We get your first born child</li>
<li>Any number of unenforceable and legally void conditions would go here</li>
<r:shopping:checkout:process processor_url="" next_url="">
I agree to the terms and conditions outlined above
= Payment Processing
As noted above Shopping Trike _does not_ process payments. Instead it relies upon external applications for this functionality.
When a user submits a form created using the <r:shopping:checkout:process processor_url="..." next_url="..."> ... </r:shopping:checkout:process> tags a few things happen. The significant steps are:
1. The submitted form data is inspected to make sure the user agreed to the terms and conditions.
2. The cart has a unique identifier added to it.
3. If processor_url is specified in tags then
a. The cart is converted to well-formed XML (examples below).
b. The cart XML is transmitted to processor_url specified in the tags.
c. The response from the processor_url is examined to ensure that the server responded with code 200 (OK).
6. The customer's web browser is redirected to next_url specified in the tags. If processor_url is specified in tags then the cart id is passed as the GET parameter "cart".
= Internal Processing
where the next_url is local to this server, then the cart may be accessed via session[:cart]
= External Processing
External processing is enabled by the processor_url specified in tags
After that it is entirely the receiving application's responsibility to turn the cart XML into whatever model it uses and process payment for the cart. A typical process for the external application would be:
processor_url request:
1. Receive the cart XML and turn it into some internal order model.
2. Save the model to a temporary file that can be looked up based on cart ID.
next_url request:
1. Use the GET parameter "cart" to locate the internal order model's temporary file.
2. Load the order model and associate it with the customer's session.
3. Gather payment details.
4. Process payment.
5. Record order in audit log.
The XML format produced from Shopping Trike's cart has the following structure:
An example XML cart generated by an imaginary pizza parlour eCommerce system for a customer ordering a single pizza and two garlic breads would look like the following:
<?xml version="1.0" encoding="UTF-8"?>
<description>A family size BBQ pizza fresh from our ovens!</description>
<description>Fresh garlic bread. Mmmm Tasty!(tm)</description>
Future versions of Shopping Trike may extend this format but the tags already present will probably remain as they are.