The e-commerce module lets you add online shopping to your site.
By default, it sets up a basic structure of some product groups, two products, a checkout page, an account page and a terms and conditions page to describe your terms of use. These are used for examples, and the content for each e-commerce page type can be changed like a normal page would using the SilverStripe CMS.
These were originally noted by Sam and extended by Sean to provide a broader understanding of what they do. Add these setup changes to the mysite/_config.php file in your project folder.
Currently the e-commerce module supports DPS (Direct Payment Solutions) via PxPost, and WorldPay for credit card processing.
DPS and WorldPay and cheque are integrated into the e-commerce module out of the box. By default, the only payment type accepted is cheque unless you enable DPS or WorldPay using the configuration.
The setup for payment methods is a line in mysite/_config.php, for example:
// Define which payment methods your site uses. Payment::set_supported_methods(array( 'WorldpayPayment' => 'Credit card (WorldPay)' ));
Payment::set_supported_methods()array('PaymentClassName' ⇒ 'Title of payment method')If you want to use WorldPay, you can add these lines to the same file we did above to set up your account.
You can also choose what the mode the processor operates in (100 is test, 0 is live).
The callback password needs to be defined so that WorldPay can redirect back to the site after WorldPay has processed the payment. (WARNING: Your site needs to be accessible by WorldPay (not password protected, like in a local environment) for the callback to work. If callback fails, you will have to re-enable callback in your WorldPay configuration (on the WorldPay site).)
// Define which payment methods your site uses. Payment::set_supported_methods(array( 'WorldpayPayment' => 'Credit card (WorldPay)' ));
// Set the installation ID of your WorldPay account. WorldpayPayment::set_installation_id(111111); // Check if the site is in 'live' mode, use WP live mode. // otherwise, use WP test mode instead to be careful. if(Director::isLive()) { WorldpayPayment::set_testmode(0); } else { WorldpayPayment::set_testmode(100); } // Set the callback password for your account WorldpayPayment::set_callback_password(blahblah);
Setting up DPS to work with the e-commerce module is a simple process of using the following code in your project's _config.php file, and making sure the credentials are correct with your DPS account.
If you are signing up for a brand new DPS account, please ensure that you are using PxPost. Details of this can be found at: http://www.dps.co.nz/technical_resources/ecommerce_nonhosted/pxpost.html
// Define which payment methods your site uses. Payment::set_supported_methods(array( 'DPSPayment' => 'Credit card (DPS)' ));
// Check if the site is in 'live' mode, use the live credentials. // otherwise, use test credentials instead to be careful. if(Director::isLive()) { DPSPayment::set_account('MyDPSAccountLive', '11111111'); } else { DPSPayment::set_account('MyDPSAccountDev', '11111111'); }
DPSPayment::set_account()Testing DPS
A page for reference in terms of testing your DPS account with the e-commerce module can be found here: https://www.paymentexpress.com/knowledge_base/faq/developer_faq.html#testing
To set up a PayPal payment, you need only the mail address of the account
// Check if the site is in 'live' mode, use the live credentials. // otherwise, use test credentials instead to be careful. if(Director::isLive()) { PayPalPayment::set_account_email('mymail@mydomain.com'); } else { PayPalPayment::set_test_mode('mymailtest@mydomaintest.com'); }
For example, if you want DPS and cheque as accepted payments on your site you would have something like this as your Payment::set_supported_methods(array()) function in mysite/_config.php:
// Define which payment methods your site uses. Payment::set_supported_methods(array( 'DPSPayment' => 'Credit card (DPS)', 'ChequePayment' => 'Cheque' ));
By default, there is no shipping cost added to products. However, out of the box there is support for a fixed shipping price for each country. You can define this by editing your _config.php file within the project directory (typically mysite on a default installation of SilverStripe).
Below is an example of how you would define this inside mysite/_config.php:
This example below shows a fixed shipping price for all countries:
// Set a flat rate for shipping charges on an order. SimpleShippingCalculator::set_charges(5);
And this example demonstrates a fixed price of 5 for any country, with an override of 10 if the country shipping to is Australia (AU):
// Set a flat rate for shipping charges on an order. If the user is from AU // (Australia), then their shipping becomes 10 for an order (overrided). SimpleShippingCalculator::set_charges(5); SimpleShippingCalculator::set_charges_for_countries(array( 'AU' => 10, ));
For a list of country codes you can use, please visit http://www.bcpl.net/~j1m5path/isocodes.html
Tax calculation is used for adding country tax onto orders. You can easily configure this the same way you would with shipping calculation.
By default, there is no tax charged.
Below is an example of how to use tax calculation. It is added into mysite/_config.php:
// Set the tax calculation to be for NZ customers at 12.5% exclusive // on the order price. TaxCalculator::set_for_country("NZ", 0.125, "GST", "exclusive");
TaxCalculator::set_for_country()
You can choose which currency your site operates in. If you don't specify a currency in mysite/_config.php then it defaults to USD (US Dollars).
Below is an example of how to choose the NZD currency. It is added into mysite/_config.php:
// Set the currency of the site to be in NZD (New Zealand Dollars). Order::set_site_currency("NZD");
After a user purchases their order they receive an email from the system showing a summary of what they ordered, and the details that they submitted on the order form.
Below is an example of how to choose the email customers will see (the from address) when they receive their emails. This email address also receives a copy of the receipt the customer will get (with their order details). It is defined in mysite/_config.php like below:
// Set the email of the admin who looks after receiving the order emails. Order::set_email('bob@mygreatshop.com');
If you don't define Order::set_email() inside mysite/_config.php then it will attempt to get the admin email address as defined in Email::setAdminEmail(). Failing that, it won't send any admin emails at all until you define one in mysite/_config.php.
Overriding the default CSS in the e-commerce module is easy. The classes like CheckoutPage are setup to use the CheckoutPage.css file found in the module (built for the Black Candy theme). You can, however, place a file of the same name inside your project folder. For example, if you place CheckoutPage.css inside mysite/css/ it will override ecommerce/css/CheckoutPage.css with your one as preference. All the main CSS files in the e-commerce module are setup to do this using the init() function and Requirements::css().
Overriding the templates is the same as overriding the CSS. You would simply copy the template used in the module into your project directory, as we would do above with CSS and it would take preference to your one over the e-commerce module default template.
If you want to add or remove fields to the order form or my account page, you can create a Member role decorator with an augmentEcommerceFields function defined. This function will be passed a fieldset object with the member-specific fields. It won't include any payment fields, or the separate shipping address selector.
If you wish to show different fields for new users, you can check to see if $this→owner→ID has a value. New users will have this function called on the singleton object, which has no ID#.
class MyCustomRole extends DataObjectDecorator { function augmentEcommerceFields(&$fields) { // Returning users shouldn't be shown phone / email fields if($this->owner->ID) { $fields->removeByName('HomePhone'); $fields->removeByName('MobilePhone'); $fields->removeByName('Email'); } } }
Note: This change went into trunk 2007-14-12, and won't be available in a stable release until 0.6.
By default the class SimpleShippingCalculator is used to calculate shipping. However, developers are able to create their own classes to calculate shipping based on a custom set of rules.
First of all, to override the default SimpleShippingCalculator class with an example class called CustomShippingCalculator you can use the line in your project _config.php file like this:
Object::useCustomClass('ShippingCalculator', 'CustomShippingCalculator');
Once you've done this, you can then create your file inside your project (inside mysite/code - replace mysite with your project name if it isn't mysite) called CustomShippingCalculator.php and set it up like this, which extends ShippingCalculator:
<?php class CustomShippingCalculator extends ShippingCalculator { function getCharge(Order $o) { // insert logic to do shipping calculation, refer to SimpleShippingCalculator for how this works } } ?>
You can examine SimpleShippingCalculator to see how that class works to calculate shipping as an example. From there you're free to create it how you see fit.
There is also an experimental WeightBasedShipping class in the e-commerce code which can be used as a reference.
The e-commerce module features a Payment API that can be easily extended to allow addition of another payment gateway, currently DPS and WorldPay have already been integrated into the module and are available to use. However, if you want to add your own payment gateway a good place to start would be sub-classing Payment.
For example:
class CustomPayment extends Payment { // insert your payment code here, refer to DPSPayment.php or WorldpayPayment.php // for reference. }
Then, to use CustomPayment as a payment method you can use this:
// Define which payment methods your site uses. Payment::set_supported_methods(array( 'CustomPayment' => 'My Custom Payment' ));
Obviously you will want to rename 'Custom' to something a bit more appropriate to what gateway you're trying to implement for your e-commerce site.
To get an idea of how DPS and WorldPay are currently implemented please see DPSPayment.php and WorldpayPayment.php which are included with the module.
WorldPay: The receipt email doesn't get sent out because of inaccurate information generated in it.
To see the changelog, ecommerce-changelog.
Here is a small guide through all the classes included in the e-commerce platform.
The following classes extend the Page class:
The following classes extend the Controller class:
The following classes extend the DataObject class:
The following classes extend the Form Class:
The folliwng classes extend the RequiredField class:
The following classes extend the DataObject class:
The following classes extend the DataObjectDecorators class:
The following classes extend the Payment class:
The following classes extend the Object class:
The following classes extend the ViewableData class:
The following classes extend the Report class (the Report class is also defined in the e-commerce module):
The following classes extend the Email_Template class:
The following classes extend the SideReport class:
The following are stand alone classes for the ecommerce module:
Here is a diagram on how the data model works for the eCommerce module core classes.
The eCommerce data model is centred around the Order and OrderAttribute classes. Each of these core classes are data bound classes, meaning that instances of them are designed to be saved into the database, which describes the order. Both extend from DataObject in order to achieve this. These two classes make up the bulk of the core eCommerce system, and as a result most of the other components in the eCommerce package link to it in some form, either directly or indirectly. For example, the Product class, which contains information about the item for sale indirectly associates with Order through the Product_OrderItem class, which is an extension from OrderItem.
An Order has a one-to-many relationship with multiple classes. Specifically, an Order has a a one-to-many relationship with these classes (as of the current version of eCommerce):
To describe the one-to-many relationship for one of these classes to Order, we will take Payment as an example.
An Order has many Payment class instances related to it. This would be the payments that make up the order from the customer who purchased the goods. The customer usually would make one payment, which is the cost of the entire order. However, if they wished, they could pay for their order in parts - such as half at the start, and another half later on. This is why an Order has many Payments related to it, because it can allow for multiple payments for an order.
Order also has a many-to-one relationship with Member, so a Member can have many Orders, and an Order has one Member. This Member instance would be the person who ordered the goods, and thus makes up the billing details of the order.
Order is a core class to the eCommerce module. It contains many number of “Order attributes” (see OrderAttribute), properties, payments, and functions for determining what's in the order at the time of checkout, finding out the current currency, and tax information on order if applicable. It's also responsible for being the “glue” for all the other eCommerce core components, in that it communicates with multiple classes.
A specific example of a property on Order is a boolean flag called UseShippingAddress that determines whether the order is to be shipped to an alternate address than the member (billing) address who created the order. The alternate address is stored on the Order as well, through the ShippingName, ShippingAddress and such properties. It also contains a Status property - for example, after the goods for that order have been shipped, the Status property on Order would be set as Sent, thus giving an accurate representation of where the order is currently at.
Order has a one-to-many relationship with multiple classes that make up the order. Here they are at the time of writing:
There are also some helper classes that relate to Order:
OrderAttribute directly relates to the Order class, many OrderAttribute instances make up an Order. OrderModifier and OrderItem are two implementations of OrderAttribute, which provide specific functionality that modifies or links products to the order. They are designed to be abstract, so a developer can create additional extensions which implement existing OrderModifier and OrderItem features.
OrderItem and OrderModifier have functionality that is directly baked into the Order class, so that the Order knows what to do with the functionality. We will now go through OrderModifier and OrderItem explaining how they fit in, and how to set them up.
Introduction
Order modifiers are a way of adding or deducting an amount to an order, for example, a tax calculator which adds additional tax to an order, or a shipping module.
Two examples of existing functionality that implement OrderModifier are:
If any of these are enabled, they will change the order total by adding or subtracting from the total. Each have their own encapsulated methods which handle the logic of how much to add or subtract based on the situation of the shop user. Both SimpleShippingModifier and TaxModifier add to the total in this case, however, a modifier can be created that would deduct an amount from the order instead of adding to it.
Setting up
Order::$modifiers is a array of the OrderModifiers classes that are recognised as being “in use”. They are defined by calling Order::set_modifiers(Array) where Array is an array of OrderModifier subclasses that should be enabled. e.g. in your _config.php for your project:
Order::set_modifiers(array( 'SimpleShippingModifier', 'TaxModifier' ));
Extending
In the above example, we've enabled SimpleShippingModifier, and TaxModifier. Each of these implement OrderModifier by subclassing it. The required variables/functions to be implemented are:
$is_chargable see API documentation
LiveAmount() see API documentation
TableTitle() see API documentation
Example
Here is a simple example of an OrderModifier in action. In this case, we have a simple voucher system that just takes $10 off the total of the order.
<?php class VoucherModifier extends OrderModifier { protected static $is_chargable = false; function LiveAmount() { return 10; } function TableTitle() { return 'Voucher deduction'; } } ?>
We also need to add VoucherModifier to the initialized modifier classes. This is done by defining Order::set_modifiers() - e.g.:
Order::set_modifiers(array( 'VoucherModifier' ));
Now when someone creates a new order by adding items to their cart, the modifier is enabled and calculates how much is to be deducted from the total price of their cart items.
OrderItem is the class that handles determining what data type should be for purchase. By default, it's a Product data type. OrderItem is the base class for all types of data that can be purchased. To show an example of the Product data type being purchasable as an order item, see Product_OrderItem in the API documentation.
Usually you would just use Product_OrderItem to relate your Product(s) to an Order. However, if you want to apply another type of data to be an OrderItem, then you need to subclass OrderItem. For example, you may want to put an event for sale, which should use the same checkout as normal products. In which case you'd call your class Event_OrderItem where “Event” is the class name of the data type, and should be in the same file. In this case, Event.php.
Payment is the base “abstract” class for all manner of payment types, ranging from cheque, to paypal to custom credit card payment gateway solutions.
By default, a number of implementations come out of the box with the eCommerce module. Here they are, at the time of writing:
In order to create your own types of payment, you need to create a new class that subclasses Payment.
There are some methods that must be implemented on your class in order for the payment to operate correctly. These are:
processPayment() (See API documentation)getPaymentFormFields() (See API documentation)getPaymentFormRequirements() (See API documentation)See DPSPayment in the API documentation for an example of how DPS is implemented for Payment.
Please use comments for notes, tips and corrections about the described
functionality.
Use the Silverstripe Forum to
ask questions.