Create Shipping Method Module

Last modified by chicurel on Fri, August 10, 2012 09:17
Source|Old Revisions  

This is an old revision of the document!


Introduction

This tutorial is similar to Creation of Payment Method module, and differs the most in adapter model.

Each shipping method can be done as separate module or few methods can be combined in same module if they share functionality or could be used together.

Our new module will be called NewModule.

Replace all instances of ‘NewModule’ with name of your module and ‘newmodule’ with simplified code, that contains only alphanumeric characters and underscore.

Replace all instances of ‘YourCompany’ with your company name or whatever name you choose.

To make this tutorial most concise, it’s implied that mentioned folders will be created when needed.

Make sure that app/code/local is in PHP‘s include_path. To do so, execute the following code, either in a shell or inside a web-accessible PHP file:

  1. <?php echo get_include_path();?>

Make sure you put this code somewhere after Magento was loaded, at the bottom of index.php for example, because Magento might modify the include_path on its own to fit its needs and dynamically attribute locations.

If you are using configuration cache, don’t forget to clean it after modifying config xml files.

Configuration

Create app/code/local/YourCompany/NewModule/etc/config.xml:

  1. <?xml version="1.0"?>
  2. <config>
  3.   <modules>
  4. <!-- declare module's version information -->
  5.     <YourCompany_NewModule>
  6. <!-- this version number will be used for database upgrades -->
  7.       <version>0.1.0</version>
  8.     </YourCompany_NewModule>
  9.   </modules>
  10.  
  11.   <global>
  12. <!-- declare model group for new module -->
  13.     <models>
  14. <!-- model group alias to be used in Mage::getModel() -->
  15.       <newmodule>
  16. <!-- base class name for the model group -->
  17.         <class>YourCompany_NewModule_Model</class>
  18.       </newmodule>
  19.     </models>
  20.  
  21. <!-- declare resource setup for new module -->
  22.     <resources>
  23. <!-- resource identifier -->
  24.       <newmodule_setup>
  25. <!-- specify that this resource is a setup resource and used for upgrades -->
  26.         <setup>
  27. <!-- which module to look for install/upgrade files in -->
  28.           <module>YourCompany_NewModule</module>
  29.         </setup>
  30. <!-- specify database connection for this resource -->
  31.         <connection>
  32. <!-- do not create new connection, use predefined core setup connection -->
  33.           <use>core_setup</use>
  34.         </connection>
  35.       </newmodule_setup>
  36.     </resources>
  37.   </global>
  38. </config>

Create app/etc/modules/YourCompany_NewModule.xml:

  1. <config>
  2. <!-- ... -->
  3.   <modules>
  4. <!-- ... -->
  5. <!-- declare YourCompany_NewModule module -->
  6.     <YourCompany_NewModule>
  7.       <active>true</active>
  8.       <codePool>local</codePool>
  9.     </YourCompany_NewModule>
  10. <!-- ... -->
  11.   </modules>
  12. <!-- ... -->
  13. </config>

Note: using “<!– ... –>” could imply there is more to input here, but for newbies like me, this is confusing if there is actually nothing to input. Also, I have seen some modules with <depends> <Mage_Shipping /> </depends> within the <YourCompany_NewModule> section. Should this be suggested?

Now application is aware of the module, but nothing will happen until we’ll create model logic!

Adapter model

Note: ShippingMethod name is arbitrary and is up to your decision.

