Today, we’ll show you how to create a module for the shipping service. The main peculiarity is that such module should be inherited from the abstract class CarrierModule and should implement the following 2 methods: «getOrderShippingCost», «getOrderShippingCostExternal»:
1 2 3 4 5 |
abstract class CarrierModuleCore extends Module { abstract public function getOrderShippingCost($params, $shipping_cost); abstract public function getOrderShippingCostExternal($params); } |
These methods are required to calculate shipping costs. We will create a shipping module to better understand all the nuances. Let’s begin:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public function install() { if (parent::install()) { foreach ($this->_hooks as $hook) { if (!$this->registerHook($hook)) { return FALSE; } } if (!$this->createCarriers()) { //function for creating new currier return FALSE; } return TRUE; } return FALSE; } |
Here we use the standard constructor, and we are going to use only one hook “асtiоnCаrrierUpdаte”. This hook is required to ensure that the module will not lose connection with the carrier, created by the module. The thing is that a carrier is given a new ID each time it is edited through the admin panel. Users do not notice this, but for the program this is very important, because ID serves as a unique identifier, which we can use to find the necessary carrier at any time.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class belvg_studyshipping extends CarrierModule { const PREFIX = 'belvg_studyshipping_'; protected $_hooks = array( 'actionCarrierUpdate', //For control change of the carrier's ID (id_carrier), the module must use the updateCarrier hook. ); protected $_carriers = array( //"Public carrier name" => "technical name", 'My new carrier' => 'belvgstudy', ); public function __construct() { $this->name = 'belvg_studyshipping'; $this->tab = 'shipping_logistics'; $this->version = '1.6.1'; $this->author = 'BelVG'; $this->bootstrap = TRUE; parent::__construct(); $this->displayName = $this->l('Belvg Shipping'); $this->description = $this->l('How to create shipping module.'); } |
When installing the module we also create a carrier and assign it to the module. This way the carrier will be receiving the shipping costs not from a static database, but dynamically, perhaps, by using a third-party API. It is important to keep the ID and reference of the carrier, because we are going to identify the carrier exactly by that field when the ID changes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
protected function createCarriers() { foreach ($this->_carriers as $key => $value) { //Create new carrier $carrier = new Carrier(); $carrier->name = $key; $carrier->active = TRUE; $carrier->deleted = 0; $carrier->shipping_handling = FALSE; $carrier->range_behavior = 0; $carrier->delay[Configuration::get('PS_LANG_DEFAULT')] = $key; $carrier->shipping_external = TRUE; $carrier->is_module = TRUE; $carrier->external_module_name = $this->name; $carrier->need_range = TRUE; if ($carrier->add()) { $groups = Group::getGroups(true); foreach ($groups as $group) { Db::getInstance()->autoExecute(_DB_PREFIX_ . 'carrier_group', array( 'id_carrier' => (int) $carrier->id, 'id_group' => (int) $group['id_group'] ), 'INSERT'); } $rangePrice = new RangePrice(); $rangePrice->id_carrier = $carrier->id; $rangePrice->delimiter1 = '0'; $rangePrice->delimiter2 = '1000000'; $rangePrice->add(); $rangeWeight = new RangeWeight(); $rangeWeight->id_carrier = $carrier->id; $rangeWeight->delimiter1 = '0'; $rangeWeight->delimiter2 = '1000000'; $rangeWeight->add(); $zones = Zone::getZones(true); foreach ($zones as $z) { Db::getInstance()->autoExecute(_DB_PREFIX_ . 'carrier_zone', array('id_carrier' => (int) $carrier->id, 'id_zone' => (int) $z['id_zone']), 'INSERT'); Db::getInstance()->autoExecuteWithNullValues(_DB_PREFIX_ . 'delivery', array('id_carrier' => $carrier->id, 'id_range_price' => (int) $rangePrice->id, 'id_range_weight' => NULL, 'id_zone' => (int) $z['id_zone'], 'price' => '0'), 'INSERT'); Db::getInstance()->autoExecuteWithNullValues(_DB_PREFIX_ . 'delivery', array('id_carrier' => $carrier->id, 'id_range_price' => NULL, 'id_range_weight' => (int) $rangeWeight->id, 'id_zone' => (int) $z['id_zone'], 'price' => '0'), 'INSERT'); } copy(dirname(__FILE__) . '/views/img/' . $value . '.jpg', _PS_SHIP_IMG_DIR_ . '/' . (int) $carrier->id . '.jpg'); //assign carrier logo Configuration::updateValue(self::PREFIX . $value, $carrier->id); Configuration::updateValue(self::PREFIX . $value . '_reference', $carrier->id); } } return TRUE; } |
When removing the module also delete the carrier.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
protected function deleteCarriers() { foreach ($this->_carriers as $value) { $tmp_carrier_id = Configuration::get(self::PREFIX . $value); $carrier = new Carrier($tmp_carrier_id); $carrier->delete(); } return TRUE; } public function uninstall() { if (parent::uninstall()) { foreach ($this->_hooks as $hook) { if (!$this->unregisterHook($hook)) { return FALSE; } } if (!$this->deleteCarriers()) { return FALSE; } return TRUE; } return FALSE; } |
Implementing the functions of the abstract class CarrierModule. We are not going to focus attention on any logic for dynamic calculation of the cost, but will just return the amount of 777.
1 2 3 4 5 6 7 8 9 |
public function getOrderShippingCost($params, $shipping_cost) { return 777; } public function getOrderShippingCostExternal($params) { return $this->getOrderShippingCost($params, 0); } |
The hook «ActionCarrierUpdate» keeps the reference of the original carrier.
1 2 3 4 5 6 |
public function hookActionCarrierUpdate($params) { if ($params['carrier']->id_reference == Configuration::get(self::PREFIX . 'swipbox_reference')) { Configuration::updateValue(self::PREFIX . 'swipbox', $params['carrier']->id); } } |
So, this is the entire module. When developing such a module the main part of the work takes to receive data via API and to develop the logic for calculating the cost of delivery.
Check out our Prestashop Modules.
Hi Feroce
Unfortunately, this article is relevant for PrestaShop 1.6 version. We will do our best to update it for PrestaShop 1.7 as soon as possible. Subscribe and stay turned :)
Hi Roberto
thank you!
If you want to override price that 3rd party carriers return or price of the carriers that was created in admin you will need to override the logic of the Carrier class: https://github.com/PrestaShop/PrestaShop/blob/develop/classes/Carrier.php (or other class, depends on 3rd party module)
Great tutorial!
You said “When installing the module we also create a carrier and assign it to the module” so we can modify the price using the getOrderShippingCost method but would be possible to edit other carriers not created by the module?
Let’s say when someone install my module there are already 3 carriers configured in PrestaShop and I’d like to modify those as well, so far I can only modify the ones that has been created from the module
thanks!
Hi,
I’m new to Prestashop and your code help us a lot. But I’m on Prestashop 1.7 and it doesn’t work. After struglling a lot I discover the way you INSERT data in the DB seems not to more available.
So all the Db::getInstance() fail.
I change them by thing like that:
$tmp = “INSERT INTO “._DB_PREFIX_.”carrier_group (id_carrier,id_group) VALUES (“.$carrier->id.”,”.$group[‘id_group’].”)”;
Db::getInstance()->execute($tmp);
and now it’s OK.
Thanks a lot
Hi, Developer, thanks for your question.
For helping you in this case, our specialists need to see you site itself. You can drop us an email at [email protected]. My colleagues from the support department will be happy to help you.
i have added some code after carrier list. and create new carrier related to it.
My aim is there extra code would be show when i click created new carrier.
thanks..
Hi Alfonso
Thanks for your feedback, we appreciate it!
wow its perfect !!! worked for me, great tutorial thanks for sharing
Hi,
unfortunately, we don’t provide any downloadable extension currently, as the article is pretty old and we don’t update it anymore.
In case you need any customized solution feel free to contact us via email [email protected].
Hello,
Where we can download the module?
Thanks Alex,
I finally know how to retrieve the order total.
by using:
$this->context->cart->getOrderTotal(true, Cart::ONLY_PHYSICAL_PRODUCTS_WITHOUT_SHIPPING, $product_list);
Hi Alex,
yes, i think getOrderTatal() is the method i need.
now i am just trying to call the method and return the Order Total but always run into error.
the file: belvg_freightdelivery.php
public function getOrderShippingCost($params, $shipping_cost)
{
return $this->context->cart->getOrderTotal();
}
before calling the getOrderTotal method, do i need to define the path or include any files ?
thanks
Hi, Jeff,
you need to take a look at the Cart.php class to find the appropriate method.
I guess you are looking for this method: github.com
You can use cart object from context object, for example:
$this->context->cart->getOrderTotal()
orContext::getContext()->cart->getOrderTotal()
Regards,
Alex
What is the variable for total order amount?
i wanna calculate the shipping by order amount and weight. i need to know how to get the total amount.
Hello Max,
frankly speaking, I haven’t checked. However, I’m about 80% sure that it will work for Presta 1.7 :)
When you created the module, share your method, please.
Regards,
Alex
Any thoughts of updating this page for 1.7 or will it work for this as well?
Hi Juan,
please contact our support department to order the review of the code.
[email protected]
Hi, i am just a beginner and i try to create my own carrier module. So far its cool but i stack at this point. I know i can return any integer at “public function getOrderShippingCost($params, $shipping_cost)” as my shipping price. My problem is i have 3 carrier and i want a different cost each carrier. Here my full code:
< ...>
It will be good if someone can help me. Thanks for your great tutorial!
i also have same problems
Hi Michaël,
To get the answers to your questions, please get in touch with our Support Team: [email protected]
Do you know if exist a module for Fedex V2 webservice and for prestashop v1.6.1.7
Hello Alex, I download you module and juste install in my new prestashop 1.6.1.7.
In the admin, i see the carrier but in the front office part on the shipping step, the carrier it’s not propose ….
Have you an idea ? I need to configure something ?
You see a resume of my carrier config:
This carrier is not free and the delivery announced is: Depends on the freight company [1-2 days].
The shipping cost is calculated according to the weight and the tax rule No tax will be applied.
This carrier can deliver orders from 0.000000 KGS to 1000000.000000 KGS. If the order is out of range, the behavior is to apply the cost of the highest defined range.
This carrier will be proposed for those delivery zones
Africa
Asia
Central America/Antilla
Europe
Europe (non-EU)
North America
Oceania
South America
And it will be proposed for those client groups
Visitor
Guest
Customer
Tarif2
BojanLearning
Still more questions than answers.
For example, this page babynabor.com/carrier.html I want to show what I need.
So, I have a widget from an external site, which calculates the shipping cost depending on city. City of delivery is selected in the same widget at the time of order. I was able to embed the widget without creating a module, but the problem is that it is not clear how to pass the cost of delivery. One idea is to use the module with minor modifications. You can go the way of embedding the widget in order-carrier.tpl based on ID, but I think that making changes to Your module would be more correct.
In this regard, could You tell where to paste in Your module code of the widget, so it can recalculate the shipping cost to the total cost?
Thank you.
@bona
Hello Alex. A question… I use for value creation delivery third-party widget. This widget is built in to the front page. Therefore, the shipping cost is determined by the third party service at the time of registration of the order by the client. So here is how to pass the value of shipping cost in function getOrderShippingCostExternal? Thx.
Hi Alex,
First of all thanks for this tutorial !
Do you know how i can make the delays dynamic on a carrier module.
I’m trying to have dynamic delays called on an API.
Thank you for your time.
Stefan K.
Smart,
You can download the module here.
Where is download link?
Thank you for the tutorial.
I have a problem trying to test the module. I try to upload the module but does not appear in the list of modules, so I can not install it.
I followed the instructions in the user manual but I can not make it work, I appreciate any suggestions.
Can you tell me how can we generate tracking number automatically?
Vipul Hadiya,
It is really strange. As we do not use any logic in calculating the shipping cost, it should just return 777.
I followed you tutorial code without changing a single alphabet but instead of returning shipping cost as 777, it shows “Free Shipping”.
I don’t care about logic I just want this 777 as shipping price but i can’t get it. Can you suggest anything?
Tommix,
It is not the full code;) It is just a sample.
bun hin,
The reference to the API for some other module does not make much sense, because they all are different. Besides these modules are paid.
Thanks for tut, helpfull. But anyways, you firt should test before publishing. Your code have errors.
You defined hooks into variable, but never used it in installation to register them. Unless maybe PS registers them automatically, who knows. Anyways, thanks.
Thank you for the tutorial,
could you please share tutorial for the essential part for shipping module that is using the API to get the cost of shipping based on total weight, city or sub city of destination, service type (eg economy, reguler, fast)
i belive it will need city or sub -city field as required for shipping address, and teh API processing than integrate to the rest of the modul.
Regards,
Bun Hin
Razvan,
From what class is the module inherited from? From
CarrierModule
?name = ‘shippingconfigurator’;
$this->tab = ‘shipping_logistics’;
$this->version = ‘1.0’;
$this->author = ‘R. Pepelea’;
$this->limited_countries = array();
parent::__construct ();
$this->displayName = $this->l(‘Shipping Configurator’);
$this->description = $this->l(‘Configure your shipping prices depending on weight.’);
}
public function install(){
if (parent::install()) {
foreach ($this->_hooks as $hook) {
if (!$this->registerHook($hook)) {
return FALSE;
}
}
return TRUE;
}
return FALSE;
}
public function uninstall()
{
if (parent::uninstall()) {
foreach ($this->_hooks as $hook) {
if (!$this->unregisterHook($hook)) {
return FALSE;
}
}
return TRUE;
}
return FALSE;
}
public function hookactionCartSave($params)
{
global $smarty;
$product_list = $params[‘cart’]->getProducts();
$total_weight = 0;
$total_extra_cost = 0;
foreach ( $product_list as $product ):
$total_weight += $product[‘weight_attribute’];
endforeach;
$total_extra_cost = $total_weight * 33;
}
public function hookActionCarrierUpdate($params)
{
}
public function getOrderShippingCost($params = null, $shipping_cost = 0){
return 777;
}
public function getOrderShippingCostExternal($params){
return 999;
// return $this->getOrderShippingCost($params, 0);
}
}
I have this code, could you please tell me why doesn’t it overwrite my shipping costs?
I get the same shipping cost, it doesn’t change to 999 or 777.
You can set a tracking number for the order in the admin panel. Click edit and set the tracking number:
Hi.
this is an excellent tutorial, thanks for sharing this.
I have a question, How can I add the tracking code to the order when is already paid.
Paolo,
You can download the module here.
Hello. Thank you for your tutorial.
I can’t seem to find the link to download the ready-to-use module.
That would be very helpful!
Thank you
ljerry,
Have you seen this module:
Shipcloud – Shipping Tool for DHL, Hermes, UPS etc by Silbersaiten
If it does not suit your needs, we can make you a new module. You can contact our support team at [email protected].
how can add DHL shipping module in prista shop and what is the possibility to add.
thanks