rubensaid Posted July 6, 2015 Share Posted July 6, 2015 (edited) I found a better solution! Just activate advanced stock management, then edit products to allow use advanced stock management for them and finally linked these products with a specific warehouse (could be one for each supplier). Prestashop will calculate cost independently and also will split orders. Hi, I want to share a code I was working out and now it's functionally. This is an override for Cart.php class that make possible to calculate shipping cost grouping products by supplier. <?php class Cart extends CartCore { /** * 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) { if ($this->isVirtualCart()) return 0; if (!$default_country) $default_country = Context::getContext()->country; if (!is_null($product_list)) foreach ($product_list as $key => $value) if ($value['is_virtual'] == 1) unset($product_list[$key]); $complete_product_list = $this->getProducts(); if (is_null($product_list)) $products = $complete_product_list; else $products = $product_list; if (Configuration::get('PS_TAX_ADDRESS_TYPE') == 'id_address_invoice') $address_id = (int)$this->id_address_invoice; elseif (count($product_list)) { $prod = current($product_list); $address_id = (int)$prod['id_address_delivery']; } else $address_id = null; if (!Address::addressExists($address_id)) $address_id = null; $cache_id = 'getPackageShippingCost_'.(int)$this->id.'_'.(int)$address_id.'_'.(int)$id_carrier.'_'.(int)$use_tax.'_'.(int)$default_country->id; if ($products) foreach ($products as $product) $cache_id .= '_'.(int)$product['id_product'].'_'.(int)$product['id_product_attribute']; if (Cache::isStored($cache_id)) return Cache::retrieve($cache_id); // Order total in default currency without fees $order_total = $this->getOrderTotal(true, Cart::ONLY_PHYSICAL_PRODUCTS_WITHOUT_SHIPPING, $product_list); // Start with shipping cost at 0 $shipping_cost = 0; // If no product added, return 0 if (!count($products)) { Cache::store($cache_id, $shipping_cost); return $shipping_cost; } if (!isset($id_zone)) { // Get id zone if (!$this->isMultiAddressDelivery() && isset($this->id_address_delivery) // Be carefull, id_address_delivery is not usefull one 1.5 && $this->id_address_delivery && Customer::customerHasAddress($this->id_customer, $this->id_address_delivery )) $id_zone = Address::getZoneById((int)$this->id_address_delivery); else { if (!Validate::isLoadedObject($default_country)) $default_country = new Country(Configuration::get('PS_COUNTRY_DEFAULT'), Configuration::get('PS_LANG_DEFAULT')); $id_zone = (int)$default_country->id_zone; } } if ($id_carrier && !$this->isCarrierInRange((int)$id_carrier, (int)$id_zone)) $id_carrier = ''; if (empty($id_carrier) && $this->isCarrierInRange((int)Configuration::get('PS_CARRIER_DEFAULT'), (int)$id_zone)) $id_carrier = (int)Configuration::get('PS_CARRIER_DEFAULT'); $total_package_without_shipping_tax_inc = $this->getOrderTotal(true, Cart::BOTH_WITHOUT_SHIPPING, $product_list); if (empty($id_carrier)) { if ((int)$this->id_customer) { $customer = new Customer((int)$this->id_customer); $result = Carrier::getCarriers((int)Configuration::get('PS_LANG_DEFAULT'), true, false, (int)$id_zone, $customer->getGroups()); unset($customer); } else $result = Carrier::getCarriers((int)Configuration::get('PS_LANG_DEFAULT'), true, false, (int)$id_zone); foreach ($result as $k => $row) { if ($row['id_carrier'] == Configuration::get('PS_CARRIER_DEFAULT')) continue; if (!isset(self::$_carriers[$row['id_carrier']])) self::$_carriers[$row['id_carrier']] = new Carrier((int)$row['id_carrier']); $carrier = self::$_carriers[$row['id_carrier']]; // Get only carriers that are compliant with shipping method if (($carrier->getShippingMethod() == Carrier::SHIPPING_METHOD_WEIGHT && $carrier->getMaxDeliveryPriceByWeight((int)$id_zone) === false) || ($carrier->getShippingMethod() == Carrier::SHIPPING_METHOD_PRICE && $carrier->getMaxDeliveryPriceByPrice((int)$id_zone) === false)) { unset($result[$k]); continue; } // If out-of-range behavior carrier is set on "Desactivate carrier" print "Git3 ".$this->getTotalWeight(); if ($row['range_behavior']) { $check_delivery_price_by_weight = Carrier::checkDeliveryPriceByWeight($row['id_carrier'], $this->getTotalWeight(), (int)$id_zone); $total_order = $total_package_without_shipping_tax_inc; $check_delivery_price_by_price = Carrier::checkDeliveryPriceByPrice($row['id_carrier'], $total_order, (int)$id_zone, (int)$this->id_currency); // Get only carriers that have a range compatible with cart if (($carrier->getShippingMethod() == Carrier::SHIPPING_METHOD_WEIGHT && !$check_delivery_price_by_weight) || ($carrier->getShippingMethod() == Carrier::SHIPPING_METHOD_PRICE && !$check_delivery_price_by_price)) { unset($result[$k]); continue; } } if ($carrier->getShippingMethod() == Carrier::SHIPPING_METHOD_WEIGHT) $shipping = $carrier->getDeliveryPriceByWeight($this->getTotalWeight($product_list), (int)$id_zone); else $shipping = $carrier->getDeliveryPriceByPrice($order_total, (int)$id_zone, (int)$this->id_currency); if (!isset($min_shipping_price)) $min_shipping_price = $shipping; if ($shipping <= $min_shipping_price) { $id_carrier = (int)$row['id_carrier']; $min_shipping_price = $shipping; } } } if (empty($id_carrier)) $id_carrier = Configuration::get('PS_CARRIER_DEFAULT'); if (!isset(self::$_carriers[$id_carrier])) self::$_carriers[$id_carrier] = new Carrier((int)$id_carrier, Configuration::get('PS_LANG_DEFAULT')); $carrier = self::$_carriers[$id_carrier]; // No valid Carrier or $id_carrier <= 0 ? if (!Validate::isLoadedObject($carrier)) { Cache::store($cache_id, 0); return 0; } if (!$carrier->active) { Cache::store($cache_id, $shipping_cost); return $shipping_cost; } // Free fees if free carrier if ($carrier->is_free == 1) { Cache::store($cache_id, 0); return 0; } // Select carrier tax if ($use_tax && !Tax::excludeTaxeOption()) { $address = Address::initialize((int)$address_id); $carrier_tax = $carrier->getTaxesRate($address); } $configuration = Configuration::getMultiple(array( 'PS_SHIPPING_FREE_PRICE', 'PS_SHIPPING_HANDLING', 'PS_SHIPPING_METHOD', 'PS_SHIPPING_FREE_WEIGHT' )); // 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; } // Get shipping cost using correct method if ($carrier->range_behavior) { if(!isset($id_zone)) { // Get id zone if (isset($this->id_address_delivery) && $this->id_address_delivery && Customer::customerHasAddress($this->id_customer, $this->id_address_delivery)) $id_zone = Address::getZoneById((int)$this->id_address_delivery); else $id_zone = (int)$default_country->id_zone; } $suppliers = Array(); $weight_per_supplier = Array(); $products_per_suppliers = Array(); foreach ($products as $product) { $product_supplier = $product['id_supplier']; if (!in_array($product_supplier, $suppliers)) { $suppliers[] = $product_supplier; } $products_per_suppliers[$product_supplier][] = $product; $weight_per_supplier[$product_supplier] += $product['weight']; } if (($carrier->getShippingMethod() == Carrier::SHIPPING_METHOD_WEIGHT && !Carrier::checkDeliveryPriceByWeight($carrier->id, $this->getTotalWeight(), (int)$id_zone)) || ($carrier->getShippingMethod() == Carrier::SHIPPING_METHOD_PRICE && !Carrier::checkDeliveryPriceByPrice($carrier->id, $total_package_without_shipping_tax_inc, $id_zone, (int)$this->id_currency) )) $shipping_cost += 0; else { if ($carrier->getShippingMethod() == Carrier::SHIPPING_METHOD_WEIGHT) { foreach ($products_per_suppliers as $products_per_supplier) { $shipping_cost += $carrier->getDeliveryPriceByWeight($this->getTotalWeight($products_per_supplier), $id_zone); } } else { // by price $shipping_cost += $carrier->getDeliveryPriceByPrice($order_total, $id_zone, (int)$this->id_currency); } } } else { if ($carrier->getShippingMethod() == Carrier::SHIPPING_METHOD_WEIGHT) $shipping_cost += $carrier->getDeliveryPriceByWeight($this->getTotalWeight($product_list), $id_zone); else $shipping_cost += $carrier->getDeliveryPriceByPrice($order_total, $id_zone, (int)$this->id_currency); } // Adding handling charges if (isset($configuration['PS_SHIPPING_HANDLING']) && $carrier->shipping_handling) $shipping_cost += (float)$configuration['PS_SHIPPING_HANDLING']; // Additional Shipping Cost per product foreach ($products as $product) if (!$product['is_virtual']) $shipping_cost += $product['additional_shipping_cost'] * $product['cart_quantity']; $shipping_cost = Tools::convertPrice($shipping_cost, Currency::getCurrencyInstance((int)$this->id_currency)); //get external shipping cost from module if ($carrier->shipping_external) { $module_name = $carrier->external_module_name; $module = Module::getInstanceByName($module_name); if (Validate::isLoadedObject($module)) { if (array_key_exists('id_carrier', $module)) $module->id_carrier = $carrier->id; if ($carrier->need_range) if (method_exists($module, 'getPackageShippingCost')) $shipping_cost = $module->getPackageShippingCost($this, $shipping_cost, $products); else $shipping_cost = $module->getOrderShippingCost($this, $shipping_cost); else $shipping_cost = $module->getOrderShippingCostExternal($this); // Check if carrier is available if ($shipping_cost === false) { Cache::store($cache_id, false); return false; } } else { Cache::store($cache_id, false); return false; } } // Apply tax if ($use_tax && isset($carrier_tax)) $shipping_cost *= 1 + ($carrier_tax / 100); $shipping_cost = (float)Tools::ps_round((float)$shipping_cost, 2); Cache::store($cache_id, $shipping_cost); return $shipping_cost; } /** * Return cart weight * @return float Cart weight */ public function getTotalWeight($products = null) { if (!is_null($products)) { $total_weight = 0; $suppliers = Array(); $weight_per_supplier = Array(); $products_per_suppliers = Array(); foreach ($products as $product) { $product_supplier = $product['id_supplier']; if (!in_array($product_supplier, $suppliers)) { $suppliers[] = $product_supplier; } $products_per_suppliers[$product_supplier][] = $product; if (!isset($product['weight_attribute']) || is_null($product['weight_attribute'])) $weight_per_supplier[$product_supplier] += $product['weight'] * $product['cart_quantity']; else $weight_per_supplier[$product_supplier] += $product['weight_attribute'] * $product['cart_quantity']; } $total_weight = max($weight_per_supplier); return $total_weight; } if (!isset(self::$_totalWeight[$this->id])) { if (Combination::isFeatureActive()) $weight_product_with_attribute = Db::getInstance()->getValue(' SELECT SUM((p.`weight` + pa.`weight`) * cp.`quantity`) as nb FROM `'._DB_PREFIX_.'cart_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON (cp.`id_product` = p.`id_product`) LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (cp.`id_product_attribute` = pa.`id_product_attribute`) WHERE (cp.`id_product_attribute` IS NOT NULL AND cp.`id_product_attribute` != 0) AND cp.`id_cart` = '.(int)$this->id.' GROUP BY p.`id_supplier` ORDER BY nb DESC LIMIT 1'); else $weight_product_with_attribute = 0; $weight_product_without_attribute = Db::getInstance()->getValue(' SELECT SUM(p.`weight` * cp.`quantity`) as nb FROM `'._DB_PREFIX_.'cart_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON (cp.`id_product` = p.`id_product`) WHERE (cp.`id_product_attribute` IS NULL OR cp.`id_product_attribute` = 0) AND cp.`id_cart` = '.(int)$this->id.' GROUP BY p.`id_supplier` ORDER BY nb DESC LIMIT 1'); self::$_totalWeight[$this->id] = round((float)$weight_product_with_attribute + (float)$weight_product_without_attribute, 3); } return self::$_totalWeight[$this->id]; } } ?> This code (https://gist.github.com/rubensaid/ec7512dbdc6fd289cd77) was based on mpampols's code (https://gist.github.com/mpampols/26d5780a794e698a5e12) Hope you find this an util complement for you shop. Cart.php Edited September 23, 2015 by comprope (see edit history) Link to comment Share on other sites More sharing options...
Blawdi Posted July 10, 2015 Share Posted July 10, 2015 hello, its possible to added screen ? thank Link to comment Share on other sites More sharing options...
rubensaid Posted July 13, 2015 Author Share Posted July 13, 2015 (edited) I think Screenshots wouldn't help make this clear so I will make an example, please read carefully. Let's sey we have 4 products in our store: Products Product1, which costs 20.00 USD and weights 3 lbs, its suppplied by Supplier1 Product2, which costs 10.00 USD and weights 2 lbs, its suppplied by Supplier2 Product3, which costs 50.00 USD and weights 8 lbs, its suppplied by Supplier3 Product4, which costs 5.00 USD and weights 0.5 lbs, its suppplied by Supplier1 And three suppliers called Supplier1, Supplier2 and Supplier3. Besides, we have two carriers Carriers Carrier1 can transport products up to 4 lbs and costs 5 USD flat. Carrier2 can transport products up to 9 lbs and costs 8 USD flat. Once we have install this overrides we could have this behavior: Cart combination #1 Product1 + Product2 - Total products cost: 30.00 USD - Total products weight: 5 lbs (3 + 2) but max weight per supplier is 3 lbs max(3,2) So available carriers for this cart are Carrier1 and Carrier2 - if use default PS behavior, just Carrier2 would be available since weight value to filter would be 5 lbs instead of 3 lbs Cost for Carrier1 is 10 USD (5 + 5) and 16 USD (8 + 8) for Carrier2 - if use default PS behavior, cost for Carrier1 would be 5 USD and Carrier2 8 USD because it wouldn't care these products belongs to different suppliers Cart combination #2 Product1 + Product3 + Product4 - Total products cost: 75.00 USD - Total products weight: 11.5 lbs (3 + 8 + 0.5) but max weight per supplier is 8 lbs max((3+0.5),8) - because Product1 and Product4 belongs to same supplier So available carrier for this cart is Carrier2 - if use default PS behavior, no carrier would be available Cost for Carrier2 is 16 USD (8 + 8) - if use default PS behavior and imaging that Carrier2 behavior is set to apply max cost if not in rage, cost would be just 8 USD Since you have to choose just one carrier for order, same price would be apply to each product line unless you configure ranges. Hope it is now clear what this override does. Regards. Ruben Felix Lima, Peru Edited July 13, 2015 by rubensaid (see edit history) 1 Link to comment Share on other sites More sharing options...
Blawdi Posted July 13, 2015 Share Posted July 13, 2015 Ok,I copied your code in a .php file add "Cart.php"I put in: / override / classesI cleared the cacheI create a CART with 2 products of two different supplier, but it did not change anything.I did some bad things?thank you a lot Link to comment Share on other sites More sharing options...
rubensaid Posted July 13, 2015 Author Share Posted July 13, 2015 Checklist: 1. Check your products has values for weight in your BO 2. Check configuration for your carries. What is their behavior for out of range? 3. Make sure you delete cache/class_index.php after create override/classes/Cart.php I've made test here: http://dev.compro.pe/index.php?product_rewrite=printed-chiffon-dress&controller=product&id_lang=1 http://dev.compro.pe/index.php?product_rewrite=blouse&controller=product&id_lang=1 These two products belongs to different suppliers. Link to comment Share on other sites More sharing options...
Blawdi Posted September 7, 2015 Share Posted September 7, 2015 hello, I have test on your site, and i have no see? Link to comment Share on other sites More sharing options...
rubensaid Posted September 8, 2015 Author Share Posted September 8, 2015 hello, I have test on your site, and i have no see? I haven't been using it on my site. But I will be use finally. I just developed code becasue I though I would use it but finally desist.. however, now I have to use it .. LOL Link to comment Share on other sites More sharing options...
taydotech123 Posted September 18, 2015 Share Posted September 18, 2015 We should NOT modify core of prestashop, it is very RISK ! Link to comment Share on other sites More sharing options...
rubensaid Posted September 18, 2015 Author Share Posted September 18, 2015 We should NOT modify core of prestashop, it is very RISK ! This is an override, we are not modifying core files directly. If you read developers manuals, you will see that Prestashop mention using overrides to change default behaviour. Link to comment Share on other sites More sharing options...
doozyden Posted June 18, 2017 Share Posted June 18, 2017 Hi there, this is exactly what i need i havent yet tried it out, i would like to confirm if this will work with the latest version of prestashop 1.6.1.14? Link to comment Share on other sites More sharing options...
m.rtr Posted January 1, 2021 Share Posted January 1, 2021 Hi! The latest solution of the warehouses works for me, BUT - there is no carrier name displayed, just the amount that customer will pay. Does someone has the tip how to solve this? thanx! Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now