Create app/code/local/YourCompany/NewModule/Model/Carrier/ShippingMethod.php:

  1. <?php
  2.  
  3. /**
  4. * Our test shipping method module adapter
  5. */
  6. class YourCompany_NewModule_Model_Carrier_ShippingMethod extends Mage_Shipping_Model_Carrier_Abstract
  7. {
  8.   /**
  9.    * unique internal shipping method identifier
  10.    *
  11.    * @var string [a-z0-9_]
  12.    */
  13.   protected $_code = 'newmodule';
  14.  
  15.   /**
  16.    * Collect rates for this shipping method based on information in $request
  17.    *
  18.    * @param Mage_Shipping_Model_Rate_Request $data
  19.    * @return Mage_Shipping_Model_Rate_Result
  20.    */
  21.   public function collectRates(Mage_Shipping_Model_Rate_Request $request)
  22.   {
  23.     // skip if not enabled
  24.     if (!Mage::getStoreConfig('carriers/'.$this->_code.'/active')) {
  25.         return false;
  26.     }
  27.  
  28.     /**
  29.      * here we are retrieving shipping rates from external service
  30.      * or using internal logic to calculate the rate from $request
  31.      * you can see an example in Mage_Usa_Model_Shipping_Carrier_Ups::setRequest()
  32.      */
  33.  
  34.     // get necessary configuration values
  35.     $handling = Mage::getStoreConfig('carriers/'.$this->_code.'/handling');
  36.  
  37.     // this object will be returned as result of this method
  38.     // containing all the shipping rates of this method
  39.     $result = Mage::getModel('shipping/rate_result');
  40.  
  41.     // $response is an array that we have
  42.     foreach ($response as $rMethod) {
  43.       // create new instance of method rate
  44.       $method = Mage::getModel('shipping/rate_result_method');
  45.  
  46.       // record carrier information
  47.       $method->setCarrier($this->_code);
  48.       $method->setCarrierTitle(Mage::getStoreConfig('carriers/'.$this->_code.'/title'));
  49.  
  50.       // record method information
  51.       $method->setMethod($rMethod['code']);
  52.       $method->setMethodTitle($rMethod['title']);
  53.  
  54.       // rate cost is optional property to record how much it costs to vendor to ship
  55.       $method->setCost($rMethod['amount']);
  56.  
  57.       // in our example handling is fixed amount that is added to cost
  58.       // to receive price the customer will pay for shipping method.
  59.       // it could be as well percentage:
  60.       /// $method->setPrice($rMethod['amount']*$handling/100);
  61.       $method->setPrice($rMethod['amount']+$handling);
  62.  
  63.       // add this rate to the result
  64.       $result->append($method);
  65.     }
  66.  
  67.     return $result;
  68.   }
  69.  
  70.   /**
  71.    * This method is used when viewing / listing Shipping Methods with Codes programmatically
  72.    */
  73.   public function getAllowedMethods() {
  74.     return array($this->_code => $this->getConfigData('name'));
  75.   }
  76. }

Now that we have the model let’s give admin a way to configure it and also make checkout process aware of this method.

Admin Configuration Implementation

