Shipping Modules in Magento: Part 1

Exclusive offer: get 80% off this eBook here
Magento 1.3: PHP Developer's Guide

Magento 1.3: PHP Developer's Guide — Save 80%

Design, develop, and deploy feature-rich Magento online stores with PHP coding

₨739.00    ₨147.80
by Jamie Huskisson | January 2010 | MySQL Open Source PHP

In this two-part article by Jamie Huskisson, we will apply our knowledge of Magento's core architecture and apply it to one of the fundamental building blocks of Magento, its shipping module.

Here, we will learn how to create a shipping module, so that we can develop our own when the need arises. By the end of this article we will:

  • Know where to find shipping modules that others have produced
  • Know how to put together a basic shipping module and know what values pertain to what information
  • Be able to create our own methods for calculation or handling shipping with Magento

What shipping modules do

Shipping modules are used to define the handling of the order, before it goes through the payment method section of the order process. They take the order itself and decide how to go about charging and delivering it to the customer. Magento takes the order through each shipping module that is installed and active in the system. Each shipping module is then able to process the order currently in the cart and present any available options to the user, from what it sees in the order.

For example: we have a shipping module in our system that provides free delivery to people located within the UK and ordering over £40. Let's presume that we are ordering £50 worth of goods and are located within the UK. When the order is sent through this module, it checks whether or not the user is in the UK and the order total is over £40. If these conditions are met, (which our order does), then we are presented with a free delivery option, among others, to choose during our order process.

This is a very simple version of what a shipping module can do. The full range of what can be done using shipping modules can be grasped by looking at Shipping Modules on Magento Connect and finding what it has on offer. Here's a small range of what has been made public:

  • Royal Mail UK, EU, and Worldwide Shipping module — For calculation and handling of all of Royal Mail's shipping methods using weight and distance. This module sends key product information to Royal Mail via their API, authenticating with information that the Magento store administrator has input, and outputs pricing for various shipping options on the current order.
  • Regional Free Shipping module — Gives the Magento administrator the option to allow free shipping by region, instead of by country. This provides a choice to the store administrator of breaking down free shipping further than country. For example, this would be good for someone who runs a store based in Nottingham that wants to reward local customers in the East Midlands, as opposed to simply giving free shipping to the entire United Kingdom.
  • Basic Store Pickup Shipping module — Enables customers to choose between picking up the item themselves and having it delivered to them. This is advantageous for companies which use Magento and have a physical store presence with stock held.

Magento Connect can be accessed at the following URL:http://www.magentocommerce.com/magento-connect.

The three core types of shipping module can be summarized in the following:

  • Third-party API and/or web service integration. For integration with existing couriers that have web-based APIs or web services that offer the same for organization of your shipping. Many existing services make an API available to us for integrating into Magento. We should check Magento Connect for any existing modules that others have created.
  • Using customer data to provide unique calculations and opportunities to certain users. Anything that the customer puts in it while checking out can be used for this type of module.
  • Shipping methods that involve a physical store or location for additional options that compliment others. We could theoretically build up a set of stores under the Magento store company's business. We could then link them up with local computers at the locations and use the shipping module to check for stocks at each location. We should do that before suggesting the store as a location for the user to be able to pick up the item.

How to begin with a shipping module

  • Here we'll be learning about how to begin with a shipping module. This is the skeletal structure of a shipping module that we can use as a template for any shipping module which we create. We will also be using it to create a very basic shipping module at the end of this article.
  • For the purpose of following this tutorial, we will be creating all files in /app/code/local/MagentoBook/ShippingModule/ , which will be the base directory for all files created (from this point onwards). We must make sure that this directory and sub-directory are set up before continuing onwards. This means that if the file is declared to be /hello/world.php, we place this on the end of our initial base address and it becomes /app/code/local/MagentoBook/ShippingModule/hello/world.php
  • Please start by creating the directory MagentoBook in /app/code/local/ and a sub-directory within that called ShippingModule, creating the directory structure /MagentoBook/ShippingModule/.

The configuration files

We create /app/code/local/MagentoBook/ShippingModule/etc/config.xml in our module's folder. Here, we'll place the following code which will declare our new module for use, make it depend on Mage_Shipping being enabled, set it at version 0.1.0 and allow it to use the existing global database connection which is set up for our store.

<?xml version="1.0"?>
<config>
<modules>
<MagentoBook_ShippingModule>
<version>0.1.0</version>
<depends>
<Mage_Shipping />
</depends>
</MagentoBook_ShippingModule>
</modules>

<global>
<models>
<shippingmodule>
<class>MagentoBook_ShippingModule_Model</class>
</shippingmodule>
</models>

