Create Shipping Method Module
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:
-
<?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
:
-
<?xml version="1.0"?>
-
<config>
-
<modules>
-
<!-- declare module's version information -->
-
<YourCompany_NewModule>
-
<!-- this version number will be used for database upgrades -->
-
<version>0.1.0</version>
-
</YourCompany_NewModule>
-
</modules>
-
-
<global>
-
<!-- declare model group for new module -->
-
<models>
-
<!-- model group alias to be used in Mage::getModel() -->
-
<newmodule>
-
<!-- base class name for the model group -->
-
<class>YourCompany_NewModule_Model</class>
-
</newmodule>
-
</models>
-
-
<!-- declare resource setup for new module -->
-
<resources>
-
<!-- resource identifier -->
-
<newmodule_setup>
-
<!-- specify that this resource is a setup resource and used for upgrades -->
-
<setup>
-
<!-- which module to look for install/upgrade files in -->
-
<module>YourCompany_NewModule</module>
-
</setup>
-
<!-- specify database connection for this resource -->
-
<connection>
-
<!-- do not create new connection, use predefined core setup connection -->
-
<use>core_setup</use>
-
</connection>
-
</newmodule_setup>
-
</resources>
-
</global>
-
</config>
Edit app/etc/modules/YourCompany_NewModule.xml
:
-
<config>
-
<!-- ... -->
-
<modules>
-
<!-- ... -->
-
<!-- declare YourCompany_NewModule module -->
-
<YourCompany_NewModule>
-
<active>true</active>
-
<codePool>local</codePool>
-
</YourCompany_NewModule>
-
<!-- ... -->
-
</modules>
-
<!-- ... -->
-
</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
:
-
<?php
-
-
/**
-
* Our test shipping method module adapter
-
*/
-
class YourCompany_NewModule_Model_Carrier_ShippingMethod extends Mage_Shipping_Model_Carrier_Abstract
-
{
-
/**
-
* unique internal shipping method identifier
-
*
-
* @var string [a-z0-9_]
-
*/
-
protected $_code = 'newmodule';
-
-
/**
-
* Collect rates for this shipping method based on information in $request
-
*
-
* @param Mage_Shipping_Model_Rate_Request $data
-
* @return Mage_Shipping_Model_Rate_Result
-
*/
-
public function collectRates(Mage_Shipping_Model_Rate_Request $request)
-
{
-
// skip if not enabled
-
if (!Mage::getStoreConfig('carriers/'.$this->_code.'/active')) {
-
return false;
-
}
-
-
/**
-
* here we are retrieving shipping rates from external service
-
* or using internal logic to calculate the rate from $request
-
* you can see an example in Mage_Usa_Model_Shipping_Carrier_Ups::setRequest()
-
*/
-
-
// get necessary configuration values
-
$handling = Mage::getStoreConfig('carriers/'.$this->_code.'/handling');
-
-
// this object will be returned as result of this method
-
// containing all the shipping rates of this method
-
$result = Mage::getModel('shipping/rate_result');
-
-
// $response is an array that we have
-
foreach ($response as $rMethod) {
-
// create new instance of method rate
-
$method = Mage::getModel('shipping/rate_result_method');
-
-
// record carrier information
-
$method->setCarrier($this->_code);
-
$method->setCarrierTitle(Mage::getStoreConfig('carriers/'.$this->_code.'/title'));
-
-
// record method information
-
$method->setMethod($rMethod['code']);
-
$method->setMethodTitle($rMethod['title']);
-
-
// rate cost is optional property to record how much it costs to vendor to ship
-
$method->setCost($rMethod['amount']);
-
-
// in our example handling is fixed amount that is added to cost
-
// to receive price the customer will pay for shipping method.
-
// it could be as well percentage:
-
/// $method->setPrice($rMethod['amount']*$handling/100);
-
$method->setPrice($rMethod['amount']+$handling);
-
-
// add this rate to the result
-
$result->append($method);
-
}
-
-
return $result;
-
}
-
}
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
-
<?xml version="1.0"?>
-
<config>
-
<sections>
-
<carriers>
-
<groups>
-
<newmodule translate="label" module="shipping">
-
<label>Carrier Name</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_store>
-
<fields>
-
<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>
-
<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>
-
<!--
-
If the free_shipping_enable flag enable, the system will check free_shipping_subtotal to give free shipping
-
otherwise will use shopping cart price rule behaviour
-
-->
-
<free_shipping_enable translate="label">
-
<label>Free shipping with minimum order amount</label>
-
<frontend_type>select</frontend_type>
-
<source_model>adminhtml/system_config_source_enabledisable</source_model>
-
<sort_order>21</sort_order>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</free_shipping_enable>
-
<free_shipping_subtotal translate="label">
-
<label>Minimum order amount for free shipping</label>
-
<frontend_type>text</frontend_type>
-
<sort_order>22</sort_order>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</free_shipping_subtotal>
-
<dutiable translate="label">
-
<label>Shipment Dutiable</label>
-
<frontend_type>select</frontend_type>
-
<source_model>adminhtml/system_config_source_yesno</source_model>
-
<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_store>
-
</dutiable>
-
<gateway_url translate="label">
-
<label>Gateway URL</label>
-
<frontend_type>text</frontend_type>
-
<sort_order>2</sort_order>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</gateway_url>
-
<handling_type translate="label">
-
<label>Calculate Handling Fee</label>
-
<frontend_type>select</frontend_type>
-
<source_model>shipping/source_handlingType</source_model>
-
<sort_order>10</sort_order>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>0</show_in_store>
-
</handling_type>
-
<handling_action translate="label">
-
<label>Handling Applied</label>
-
<frontend_type>select</frontend_type>
-
<source_model>shipping/source_handlingAction</source_model>
-
<sort_order>11</sort_order>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>0</show_in_store>
-
</handling_action>
-
<handling_fee translate="label">
-
<label>Handling fee</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>
-
</handling_fee>
-
<max_package_weight translate="label">
-
<label>Maximum Package Weight (Please consult your shipping carrier for maximum supported shipping weight)</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_store>
-
</max_package_weight>
-
<id translate="label">
-
<label>Access ID</label>
-
<frontend_type>text</frontend_type>
-
<backend_model>adminhtml/system_config_backend_encrypted</backend_model>
-
<sort_order>5</sort_order>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</id>
-
<password translate="label">
-
<label>Password</label>
-
<frontend_type>text</frontend_type>
-
<backend_model>adminhtml/system_config_backend_encrypted</backend_model>
-
<sort_order>6</sort_order>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</password>
-
<shipping_intlkey translate="label">
-
<label>Shipping key (International)</label>
-
<frontend_type>text</frontend_type>
-
<backend_model>adminhtml/system_config_backend_encrypted</backend_model>
-
<sort_order>8</sort_order>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</shipping_intlkey>
-
<shipping_key translate="label">
-
<label>Shipping key</label>
-
<frontend_type>text</frontend_type>
-
<backend_model>adminhtml/system_config_backend_encrypted</backend_model>
-
<sort_order>8</sort_order>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</shipping_key>
-
<sort_order translate="label">
-
<label>Sort order</label>
-
<frontend_type>text</frontend_type>
-
<sort_order>100</sort_order>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</sort_order>
-
<title translate="label">
-
<label>Title</label>
-
<frontend_type>text</frontend_type>
-
<sort_order>2</sort_order>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</title>
-
<sallowspecific translate="label">
-
<label>Ship to applicable countries</label>
-
<frontend_type>select</frontend_type>
-
<sort_order>90</sort_order>
-
<frontend_class>shipping-applicable-country</frontend_class>
-
<source_model>adminhtml/system_config_source_shipping_allspecificcountries</source_model>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</sallowspecific>
-
<specificcountry translate="label">
-
<label>Ship to Specific countries</label>
-
<frontend_type>multiselect</frontend_type>
-
<sort_order>91</sort_order>
-
<source_model>adminhtml/system_config_source_country</source_model>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</specificcountry>
-
<showmethod translate="label">
-
<label>Show method if not applicable</label>
-
<frontend_type>select</frontend_type>
-
<sort_order>92</sort_order>
-
<source_model>adminhtml/system_config_source_yesno</source_model>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</showmethod>
-
<specificerrmsg translate="label">
-
<label>Displayed Error Message</label>
-
<frontend_type>textarea</frontend_type>
-
<sort_order>80</sort_order>
-
<show_in_default>1</show_in_default>
-
<show_in_website>1</show_in_website>
-
<show_in_store>1</show_in_store>
-
</specificerrmsg>
-
</fields>
-
</newmodule>
-
</groups>
-
</carriers>
-
</sections>
-
</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.
from:http://www.magentocommerce.com/wiki/5_-_modules_and_development/shipping/create-shipping-method-module