In this step, we need to tell Magento how to display our module in the Configuration section of the administrative panel. In order to do so, we must create app/code/local/YourCompany/NewModule/etc/system.xml and make it look something like this

  1. <?xml version="1.0"?>
  2. <config>
  3.    <sections>
  4.     <carriers>
  5.         <groups>
  6.             <newmodule translate="label" module="shipping">
  7.                 <label>Carrier Name</label>
  8.                 <frontend_type>text</frontend_type>
  9.                 <sort_order>13</sort_order>
  10.                 <show_in_default>1</show_in_default>
  11.                 <show_in_website>1</show_in_website>
  12.                 <show_in_store>1</show_in_store>
  13.                    <fields>
  14.                       <account translate="label">
  15.                             <label>Account number</label>
  16.                             <frontend_type>text</frontend_type>
  17.                             <sort_order>7</sort_order>
  18.                             <show_in_default>1</show_in_default>
  19.                             <show_in_website>1</show_in_website>
  20.                             <show_in_store>1</show_in_store>
  21.                         </account>
  22.                         <active translate="label">
  23.                             <label>Enabled</label>
  24.                             <frontend_type>select</frontend_type>
  25.                             <source_model>adminhtml/system_config_source_yesno</source_model>
  26.                             <sort_order>1</sort_order>
  27.                             <show_in_default>1</show_in_default>
  28.                             <show_in_website>1</show_in_website>
  29.                             <show_in_store>1</show_in_store>
  30.                         </active>
  31.                         <contentdesc translate="label">
  32.                             <label>Package Description</label>
  33.                             <frontend_type>text</frontend_type>
  34.                             <sort_order>12</sort_order>
  35.                             <show_in_default>1</show_in_default>
  36.                             <show_in_website>1</show_in_website>
  37.                             <show_in_store>1</show_in_store>
  38.                         </contentdesc>
  39.                         <!--
  40.                         If the free_shipping_enable flag enable, the system will check free_shipping_subtotal to give free shipping
  41.                         otherwise will use shopping cart price rule behaviour
  42.                         -->
  43.                         <free_shipping_enable translate="label">
  44.                             <label>Free shipping with minimum order amount</label>
  45.                             <frontend_type>select</frontend_type>
  46.                             <source_model>adminhtml/system_config_source_enabledisable</source_model>
  47.                             <sort_order>21</sort_order>
  48.                             <show_in_default>1</show_in_default>
  49.                             <show_in_website>1</show_in_website>
  50.                             <show_in_store>1</show_in_store>
  51.                         </free_shipping_enable>
  52.                         <free_shipping_subtotal translate="label">
  53.                             <label>Minimum order amount for free shipping</label>
  54.                             <frontend_type>text</frontend_type>
  55.                             <sort_order>22</sort_order>
  56.                             <show_in_default>1</show_in_default>
  57.                             <show_in_website>1</show_in_website>
  58.                             <show_in_store>1</show_in_store>
  59.                         </free_shipping_subtotal>
  60.                         <dutiable translate="label">
  61.                             <label>Shipment Dutiable</label>
  62.                             <frontend_type>select</frontend_type>
  63.                             <source_model>adminhtml/system_config_source_yesno</source_model>
  64.                             <sort_order>13</sort_order>
  65.                             <show_in_default>1</show_in_default>
  66.                             <show_in_website>1</show_in_website>
  67.                             <show_in_store>1</show_in_store>
  68.                         </dutiable>
  69.                         <gateway_url translate="label">
  70.                             <label>Gateway URL</label>
  71.                             <frontend_type>text</frontend_type>
  72.                             <sort_order>2</sort_order>
  73.                             <show_in_default>1</show_in_default>
  74.                             <show_in_website>1</show_in_website>
  75.                             <show_in_store>1</show_in_store>
  76.                         </gateway_url>
  77.                         <handling_type translate="label">
  78.                             <label>Calculate Handling Fee</label>
  79.                             <frontend_type>select</frontend_type>
  80.                             <source_model>shipping/source_handlingType</source_model>
  81.                             <sort_order>10</sort_order>
  82.                             <show_in_default>1</show_in_default>
  83.                             <show_in_website>1</show_in_website>
  84.                             <show_in_store>0</show_in_store>
  85.                         </handling_type>
  86.                         <handling_action translate="label">
  87.                             <label>Handling Applied</label>
  88.                             <frontend_type>select</frontend_type>
  89.                             <source_model>shipping/source_handlingAction</source_model>
  90.                             <sort_order>11</sort_order>
  91.                             <show_in_default>1</show_in_default>
  92.                             <show_in_website>1</show_in_website>
  93.                             <show_in_store>0</show_in_store>
  94.                         </handling_action>
  95.                         <handling_fee translate="label">
  96.                             <label>Handling fee</label>
  97.                             <frontend_type>text</frontend_type>
  98.                             <sort_order>12</sort_order>
  99.                             <show_in_default>1</show_in_default>
  100.                             <show_in_website>1</show_in_website>
  101.                             <show_in_store>1</show_in_store>
  102.                         </handling_fee>
  103.                         <max_package_weight translate="label">
  104.                             <label>Maximum Package Weight (Please consult your shipping carrier for maximum supported shipping weight)</label>
  105.                             <frontend_type>text</frontend_type>
  106.                             <sort_order>13</sort_order>
  107.                             <show_in_default>1</show_in_default>
  108.                             <show_in_website>1</show_in_website>
  109.                             <show_in_store>1</show_in_store>
  110.                         </max_package_weight>
  111.                         <id translate="label">
  112.                             <label>Access ID</label>
  113.                             <frontend_type>text</frontend_type>
  114.                             <backend_model>adminhtml/system_config_backend_encrypted</backend_model>
  115.                             <sort_order>5</sort_order>
  116.                             <show_in_default>1</show_in_default>
  117.                             <show_in_website>1</show_in_website>
  118.                             <show_in_store>1</show_in_store>
  119.                         </id>
  120.                         <password translate="label">
  121.                             <label>Password</label>
  122.                             <frontend_type>text</frontend_type>
  123.                             <backend_model>adminhtml/system_config_backend_encrypted</backend_model>
  124.                             <sort_order>6</sort_order>
  125.                             <show_in_default>1</show_in_default>
  126.                             <show_in_website>1</show_in_website>
  127.                             <show_in_store>1</show_in_store>
  128.                         </password>
  129.                         <shipping_intlkey translate="label">
  130.                             <label>Shipping key (International)</label>
  131.                             <frontend_type>text</frontend_type>
  132.                             <backend_model>adminhtml/system_config_backend_encrypted</backend_model>
  133.                             <sort_order>8</sort_order>
  134.                             <show_in_default>1</show_in_default>
  135.                             <show_in_website>1</show_in_website>
  136.                             <show_in_store>1</show_in_store>
  137.                         </shipping_intlkey>
  138.                         <shipping_key translate="label">
  139.                             <label>Shipping key</label>
  140.                             <frontend_type>text</frontend_type>
  141.                             <backend_model>adminhtml/system_config_backend_encrypted</backend_model>
  142.                             <sort_order>8</sort_order>
  143.                             <show_in_default>1</show_in_default>
  144.                             <show_in_website>1</show_in_website>
  145.                             <show_in_store>1</show_in_store>
  146.                         </shipping_key>
  147.                         <sort_order translate="label">
  148.                             <label>Sort order</label>
  149.                             <frontend_type>text</frontend_type>
  150.                             <sort_order>100</sort_order>
  151.                             <show_in_default>1</show_in_default>
  152.                             <show_in_website>1</show_in_website>
  153.                             <show_in_store>1</show_in_store>
  154.                         </sort_order>
  155.                         <title translate="label">
  156.                             <label>Title</label>
  157.                             <frontend_type>text</frontend_type>
  158.                             <sort_order>2</sort_order>
  159.                             <show_in_default>1</show_in_default>
  160.                             <show_in_website>1</show_in_website>
  161.                             <show_in_store>1</show_in_store>
  162.                         </title>
  163.                         <sallowspecific translate="label">
  164.                             <label>Ship to applicable countries</label>
  165.                             <frontend_type>select</frontend_type>
  166.                             <sort_order>90</sort_order>
  167.                             <frontend_class>shipping-applicable-country</frontend_class>
  168.                             <source_model>adminhtml/system_config_source_shipping_allspecificcountries</source_model>
  169.                             <show_in_default>1</show_in_default>
  170.                             <show_in_website>1</show_in_website>
  171.                             <show_in_store>1</show_in_store>
  172.                         </sallowspecific>
  173.                         <specificcountry translate="label">
  174.                             <label>Ship to Specific countries</label>
  175.                             <frontend_type>multiselect</frontend_type>
  176.                             <sort_order>91</sort_order>
  177.                             <source_model>adminhtml/system_config_source_country</source_model>
  178.                             <show_in_default>1</show_in_default>
  179.                             <show_in_website>1</show_in_website>
  180.                             <show_in_store>1</show_in_store>
  181.                         </specificcountry>
  182.                         <showmethod translate="label">
  183.                             <label>Show method if not applicable</label>
  184.                             <frontend_type>select</frontend_type>
  185.                             <sort_order>92</sort_order>
  186.                             <source_model>adminhtml/system_config_source_yesno</source_model>
  187.                             <show_in_default>1</show_in_default>
  188.                             <show_in_website>1</show_in_website>
  189.                             <show_in_store>1</show_in_store>
  190.                         </showmethod>
  191.                         <specificerrmsg translate="label">
  192.                             <label>Displayed Error Message</label>
  193.                             <frontend_type>textarea</frontend_type>
  194.                             <sort_order>80</sort_order>
  195.                             <show_in_default>1</show_in_default>
  196.                             <show_in_website>1</show_in_website>
  197.                             <show_in_store>1</show_in_store>
  198.                         </specificerrmsg>
  199.                     </fields>
  200.                 </newmodule>
  201.             </groups>
  202.         </carriers>
  203.     </sections>
  204. </config>

