We continue the series of our articles which aim to help our forum users and today we’ll describe how to make a free delivery not only for the entire store but even for a specific zone. This question was submitted by the user “B. Köring”:
I need help to configure shipping in ps 1.5.6.2. I ‘d even hire some help if you sent me a reasonable charge and I hope I am allowed to aks this here. But I am looking for help since 3 months now and I do not have a solution. Mainly I asked in the Geman forum but now I try it here.
Presta is set up to calculate the shipping by price threshhold – not by weight at the moment. So I can advertise to offer free shipping when customers buy for 40 €.
The problem is that we ship to Eurozone and when customers buy for 41 € shipping will be free – as intended. That is ok. But it is not okay if this order weighs some kilos! Because then we would have to pay a high fee – e.g. 20 € for 8 kilos or so. You see, we would make minus.
So I need to a possibility to make Prestashop skip the ‘free shipping – variable’-condition when shippment zone is not ‘standard-zone’.
Is this possible via vanilla Prestashop, a drity hack, or could this be easily done via a module where you check mark the zones that shall have NO free shipping condition?
Default PrestаShоp settings allow you to set up free delivery only for the entire store:
First off, we need to expand the table ps_carrier
to keep the data separately for each carrier. Let’s make an SQL-query which will add 2 new fileds: shipping_free_price
and shipping_free_weight
:
1 2 |
ALTER TABLE `ab16_carrier` ADD `shipping_free_price` DECIMAL( 20, 6 ) UNSIGNED NOT NULL , ADD `shipping_free_weight` DECIMAL( 20, 6 ) UNSIGNED NOT NULL ; |
To control the new fields you need to override the class Carrier
(classes/Carrier.php) and the file AdminCarrierWizardController
of the controller (controllers/admin/AdminCarrierWizardController.php).
Let’s add new fields to the Carrier class. For that we add the file Carrier.php into the folder override/classes/Carrier.php with the following code:
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 |
<php class CarrierCore extends ObjectModel { public $shipping_free_price; public $shipping_free_weight; /** * @see ObjectModel::$definition */ public static $definition = array( 'table' => 'carrier', 'primary' => 'id_carrier', 'multilang' => true, 'multilang_shop' => true, 'fields' => array( /* Override reason */ 'shipping_free_price' => array('type' => self:: TYPE_FLOAT, 'validate' => 'isFloat'), 'shipping_free_weight' => array('type' => self:: TYPE_FLOAT, 'validate' => 'isFloat'), /* Classic fields */ 'id_reference' => array('type' => self::TYPE_INT), 'name' => array('type' => self::TYPE_STRING, 'validate' => 'isCarrierName', 'required' => true, 'size' => 64), 'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'required' => true), 'is_free' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'url' => array('type' => self::TYPE_STRING, 'validate' => 'isAbsoluteUrl'), 'shipping_handling' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'shipping_external' => array('type' => self::TYPE_BOOL), 'range_behavior' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'shipping_method' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'), 'max_width' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'), 'max_height' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'), 'max_depth' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'), 'max_weight' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat'), 'grade' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'size' => 1), 'external_module_name' => array('type' => self::TYPE_STRING, 'size' => 64), 'is_module' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'need_range' => array('type' => self::TYPE_BOOL), 'position' => array('type' => self::TYPE_INT), 'deleted' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), /* Lang fields */ 'delay' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 128), ), ); } |
In order to add the ability to change settings via the backend, let’s add new fields to the controller AdminCarrierWizardController: add the file AdminCarrierWizardController.php into the folder override/controllers/ AdminCarrierWizardController.php with the following content:
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
<?php class AdminCarrierWizardController extends AdminCarrierWizardControllerCore { public function renderStepThree($carrier) { $this->fields_form = array( 'form' => array( 'id_form' => 'step_carrier_ranges', 'input' => array( array( 'type' => 'switch', 'label' => $this->l('Shipping and handling'), 'name' => 'shipping_handling', 'required' => false, 'class' => 't', 'is_bool' => true, 'values' => array( array( 'id' => 'shipping_handling_on', 'value' => 1, 'label' => $this->l('Enabled') ), array( 'id' => 'shipping_handling_off', 'value' => 0, 'label' => $this->l('Disabled') ) ), 'hint' => $this->l('Include the shipping and handling costs in the carrier price.') ), array( 'type' => 'switch', 'label' => $this->l('Free Shipping'), 'name' => 'is_free', 'required' => false, 'class' => 't', 'values' => array( array( 'id' => 'is_free_on', 'value' => 1, 'label' => '<img src="../img/admin/disabled.gif" alt="'.$this->l('No').'" title="'.$this->l('No').'" />' ), array( 'id' => 'is_free_off', 'value' => 0, 'label' => '<img src="../img/admin/enabled.gif" alt="'.$this->l('Yes').'" title="'.$this->l('Yes').'" />' ) ), ), array( 'type' => 'radio', 'label' => $this->l('Billing'), 'name' => 'shipping_method', 'required' => false, 'class' => 't', 'br' => true, 'values' => array( array( 'id' => 'billing_price', 'value' => Carrier::SHIPPING_METHOD_PRICE, 'label' => $this->l('According to total price.') ), array( 'id' => 'billing_weight', 'value' => Carrier::SHIPPING_METHOD_WEIGHT, 'label' => $this->l('According to total weight.') ) ) ), array( 'type' => 'select', 'label' => $this->l('Tax'), 'name' => 'id_tax_rules_group', 'options' => array( 'query' => TaxRulesGroup::getTaxRulesGroups(true), 'id' => 'id_tax_rules_group', 'name' => 'name', 'default' => array( 'label' => $this->l('No tax'), 'value' => 0 ) ) ), array( 'type' => 'select', 'label' => $this->l('Out-of-range behavior'), 'name' => 'range_behavior', 'options' => array( 'query' => array( array( 'id' => 0, 'name' => $this->l('Apply the cost of the highest defined range') ), array( 'id' => 1, 'name' => $this->l('Disable carrier') ) ), 'id' => 'id', 'name' => 'name' ), 'hint' => $this->l('Out-of-range behavior occurs when no defined range matches the customer\'s cart (e.g. when the weight of the cart is greater than the highest weight limit defined by the weight ranges).') ), //override reason array( 'type' => 'text', 'label' => $this->l('Free shipping starts at (price)'), 'name' => 'shipping_free_price', ), //override reason array( 'type' => 'text', 'label' => $this->l('Free shipping starts at (weight)'), 'name' => 'shipping_free_weight', ), array( 'type' => 'zone', 'name' => 'zones' ) ), )); $tpl_vars = array(); $tpl_vars['PS_WEIGHT_UNIT'] = Configuration::get('PS_WEIGHT_UNIT'); $currency = new Currency(Configuration::get('PS_CURRENCY_DEFAULT')); $tpl_vars['currency_sign'] = $currency->sign; $fields_value = $this->getStepThreeFieldsValues($carrier); $this->getTplRangesVarsAndValues($carrier, $tpl_vars, $fields_value); return $this->renderGenericForm(array('form' => $this->fields_form), $fields_value, $tpl_vars); } public function getStepThreeFieldsValues($carrier) { $id_tax_rules_group = (is_object($this->object) && !$this->object->id) ? Carrier::getIdTaxRulesGroupMostUsed() : $this->getFieldValue($carrier, 'id_tax_rules_group'); $shipping_handling = (is_object($this->object) && !$this->object->id) ? 0 : $this->getFieldValue($carrier, 'shipping_handling'); return array( 'is_free' => $this->getFieldValue($carrier, 'is_free'), 'id_tax_rules_group' => (int)$id_tax_rules_group, 'shipping_handling' => $shipping_handling, 'shipping_free_price' => (float)$carrier->shipping_free_price, //override reason 'shipping_free_weight' => (float)$carrier->shipping_free_weight, //override reason 'shipping_method' => $this->getFieldValue($carrier, 'shipping_method'), 'range_behavior' => $this->getFieldValue($carrier, 'range_behavior'), 'zones' => $this->getFieldValue($carrier, 'zones'), ); } } |
Now we need to add the logic to perform the basic task, that is, to verify the potential possibility of free delivery when selecting a carrier at the checkout step. For that we need to override the Cart class, namely the function getPасkаgeShippingCоst. Let’s create the file override/classes/Cart.php and change the behavior of the function:
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 |
/** * Return package shipping cost * * @param integer $id_carrier Carrier ID (default : current carrier) * @param booleal $use_tax * @param Country $default_country * @param Array $product_list * @param array $product_list List of product concerned by the shipping. If null, all the product of the cart are used to calculate the shipping cost * * @return float Shipping total */ public function getPackageShippingCost($id_carrier = null, $use_tax = true, Country $default_country = null, $product_list = null, $id_zone = null) { … // Free fees $free_fees_price = 0; if (isset($configuration['PS_SHIPPING_FREE_PRICE'])) $free_fees_price = Tools::convertPrice((float)$configuration['PS_SHIPPING_FREE_PRICE'], Currency::getCurrencyInstance((int)$this->id_currency)); $orderTotalwithDiscounts = $this->getOrderTotal(true, Cart::BOTH_WITHOUT_SHIPPING, null, null, false); if ($orderTotalwithDiscounts >= (float)($free_fees_price) && (float)($free_fees_price) > 0) { Cache::store($cache_id, $shipping_cost); return $shipping_cost; } if (isset($configuration['PS_SHIPPING_FREE_WEIGHT']) && $this->getTotalWeight() >= (float)$configuration['PS_SHIPPING_FREE_WEIGHT'] && (float)$configuration['PS_SHIPPING_FREE_WEIGHT'] > 0) { Cache::store($cache_id, $shipping_cost); return $shipping_cost; } //override reason $carriers_collection = new Collection('Carrier'); foreach ($carriers_collection as $carrier) { $free_fees_price = Tools::convertPrice((float)$carrier->shipping_free_price, Currency::getCurrencyInstance((int)$this->id_currency)); if ($orderTotalwithDiscounts >= (float)($free_fees_price) && (float)($free_fees_price) > 0) { return $shipping_cost; } if ($this->getTotalWeight() >= (float)$carrier->shipping_free_weight && (float)$carrier->shipping_free_weight > 0) { return $shipping_cost; } } … |
Hi Lucas,
please, check the link http://doc.prestashop.com/display/PS16/Overriding+default+behaviors
It will definitely help you to better understand how to make an override.
Hi Iryna,
In the tutorial the following steps say:
“For that we add the file Carrier.php into the folder override/classes/Carrier.php with the following code:”
&
“add the file AdminCarrierWizardController.php into the folder override/controllers/ AdminCarrierWizardController.php with the following content:”
& also
“Let’s create the file override/classes/Cart.php and change the behavior of the function:”
To me it’s not clear, do we override the code in the original file that we copied or do we add the code to the files of these steps?
Thanks for your comment.
Dear Lucas,
could you please add some details? I’m afraid I don’t catch what exactly you mean.
Hi,
Do we need to clear the contents and change it by the listed code for the files or do we need to add code?
Hi I would like to activate the carrier for selected pincode only please help me
Pedro Dias,
It is difficult to help you without this customized file. You can contact our support team at [email protected] and they will help you.
Hello,
I’ve changed the files and database like in the article but it gives “error”
Can you help?
HFriday,
I do not think so. You may try to enable showing errors: (http://blog.belvg.com/showing-php-and-sql-errors-and-debugging-a-blank-white-page-in-prestashop.html) and this will help you to understand what goes wrong.
Could the problem be that I try this on PS1.6.08?
HFriday,
Most probably you have made some mistake. We can help you to install this on your store, please, contact our support team at [email protected] to get some help.
Yes, this is what I need but after trying this in PS 1.6.0.8 it ‘kills’ my shop. Also I’m missing some hints on what I should be able to configure where after applying these changes…
Hope you can help out!