<resources>
<shippingmodule_setup>
<setup>
<module>MagentoBook_ShippingModule</module>
</setup>
<connection>
<use>core_setup</use>
</connection>
</shippingmodule_setup>
</resources>
</global>
<default>
<carriers>
<shippingmodule>
<model>MagentoBook/carrier_ShippingModule</model>
</shippingmodule>
</carriers>
</default>
</config>

Let's walk back through this code and go over what each individual section does.

We start by defining our XML header tag for the file, to ensure that it is accepted as an XML file when read by the XML parsing class in the system.

<?xml version="1.0"?>

We define the <config> tag, to ensure that everything within it is read as configuration variables to be loaded into Magento's configuration for whatever we define internally within this tag.

<config>

We define the <modules> tag, so that we're setting configuration variables for modules defined within this tag.

<modules>
<MagentoBook_ShippingModule>

We set the module's version number to 0.1.0, to supply Magento with versioning for the module in the future, if we update and need to perform statements within the update portion of the module, so as to execute above a certain version number.

<version>0.1.0</version>

We have to make sure that our module cannot be activated, or possibly run, without the Mage_Shipping core shipping handler and module activated. This is vital because the module being a shipping module is simply going to cause fatal errors without the parent Mage_Shipping module providing the helper functions needed internally.

<depends>
<Mage_Shipping />
</depends>

Next, we close off our module declaration tag and modules tag.

 </MagentoBook_ShippingModule>
</modules>

We set up our <global> tag to define global assets to Magento.

<global>

Next, we define the <models> tag to define global models to the system and for setting up our module's default model to be one of those global models which is automatically loaded.

<models>
<shippingmodule>
<class>MagentoBook_ShippingModule_Model</class>
</shippingmodule>
</models>

Next, we define the <resources>tag, so that we can configure the database resources available to the module within the system.

<resources>

Defining the <resources> tag allows us to include a setup file with our module that accesses the database. This helps if we need to load in any variables (such as default table rate rules) for our module, or for loading additional data required locally by the module, when calculating the shipping rates.

<shippingmodule_setup>
<setup>
<module>MagentoBook_ShippingModule</module>
</setup>

Here, we'll use the core database connection (the default one), and ensure that we do not overwrite the database connection set up for this particular module.

<connection>
<use>core_setup</use>
</connection>

We close off all tag pairs, besides <config>, that have been opened at this point.

 </shippingmodule_setup>
</resources>
</global>

Finally, we end the configuration file with a declaration that our module is a shipping module and should be processed as one, within the system. This will register the module to the system, so that it can actually display shipping methods to the user on checkout. Without this, nothing will be returned to the user from this module.

<default>
<carriers>
<shippingmodule>
<model>MagentoBook/carrier_ShippingModule</model>
</shippingmodule>
</carriers>
</default>

We close the <config> tag to end the XML configuration file.

</config>

After we've done this, we need to declare our module to Magento by creating a configuration file in /app/etc/modules/MagentoBook_ShippingModule.xml.

Next, we place the following code in our new configuration file, to allow this module to interact with Magento and be turned on/off under the System Configuration menu:

<?xml version="1.0"?>
<config>
<modules>
<MagentoBook_ShippingModule>
<active>true</active>
<codePool>local</codePool>
</MagentoBook_ShippingModule>
</modules>
</config>

We break this file down into the individual lines:

<?xml version="1.0"?>

The <config> wrapper tag defines the XML to be read, as a configuration of something inside Magento.

<config>

The <modules> wrapping tag defines this as a module to Magento.

<modules>

The next tag is used for defining that this is the configuration of a module entitled <MagentoBook_ShippingModule> and for applying the settings inside the tag to the module:

<MagentoBook_ShippingModule>

We make sure that it's active by default (this will be overwritten when activated/deactivated in the Magento administrative back-end).

<active>true</active>

The <code pool> tag is used for keeping this module in our local module's directory.

<codePool>local</codePool>

Closing tags are for closing the XML tags that we started the <config> tag with.

 </MagentoBook_ShippingModule>
</modules>
</config>

Now that we have the configuration set up, to allow the module to be managed within Magento and versioning control to allow for upgrades in the future, we can progress onto the module itself. It also means that we can now turn our module on/off within the administration. To do this, we go to System|Configuration , then to Advanced under the Advanced heading on the left-hand side. Once here, we will be presented Enable/Disable dropdowns for each module installed in the system.

Magento 1.3: PHP Developer's Guide

We'll set the dropdown for our module to Disable until we have completed the adaptor model and administration setup. This will prevent the module from crashing the system, while it is incomplete. We will re-activate the module once we're ready to see the output.

Magento 1.3: PHP Developer's Guide Design, develop, and deploy feature-rich Magento online stores with PHP coding
Published: January 2010
eBook Price: ₨739.00
Book Price: ₨450.00
See more
Select your format and quantity:

The adaptor model