You should now see your module in the Administration under “System” > “Configuration” > “Shipping Methods”. It’s now up to you to add your custom fields in the <fields> tag, and subsequently make your configuration do something constructive.

Common Problems

Here is a list of things that have happened to others while trying to implement thier own Shipping Module. (Please add to this list or provide responses to unresolved issues if you can. A collection of common problems and how to avoid them can only help everybody.)

Module won’t activate

Relating to the importance of casing, be sure the CompanyName you use has an initial cap letter - a lowercase initial letter will prevent this from activating. Magento really needs to have clear documentation for these norms.

This code doesn’t work on 1.4.1.1

In adminhtml all work. But model class doesn’t load. How to tell Magento in config.xml, system.xml or anywhere else to load this model class?

Module doesn't appear in frontend.

I’ve just managed to get this to work, with a bit of hacking. I had created a method following the instructions above, but couldn’t get it it give me a quote on the front end. The problem was in app/core/Mage/Shipping/Model/Shipping.php, line 164:

$className = Mage::getStoreConfig('carriers/'.$carrierCode.'/model', $storeId);

The module didn’t have a ‘model’ defined for it, so the getCarrierByCode() method was returning false straight away. The hack involved creating a new field in the system.xml file:

<model translate="label">
  <label>Model</label>
  <frontend_type>text</frontend_type>
  <sort_order>900</sort_order>
  <show_in_default>1</show_in_default>
  <show_in_website>1</show_in_website>