The adaptor model handles the core functionality behind our shipping module. From its name, we can guess that it adapts what we have into a real module that works and functions. This is something that both shipping and payment modules have.

This is where all the calculations happen and where everything will be coded. The coding is done behind the scenes to handle the shipping methods and the rates returned to the user to choose from in their checkout process.

Here we apply the name of our shipping method within our bare-bones template. For the sake of demonstration, we'll call ours BareBonesMethod in the code to follow. Our adaptor in this case will be placed in:/app/code/local/MagentoBook/ShippingModule/Model/Carrier/BaeBonesMethod.php

ShippingModule/Model/Carrier/BareBonesM ethod.php
<?php
class MagentoBook_ShippingModule_Model_Carrier_BareBonesMethod extends
Mage_Shipping_Model_Carrier_Abstract
{
protected $_code = 'shippingmodule';
public function collectRates(Mage_Shipping_Model_Rate_Request
$request)
{
if (!$this->getConfigData('active')) {
Mage::log('The '.$this->_code.' shipping method is not
active.');
return false;
}
$handling = $this->getConfigData('handling');
$result = Mage::getModel('shipping/rate_result');
foreach ($response as $method) {
$rMethod = Mage::getModel('shipping/rate_result_method');

$method->setCarrier($this->_code);
$method->setCarrierTitle($this->getConfigData('title));

$method->setMethod($method['code']);
$method->setMethodTitle($method['title']);

$method->setCost($method['amount']);

$method->setPrice($method['amount']+$handling);

$result->append($method);
}
return $result;
}
}

In this example, $response is the parsed array of an API call response to a third-party service and code, title, and amount are all values of the array resulting from the request. We'll go through this block by block, so that we're aware of the happenings at each stage:

We start by declaring our module and ensuring that it extends the shipping class of Magento. This tells Magento that the module is a shipping module.

<?php
class MagentoBook_ShippingModule_Model_Carrier_BareBonesMethod extends
Mage_Shipping_Model_Carrier_Abstract
{
protected $_code = 'shippingmodule';

We need to declare the standard collectRates function for Magento to call, when our shipping method is called.

public function collectRates(Mage_Shipping_Model_Rate_Request
$request)
{

We'll skip the rest if our module isn't enabled and log it to the Magento logs, so that we know it is being skipped.

 if (!$this->getConfigData('active')) {
Mage::log('The '.$this->_code.' shipping method is not
active.');
return false;
}

We want to retrieve our configured handling fee to be added later to the total fee for this shipping method.

$handling = $this->getConfigData('handling');

We grab our overall result that is being returned to Magento, with all available shipping modules and rates. We do that in case we need to add to it with any methods available with our module.

$result = Mage::getModel('shipping/rate_result');

$response in the code below is a theoretical example that we have returning from a third-party API, likely via SOAP or another method. This is not a set array here, but used as an example for adding multiple rates based on an array.

foreach ($response as $method) {

We prepare the new method that will be added.

$method = Mage::getModel('shipping/rate_result_method');

Next, we record our important internal system variables that Magento will use to store and refer to this shipping method.

$method->setCarrier($this->_code);
$method->setCarrierTitle($this->getConfigData('title));

Moving on, we add the method's code and title returned in our array to the new shipping method which will be returned to the user.

$method->setMethod($method['code']);
$method->setMethodTitle($method['title']);

We set the cost, again from the returned array we have. This is not returned to the user, but is used internally by the system to calculate profit (price – cost = profit).

$method->setCost($method['amount']);

We set the price for the shipping method and add our handling fee that we gathered earlier from the configured administration value.

$method->setPrice($method['amount']+$handling);

Next, we add the rate to the result which will be returned to the system.

 $result->append($method);
}

The result is returned to Magento for continuing processing onto the next shipping module installed in the system.

 return $result;
}
}

The administration setup

Now that we have an adaptor, we need to make it configurable within the system. We must do so for the Magento administrator to be able to do something constructive with what we've built. The administrator must be able to:

  • Enter personal details
  • Set up the handling rate
  • Set the cost of the shipping method that we put into the store

Our administration configuration file defines how our shipping module appears within the system configuration; which fields appear and what they relate to are defined here. Once defined, the Magento administrator is able to configure the module using these fields to get the desired result from the shipping module.

The file /app/code/local/MagentoBook/ShippingModule/etc/system.xml file contains all the administration fields for the shipping method, and will be formatted along the lines of the following code:

?xml version="1.0"?>
<config>
<sections>
<carriers>
<groups>
<shippingmodule translate="label" module="shipping">
<label>Bare Bones Shipping inc.</label>
<frontend_type>text</frontend_type>
<sort_order>13</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_sto <fields>
<active translate="label">
<label>Enabled</label>
<frontend_type>select</frontend_type>
<source_model>adminhtml/system_config_source_yesno</source_model>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</active>
<contentdesc translate="label">
<label>Package Description</label>
<frontend_type>text</frontend_type>
<sort_order>12</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</contentdesc>
{specific configurable fields listed here}
</fields>
</shippingmodule>
</groups>
</carriers>
</sections>
</config>

In this configuration file, we've simply set the options for whether or not the shipping method is enabled and for a field to describe the contents of our shipping method to the user checking out through the Magento checkout process. We will learn how these fields are formatted, so that we can add our own as we want. We will go through this in the next section.

Declaring further fields and learning how they're structured

A large number of fields are not included in system.xml, as they can be overwhelming without a thorough explanation. We'll pick and choose our fields from the below code and insert them between the <fields> </fields> tag as we go through the popular types of fields which can be used for the configuration of our module. Our fields are all built up in the same format, with the required options for each field being set out in the format below:

<account translate="label">
<label>Account number</label>
<frontend_type>text</frontend_type>
<sort_order>7</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</account>

Breaking it down, we start with the surrounding tags of <account translate="label"> </account>, which defines the configurable variable account and contains its configuration. The translate="label" is a reference to the <translate> tag that we defined earlier for translation of our module (for multi-language stores). The value inside the tag will act as a key in the language file when translating.

The <label> </label> tag pair contains the name of this configurable variable to be displayed within the administration. We try to make this short in most cases, with additional notes added where they are needed.

The <frontend_type>  </frontend_type> tag pair defines the type of field that will be shown on the frontend for the administrator configuring this shipping method. This should be set to one of the following:

  • text—For a text-input-based form element
  • select—For a select-dropdown form element
  • multiselect—For allowing the user to select multiple options from a list
  • textarea—For a textarea-input-based form element

<sort_order> </sort_order>  defines the order of the fields when they are output within the administration for the shipping method.

The final three variables for each field (that need to be defined) decide when the configurable variable should appear within the administration. Their values are always 1 or 0 to define yes or no. Here is a breakdown of the individual tags that explains to us what they do:

Tag pair

What they do

<show_in_default> </show_in_default>

Default Magento wide configuration

<show_in_website> </show_in_website>

Website wide configuration

<show_in_store> </show_in_store>

Store specific configuration

There is one additional option tag that is not required, but is important for certain types of fields. The <source_model>  < source_model > tag pair defines a source model which will populate options for a field. We consider the following as an example of this:

active translate="label">
<label>Enabled</label>
<frontend_type>select</frontend_type>
<source_model>adminhtml/system_config_source_yesno</source_model>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</active>

This particular source model adminhtml/system_config_source_yesno populates the select field with yes and no options for selection. The raw models for exploration of all the available included functions for the value of this option within your field can be found in: /app/code/core/Mage/Adminhtml/Model/System/Config/Source/.

For our adminhtml/system_config_source_yesno value, the file in question is Yesno.php within the same directory.

Here are a few more source models and what they produce in our module's administration for the user:

  • shipping/source_handlingType—Lists Magento handling types for shipping modules
  • shipping/source_handlingAction—Lists Magento handling actions for shipping modules
  • adminhtml/system_config_source_shipping_allspecificcountries—Prints out a list containing the two core options All allowed countries and Specific countries
  • adminhtml/system_config_source_country—Lists all countries in the system. It is usually used by means of multi-select lists for shipping modules and payment gateways to select the country that they should be applicable to

>> Continue Reading Shipping Modules in Magento: Part 2

 

[ 1 | 2 ]
If you have read this article you may be interested to view :
Magento 1.3: PHP Developer's Guide Design, develop, and deploy feature-rich Magento online stores with PHP coding
Published: January 2010
eBook Price: ₨739.00
Book Price: ₨450.00
See more
Select your format and quantity:

About the Author :


Jamie Huskisson

A passionate 23-year old freelance developer from Nottingham, Jamie Huskisson has been working with Magento for the past two years since the very early Beta versions. His development client list features names such as the NHS, Volkswagen, and Nike building everything from web applications to e-commerce stores and small business sites. He also trains groups of developers and provides consulting on adopting open source technologies over closed systems for clients when required.

Books From Packt

AJAX and PHP: Building Modern Web Applications 2nd Edition
AJAX and PHP: Building Modern Web Applications 2nd Edition

jQuery 1.3 with PHP
jQuery 1.3 with PHP

WordPress MU 2.8: Beginner's Guide
WordPress MU 2.8: Beginner's Guide

WordPress 2.8 Theme Design
WordPress 2.8 Theme Design

Python Testing: Beginner's Guide
Python Testing: Beginner's Guide

Building Telephony Systems with OpenSIPS 1.6
Building Telephony Systems with OpenSIPS 1.6

Joomla! with Flash
Joomla! with Flash

Moodle 1.9 Teaching Techniques
Moodle 1.9 Teaching Techniques

Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software