</model>

Then, using the admin panel, I gave this a value of ‘newmodule/carrier_newmodule’. While I was there I also created a ‘name’ field to give the method a name.

After doing that, the method was appearing in my list of quotes! — David Edwards 2008/07/28 10:26

I found another solution: insert the following code into config.xml right below the config -tag:

    <default>
        <carriers>
            <mage_newmodule>
                    <active>1</active>
                    <sallowspecific>0</sallowspecific>
<model>newmodule/carrier_newmodule</model>
                    <name>New Module</name>
                    <title>New Module</title>
                    <specificerrmsg>
                        This shipping method is currently unavailable.
                        If you would like to ship using this shipping
                        method, please contact us.
                    </specificerrmsg>
                    <handling_type>F</handling_type>
            </mage_newmodule>
        </carriers>
    </default>

office@blu-ray-onlineshop.at 2008/09/24

Module doesn't appear in admin.

Check to make sure that you have the system.xml and config.xml files in the suggested directory structure. Capitalization appears to be important. Be careful not to use “locale” where you meant to use “local”.

Backend shows errormessage when displaying the shippingmethod

Make sure that the content in every <source_model> - tag has no line-break.

Correct:

<source_model>adminhtml/system_config_source_yesno</source_model>

Incorrect:

<source_model>
                adminhtml/system_config_source_yesno
</source_model>

I get this error: -

Notice: Undefined variable: response in /var/www/vhosts/dev.theironmanstore.com/httpdocs/app/code/local/Auburn/TNTpricing/Model/Carrier/ShippingMethod.php on line 37

which happens to be this line : " foreach ($response as $rMethod) {

any ideas?

Please, can you describe where exactly should I change the name from NewModel to Newmodel for to make this work in 1.4.1.1?

For about two years does anybody find this solution? This code does not work with magento 1.4.1.1 maybe this fact should be mentioned.

Hi, i got the same error “undefine variable response”. Does anyone know the solution for this?

Comment

by tariqc

Looks like a line is missing that should have initialized $response

foreach ($response as $rMethod) {

or maybe $response should be the $result array?

guyzooi@hotmail.com 2012/02/29

Hey It is clear! : “$response is an array that we have” ;) lol

I think that this is considering that the response of a shipping service may return multiple methods. For example, the same service should return different rates, as ‘express shipping’, ‘3 days shipping’, etc. So, the $response variable is the result of the service call. But, if we want to return only one method with a simple rate, I think we can obviate the foreach method and considere only the main values to set the response, that I think that are these:

 $result = Mage::getModel('shipping/rate_result');
 $rate = Mage::getModel('shipping/rate_result_method');
 $rate->setCarrier($this->_code);
 $rate->setCarrierTitle($this->getConfigData('title'));
 $rate->setMethod('yourmethod'); 
 $rate->setMethodTitle('your method title');
 $rate->setCost($thecost); 
 $rate->setPrice($theprice); //You should calculate this or obtain in a service 
 $result->append($rate);

dchicurel@gmail.com 2012/08/10




 

Magento 2 GitHub Repository

Magento Job Board - Some sort of tag line goes here

Latest Posts| View all Jobs