Current File : /var/www/prestashop/modules/mbeshipping/src/Helper/RatesHelper.php |
<?php
/**
* 2017-2022 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author MBE Worldwide
* @copyright 2017-2024 MBE Worldwide
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of MBE Worldwide
*/
namespace PrestaShop\Module\Mbeshipping\Helper;
use PrestaShop\Module\FacetedSearch\Hook\Configuration;
use PrestaShop\Module\Mbeshipping\Ws;
require_once(dirname(__FILE__) . '/../../classes/custom/models/MbeRatesCacheHelper.php');
require_once(dirname(__FILE__) . '/../../classes/custom/models/MbeShippingDPHelper.php');
if (!defined('MBE_UAP_WEIGHT_LIMIT_20_KG')) {
define('MBE_UAP_WEIGHT_LIMIT_20_KG', 20);
}
if (!defined('MBE_UAP_LONGEST_LIMIT_97_CM')) {
define('MBE_UAP_LONGEST_LIMIT_97_CM', 97);
}
if (!defined('MBE_UAP_TOTAL_SIZE_LIMIT_300_CM')) {
define('MBE_UAP_TOTAL_SIZE_LIMIT_300_CM', 300);
}
if (!defined('MBE_UAP_SERVICE')) {
define('MBE_UAP_SERVICE', 'MDP');
}
if (!defined('MBE_UAP_ALLOWED_COUNTRIES_LIST')) {
define('MBE_UAP_ALLOWED_COUNTRIES_LIST', array('IT','FR','GB','ES','DE','PL'));
}
if (!defined('_PS_VERSION_')) {
exit;
}
class RatesHelper
{
protected $rate_table_name = 'mbeshippingrate';
const SHIPMENT_CONFIGURATION_MODE_ONE_SHIPMENT_PER_ITEM = 1;
const SHIPMENT_CONFIGURATION_MODE_ONE_SHIPMENT_PER_SHOPPING_CART_SINGLE_PARCEL = 2;
const SHIPMENT_CONFIGURATION_MODE_ONE_SHIPMENT_PER_SHOPPING_CART_MULTI_PARCEL = 3;
const HANDLING_TYPE_PER_SHIPMENT = "S";
const HANDLING_TYPE_PER_PARCEL = "P";
const HANDLING_TYPE_FIXED = "F";
const ITALIAN_URL = "https://www.mbe.it/it/tracking?c=@";
const SPAIN_URL = "https://www.mbe.es/es/tracking?c=@";
const GERMANY_URL = "https://www.mbe.de/de/tracking?c=@";
const AUSTRIA_URL = "https://www.mbe.at/at/tracking?c=@";
const FRANCE_URL = "https://www.mbefrance.fr/fr/suivi?c=@";
const POLAND_URL = "https://www.mbe.pl/pl/tracking?c=@";
const CROATIA_URL = "https://www.mbe.hr/hr/tracking?c=@";
const UNITEDKINGDOM_URL = "https://www.mbe.co.uk/track?tracking=@";
public function installRatesTable()
{
$sql = "
CREATE TABLE IF NOT EXISTS `" . _DB_PREFIX_ . bqSQL($this->rate_table_name) . "`(
`id_mbeshippingrate` int(10) unsigned NOT NULL AUTO_INCREMENT,
`country` varchar(4) NOT NULL DEFAULT '',
`region` varchar(10) NOT NULL DEFAULT '',
`city` varchar(30) NOT NULL DEFAULT '',
`zip` varchar(10) NOT NULL DEFAULT '',
`zip_to` varchar(10) NOT NULL DEFAULT '',
`weight_from` decimal(12,4) NOT NULL DEFAULT '0.0000',
`weight_to` decimal(12,4) NOT NULL DEFAULT '0.0000',
`price` decimal(12,4) DEFAULT '0.0000',
`delivery_type` varchar(255) DEFAULT '',
PRIMARY KEY (`id_mbeshippingrate`))
";
$result = \Db::getInstance()->execute($sql);
return $result;
}
public function uninstallRatesTable()
{
$sql = "DROP TABLE IF EXISTS `" . _DB_PREFIX_ . bqSQL($this->rate_table_name) . "`";
$result = \Db::getInstance()->execute($sql);
return $result;
}
public function truncate()
{
$truncateSql = " TRUNCATE `" . _DB_PREFIX_ . bqSQL($this->rate_table_name) . "` ";
$truncateResult = \Db::getInstance()->execute($truncateSql);
return $truncateResult;
}
public function insertRate($country, $region, $city, $zip, $zipTo, $weightFrom, $weightTo, $price, $deliveryType)
{
$sql = "
INSERT INTO `" . _DB_PREFIX_ . bqSQL($this->rate_table_name) . "` (
`country`,`region`,`city`,`zip`,`zip_to`,`weight_from`,`weight_to`,`price`,`delivery_type`
)
VALUES (
'" . pSQL($country) . "',
'" . pSQL($region) . "',
'" . pSQL($city) . "',
'" . pSQL($zip) . "',
'" . pSQL($zipTo) . "',
" . (float)$weightFrom . ",
" . (float)$weightTo . ",
" . (float)$price . ",
'" . pSQL($deliveryType) . "'
);
";
$insertResult = \Db::getInstance()->execute($sql);
return $insertResult;
}
public function useCustomRates($country)
{
$result = false;
if (\Configuration::get('shipments_csv_mode') === DataHelper::MBE_CSV_MODE_TOTAL) {
$result = true;
} elseif (\Configuration::get('shipments_csv_mode') === DataHelper::MBE_CSV_MODE_PARTIAL) {
$sql = "SELECT * FROM `" . _DB_PREFIX_ . bqSQL($this->rate_table_name) . "` WHERE `country` = '" . pSQL($country) . "'";
$rates = \Db::getInstance()->executeS($sql);
if (is_array($rates) && count($rates) > 0) {
$result = true;
}
}
return $result;
}
public function getCountryRates($country)
{
$sql = "SELECT * FROM `" . _DB_PREFIX_ . bqSQL($this->rate_table_name) . "` WHERE `country` = '" . pSQL($country) . "'";
$result = \Db::getInstance()->executeS($sql);
return $result;
}
public function applyInsuranceToRate($rate, $insuranceValue)
{
$result = $rate;
$percentageValue = \Configuration::get("mbe_shipments_csv_insurance_per") / 100 * $insuranceValue;
$fixedValue = \Configuration::get("mbe_shipments_csv_insurance_min");
if ($percentageValue < $fixedValue) {
$result += $fixedValue;
} else {
$result += $percentageValue;
}
return $result;
}
public function getCustomRates($country, $region, $city, $postCode, $weight, $insuranceValue)
{
$result = array();
$newdata = array();
$zipSql = " '" . pSQL($postCode) . "' BETWEEN zip AND zip_to";
$country = str_replace("'","''", $country);
$region = str_replace("'","''", $region);
$city = str_replace("'","''", $city);
$helper = new DataHelper();
$services = $helper->getAllowedShipmentServicesArray();
foreach ($services as $service) {
for ($j = 0; $j <= 7; $j++) {
$sql = "SELECT * FROM `" . _DB_PREFIX_ . bqSQL($this->rate_table_name) . "` ";
switch ($j) {
case 0:
$sql .= "WHERE ";
$sql .= "`country` = '" . pSQL($country) . "'";
$sql .= " AND ";
$sql .= "`region` = '" . pSQL($region) . "'";
$sql .= " AND ";
$sql .= " STRCMP(LOWER(city),LOWER('" . pSQL($city) . "')) = 0";
$sql .= " AND ";
$sql .= $zipSql;
break;
case 1:
$sql .= "WHERE ";
$sql .= "`country` = '" . pSQL($country) . "'";
$sql .= " AND ";
$sql .= "`region` = '" . pSQL($region) . "'";
$sql .= " AND ";
$sql .= "`city` = ''";
$sql .= " AND ";
$sql .= $zipSql;
break;
case 2:
$sql .= "WHERE ";
$sql .= "`country` = '" . pSQL($country) . "'";
$sql .= " AND ";
$sql .= "`region` = '" . pSQL($region) . "'";
$sql .= " AND ";
$sql .= "STRCMP(LOWER(city),LOWER('" . pSQL($city) . "')) = 0";
$sql .= " AND ";
$sql .= " zip = '' ";
break;
case 3:
$sql .= "WHERE ";
$sql .= "`country` = '" . pSQL($country) . "'";
$sql .= " AND ";
//$sql .= "`region` = '" . $region . "'";
$sql .= "`region` = ''";
$sql .= " AND ";
$sql .= "STRCMP(LOWER(city),LOWER('" . pSQL($city) . "')) = 0";
$sql .= " AND ";
$sql .= $zipSql;
break;
case 4:
$sql .= "WHERE ";
$sql .= "`country` = '" . pSQL($country) . "'";
$sql .= " AND ";
//$sql .= "`region` = '" . $region . "'";
$sql .= "`region` = ''";
$sql .= " AND ";
$sql .= "STRCMP(LOWER(city),LOWER('" . pSQL($city) . "')) = 0";
$sql .= " AND ";
$sql .= "zip = ''";
break;
case 5:
$sql .= "WHERE ";
$sql .= "`country` = '" . pSQL($country) . "'";
$sql .= " AND ";
//$sql .= "`region` = '" . $region . "'";
$sql .= "`region` = ''";
$sql .= " AND ";
$sql .= "city = ''";
$sql .= " AND ";
$sql .= $zipSql;
break;
case 6:
$sql .= "WHERE ";
$sql .= "`country` = '" . pSQL($country) . "'";
$sql .= " AND ";
$sql .= "`region` = '" . pSQL($region) . "'";
$sql .= " AND ";
$sql .= "city = ''";
$sql .= " AND ";
$sql .= "zip = ''";
break;
case 7:
$sql .= "WHERE ";
$sql .= "`country` = '" . pSQL($country) . "'";
$sql .= " AND ";
$sql .= "`region` = ''";
$sql .= " AND ";
$sql .= "city = ''";
$sql .= " AND ";
$sql .= "zip = ''";
break;
}
$sql .= " AND weight_from <= " . (float)$weight . " AND weight_to >=" . (float)$weight;
$sql .= " AND delivery_type = '" . pSQL($service) . "'";
$sql .= " ORDER BY country DESC, region DESC, zip DESC";
$rows = \Db::getInstance()->executeS($sql);
//$row = $read->fetchAll($select);
if (!empty($rows)) {
// have found a result or found nothing and at end of list!
foreach ($rows as $data) {
$newdata[$data["delivery_type"]] = $data;
}
break;
}
}
}
$ws = new Ws();
foreach ($newdata as $data) {
$rate = new \stdClass;
$rate->Service = $data["delivery_type"];
$rate->ServiceDesc = $ws->getLabelFromShipmentType($data["delivery_type"]);
$rate->SubzoneDesc = '';
$rate->IdSubzone = '';
$rate->NetShipmentTotalPrice = $data["price"];
$result[] = $rate;
//rate with insurance
$rateWithInsurance = new \stdClass;
$rateWithInsurance->Service = $helper->convertShippingCodeWithInsurance($data["delivery_type"]);
$label = $ws->getLabelFromShipmentType($data["delivery_type"]);
$rateWithInsurance->ServiceDesc = $helper->convertShippingLabelWithInsurance($label);
$rateWithInsurance->SubzoneDesc = '';
$rateWithInsurance->IdSubzone = '';
$rateWithInsurance->NetShipmentTotalPrice = $this->applyInsuranceToRate($data["price"], $insuranceValue);
$result[] = $rateWithInsurance;
}
return $result;
}
/**
* @param $destCountry
* @param $destRegion
* @param $city
* @param $destPostCode
* @param $baseSubtotalInclTax
* @param $weight
* @param $boxes
* @param $products
* @param $insuranceValue
* @param $oldResults
* @param $iteration
* @return array
*/
public function getRates($destCountry, $destRegion, $city, $destPostCode, $baseSubtotalInclTax, $weight, $boxes, $products, $insuranceValue, $oldResults = array(), $iteration = 1)
{
$logger = new LoggerHelper();
$helper = new DataHelper();
if ($helper->isEnabledCustomMapping()) {
// If custom mapping is used no MBE methods will be available
return [];
}
$ws = new Ws();
$result = [];
$newResults = [];
$allowedShipmentServicesArray = $helper->getAllowedShipmentServicesArray();
$tax_duty_active = $this->useTaxAndDutyService();
if (is_array($weight)) {
$weightString = json_encode($weight);
} else {
$weightString = $weight;
}
if ($this->useCustomRates($destCountry)) {
$totalWeight = 0;
if (is_array($weight)) {
foreach ($weight as $boxType) {
$totalWeight += array_sum($boxType['weight']);
}
}
$values = json_encode([$destCountry, $destRegion, $destPostCode, $weightString, $boxes, $insuranceValue, $tax_duty_active]);
$id_cache = md5($values);
$id_cart = \Context::getContext()->cart->id;
if ($cached_response = \MbeRatesCacheHelper::get($id_cache, $id_cart)) {
$logger->logDebug(__METHOD__ . ' - Rates cache found for ' . $id_cache . ' and cart ' . $id_cart);
$logger->logDebug(__METHOD__ . ' - Rates cache: ' . print_r($cached_response, true));
$shipments = $cached_response;
} else {
$logger->logDebug(__METHOD__ . ' - No rates cache found for ' . $id_cache . ' and cart ' . $id_cart);
}
if (!isset($shipments) || $shipments === false) {
$shipments = $this->getCustomRates($destCountry, $destRegion, $city, $destPostCode, $totalWeight, $insuranceValue);
if ($tax_duty_active && !empty($shipments)) {
$shipments2 = $ws->estimateShipping(
$destCountry,
$destRegion,
$destPostCode,
$weight,
$boxes,
$products,
$insuranceValue,
$allowedShipmentServicesArray,
false,
[],
true);
if (!empty($shipments2)) {
$this->addTaxAndDutyService($shipments, $shipments2);
}
}
$logger->logDebug(__METHOD__ . ' - Storing rates cache for ' . $id_cache . ' and cart ' . $id_cart);
$logger->logDebug(__METHOD__ . ' - Rates cache: ' . print_r($shipments, true));
\MbeRatesCacheHelper::store($id_cache, $id_cart, $shipments);
}
} else {
// Get Pickup State
$pickup_address_default = null;
$pickup_active = (bool)\Configuration::get('MBESHIPPING_PICKUP_MODE');
if($pickup_active && \Configuration::get('MBESHIPPING_PICKUP_REQUEST_MODE') === 'automatically') {
$pickup_address_default = \MbePickupAddressHelper::getDefaultPickupAddress();
if(empty($pickup_address_default)) {
$pickup_active = false;
}
}
$values = json_encode([$destCountry, $destRegion, $destPostCode, $weightString, $boxes, $insuranceValue, $pickup_active, $pickup_address_default, $tax_duty_active]);
$id_cache = md5($values);
$id_cart = \Context::getContext()->cart->id;
if ($cached_response = \MbeRatesCacheHelper::get($id_cache, $id_cart)) {
$logger->logDebug(__METHOD__ . ' - Rates cache found for ' . $id_cache . ' and cart ' . $id_cart);
$logger->logDebug(__METHOD__ . ' - Rates cache: ' . print_r($cached_response, true));
$shipments = $cached_response;
} else {
$logger->logDebug(__METHOD__ . ' - No rates cache found for ' . $id_cache . ' and cart ' . $id_cart);
}
if (!isset($shipments) || $shipments === false) {
$shipments = $ws->estimateShipping(
$destCountry,
$destRegion,
$destPostCode,
$weight,
$boxes,
$products,
$insuranceValue,
$allowedShipmentServicesArray,
$pickup_active,
$pickup_address_default,
$tax_duty_active
);
$logger->logDebug(__METHOD__ . ' - Storing rates cache for ' . $id_cache . ' and cart ' . $id_cart);
$logger->logDebug(__METHOD__ . ' - Rates cache: ' . print_r($shipments, true));
\MbeRatesCacheHelper::store($id_cache, $id_cart, $shipments);
}
}
if (!$shipments) {
return [];
}
$allowedShipmentServicesArray = $helper->getAllowedShipmentServicesArray();
$shipments = $this->selectShipments($shipments);
foreach ($shipments as $shipment) {
$shipmentMethod = $shipment->Service;
$shipmentMethodKey = $shipment->Service;
if (in_array($shipmentMethod, $allowedShipmentServicesArray, true)) {
$shipmentTitle = $shipment->ServiceDesc;
$shipmentTitle .= ' - ' . $shipment->SubzoneDesc;
$shipmentPrice = $shipment->NetShipmentTotalPrice;
$shipmentPrice = $this->applyFee($shipmentPrice, $boxes);
$shippingThreshold = $helper->getThresholdByShippingServrice($shipmentMethod . (\Configuration::get('mbecountry') === $destCountry ? '' : '_ww'));
if ($shippingThreshold != null && $baseSubtotalInclTax >= $shippingThreshold) {
$shipmentPrice = 0;
}
$customLabel = $helper->getShippingMethodCustomLabel($shipment->Service);
$current = new \stdClass();
$current->title = $customLabel ?: $shipment->ServiceDesc;
$current->mbetitle = $shipment->ServiceDesc;
$current->title_full = $shipmentTitle;
$current->method = $shipmentMethod;
$current->price = $shipmentPrice;
$current->subzone = $shipment->SubzoneDesc;
$current->subzone_id = $shipment->IdSubzone;
$current->shipment_code = $shipmentMethodKey;
$newResults[$shipmentMethodKey] = $current;
}
}
if ($iteration == 1) {
$result = $newResults;
} else {
foreach ($newResults as $newResultKey => $newResult) {
if (array_key_exists($newResultKey, $oldResults)) {
$newResult->price += $oldResults[$newResultKey]->price;
$result[$newResultKey] = $newResult;
}
}
}
return $result;
}
/**
* Collect rates
*
* @param $cart \Cart
* @param $weight
* @return array
*/
public function collectRates(\Cart $cart)
{
//INSERT HERE CHECK FOR CSV
$helper = new DataHelper();
$logger = new LoggerHelper();
$id_address = $cart->id_address_delivery;
$address = new \Address($id_address);
$country = new \Country((int)($address->id_country));
$city = $address->city;
$region = new \State($address->id_state);
$destRegion = $region->iso_code;
$shipmentConfigurationMode = $helper->getShipmentConfigurationMode();
$shipments = [];
$baseSubtotalInclTax = $cart->getOrderTotal(true, \Cart::BOTH_WITHOUT_SHIPPING);
$boxesDimensionWeight = [];
$boxesSingleParcelDimensionWeight = [];
$products = [];
foreach ($cart->getProducts() as $item) {
$product = new \stdClass();
$product->SKUCode = $item['reference'];
$product->Description = $item['name'];
$product->Quantity = $item['cart_quantity'];
$product->Price = $item['price'];
$product->Weight = $helper->convertWeight($item['weight']);
$category = new \Category((int)$item['id_category_default']);
$product->Category = $category->getName();
$products[] = $product;
}
if ($shipmentConfigurationMode == self::SHIPMENT_CONFIGURATION_MODE_ONE_SHIPMENT_PER_ITEM) {
$iteration = 1;
foreach ($cart->getProducts() as $item) {
$weight = $item['weight'];
$weight = $helper->convertWeight($weight);
$boxesDimensionWeight = [];
$boxesSingleParcelDimensionWeight = [];
// Retrieve the product info using the new box structure
$helper->getBoxesArray(
$boxesDimensionWeight,
$boxesSingleParcelDimensionWeight,
$weight,
$helper->getPackageInfo($item['reference'])
);
if (\Configuration::get('mbe_shipments_ins_mode') === DataHelper::MBE_INSURANCE_WITH_TAXES) {
$insuranceValue = $item['price_wt'];
} else {
$insuranceValue = $item['price'];
}
for ($i = 1; $i <= $item['cart_quantity']; $i++) {
$logger->logDebug("Product Iteration: $iteration");
$shipments = $this->getRates($country->iso_code, $destRegion, $city, $address->postcode, $baseSubtotalInclTax, $boxesDimensionWeight, 1, $products, $insuranceValue, $shipments, $iteration);
$iteration++;
}
}
} elseif ($shipmentConfigurationMode == self::SHIPMENT_CONFIGURATION_MODE_ONE_SHIPMENT_PER_SHOPPING_CART_SINGLE_PARCEL) {
$insuranceValue = 0;
foreach ($cart->getProducts() as $item) {
$itemQty = $item['cart_quantity'];
for ($i = 1; $i <= $itemQty; $i++) {
$packageInfo = $helper->getPackageInfo($item['reference']);
$boxesDimensionWeight = $helper->getBoxesArray(
$boxesDimensionWeight,
$boxesSingleParcelDimensionWeight,
$helper->convertWeight($item['weight']),
$packageInfo
);
}
$insuranceValue += $this->getSubtotalForInsurance($item);
}
$boxesDimensionWeight = $helper->mergeBoxesArray(
$boxesDimensionWeight,
$boxesSingleParcelDimensionWeight
);
$numBoxes = $helper->countBoxesArray($boxesDimensionWeight);
$logger->logDebug(__METHOD__ . " - Num Boxes: $numBoxes");
$shipments = $this->getRates($country->iso_code, $destRegion, $city, $address->postcode, $baseSubtotalInclTax, $boxesDimensionWeight, $numBoxes, $products, $insuranceValue, array(), 1);
} elseif ($shipmentConfigurationMode == self::SHIPMENT_CONFIGURATION_MODE_ONE_SHIPMENT_PER_SHOPPING_CART_MULTI_PARCEL) {
$numBoxes = 0;
$insuranceValue = 0;
foreach ($cart->getProducts() as $item) {
$insuranceValue += $this->getSubtotalForInsurance($item);
$numBoxes += $item['cart_quantity'];
for ($i = 1; $i <= $item['cart_quantity']; $i++) {
$helper->getBoxesArray(
$boxesDimensionWeight,
$boxesSingleParcelDimensionWeight,
$helper->convertWeight($item['weight']),
$helper->getPackageInfo($item['reference'], true)
);
}
}
$logger->logDebug(__METHOD__ . " - Num Boxes: $numBoxes");
$shipments = $this->getRates($country->iso_code, $destRegion, $city, $address->postcode, $baseSubtotalInclTax, $boxesSingleParcelDimensionWeight, $numBoxes, $products, $insuranceValue, array(), 1);
}
if (empty($shipments)) {
return [];
}
$result = [];
$shipments = $this->mergeShipments($shipments, $cart->id, $country, $baseSubtotalInclTax);
foreach ($shipments as $key => $shipment) {
if ($shipment instanceof \stdClass) {
$carrier = $this->createOrFindCarrier($shipment->title, $shipment->mbetitle, $shipment->shipment_code);
\Configuration::updateValue('carrier_' . $carrier->id, $shipment->shipment_code);
$result[$key] = array('carrier' => $carrier, 'price' => $shipment->price);
} else {
foreach ($shipment as $k => $obj) {
if (($obj instanceof \stdClass) && !isset($result[$k])) {
$carrier = $this->createOrFindCarrier($obj->title, $obj->mbetitle, $obj->shipment_code);
\Configuration::updateValue('carrier_' . $carrier->id, $obj->shipment_code);
$price = $obj->price;
$shippingThreshold = $helper->getThresholdByShippingServrice($obj->shipment_code . (\Configuration::get('mbecountry') === $country ? '' : '_ww'));
if ($shippingThreshold != null && $baseSubtotalInclTax >= $shippingThreshold) {
$price = 0;
}
$result[$k] = array('carrier' => $carrier, 'price' => $price);
}
}
}
}
return $result;
}
private function mergeShipments($shipments, $cart_id, $country, $baseSubtotalInclTax)
{
// ritorna il tipo di punto selezionato
$typeOfPoint = \MbeShippingDPHelper::getTypeByPudo($cart_id);
if (!empty($shipments['NMDP']) && !empty($shipments['GPP'])) {
$price = 0;
if (empty($typeOfPoint)) {
$price = min($shipments['NMDP']->price, $shipments['GPP']->price);
} else {
$price = $shipments[$typeOfPoint]->price;
}
$shipments = $this->addDPShipment($shipments, 'NMDP-GPP', $price, $shipments['NMDP']->subzone,
$shipments['NMDP']->subzone_id, $country, $baseSubtotalInclTax);
unset($shipments['NMDP']);
unset($shipments['GPP']);
} else {
if (!empty($shipments['11']) && !empty($shipments['12'])) {
$price = 0;
if (empty($typeOfPoint)) {
$price = min($shipments['11']->price, $shipments['12']->price);
} else {
if ($typeOfPoint == "NMDP") {
$typeOfPoint = '11';
} else {
if ($typeOfPoint == "GPP") {
$typeOfPoint = '12';
}
}
$price = $shipments[$typeOfPoint]->price;
}
$shipments = $this->addDPShipment($shipments, '1112', $price, $shipments['11']->subzone,
$shipments['11']->subzone_id, $country, $baseSubtotalInclTax);
unset($shipments['11']);
unset($shipments['12']);
}
}
return $shipments;
}
public function addDPShipment($shipments, $id, $price, $subzone, $id_subzone, $destCountry, $baseSubtotalInclTax)
{
$isCustomLabel = \Configuration::get('mbe_custom_label_' . \Tools::strtolower($id));
$shipments[$id] = (object)array(
"title" => !empty($isCustomLabel) ? $isCustomLabel : "Delivery Point",
"mbetitle" => "Delivery Point",
"title_full" => "Delivery Point",
"method" => $id,
"price" => $price,
"subzone" => $subzone,
"subzone_id" => $id_subzone,
"shipment_code" => $id
);
$helper = new DataHelper();
$shippingThreshold = $helper->getThresholdByShippingServrice($id . (\Configuration::get('mbecountry') === $destCountry ? '' : '_ww'));
if ($shippingThreshold != null && $baseSubtotalInclTax >= $shippingThreshold) {
$shipments[$id]->price = 0;
}
return $shipments;
}
public function selectShipments($shipments)
{
$result = array();
foreach ($shipments as $s) {
$values = array();
foreach ($result as $r) {
$values[] = $r->Service;
}
if (!in_array($s->Service, $values)) {
$result[] = $s;
}
else {
$r = null;
$k = null;
foreach ($result as $t => $struct) {
if ($s->Service == $struct->Service) {
$r = $struct;
$k = $t;
break;
}
}
if ($s->NetShipmentTotalPrice > $r->NetShipmentTotalPrice) {
$result[$k] = $s;
}
}
}
return $result;
}
public function applyFee($value, $packages = 1)
{
$handlingType = \Configuration::get('handling_type');
$handlingAction = \Configuration::get('handling_action');
$handlingFee = \Configuration::get('handling_fee');
if ($handlingAction === self::HANDLING_TYPE_PER_SHIPMENT) {
$packages = 1;
}
if (self::HANDLING_TYPE_FIXED === $handlingType) {
$result = $value + $handlingFee * $packages;
} else {
$result = $value * (100 + $handlingFee) / 100;
}
return $result;
}
public function createOrFindCarrier($key, $mbekey, $key2)
{
$logger = new LoggerHelper();
$carrier = new \Carrier();
if (!isset($mbekey) || $mbekey === '' || $key === $mbekey) {
// add service code to service title and check if there is insurance present
$key2_firstchars = \Tools::substr($key2, 0, 3);
if (\strpos($key, $key2_firstchars) === false) {
if (\strpos($key2, 'INSURANCE') == true) {
$keys = explode('+', $key);
$keys2 = explode('_', $key2);
$key = $keys[0] . '(' . $keys2[0] . ') +' . $keys[1];
} else {
$key .= ' (' . $key2 . ')';
}
}
}
$carrier->name = $key;
$carrier->active = true;
$carrier->deleted = 0;
$carrier->shipping_handling = false;
$carrier->range_behavior = 0;
$carrier->url = $this->getTrackingUrlBySystem(\Configuration::get('mbecountry'));
if (isset($mbekey) && $mbekey !== '' && $key !== $mbekey) {
$key = $mbekey;
$key2_firstchars = \Tools::substr($key2, 0, 3);
if (\strpos($key, $key2_firstchars) === false) {
if (\strpos($key2, 'INSURANCE') == true) {
$keys = explode('+', $key);
$keys2 = explode('_', $key2);
$key = $keys[0] . '(' . $keys2[0] . ') +' . $keys[1];
} else {
$key .= ' (' . $key2 . ')';
}
}
}
foreach (\Language::getLanguages() as $lang) {
$carrier->delay[$lang['id_lang']] = \Tools::substr(\Configuration::get('mbeshippingdelay_' . \Tools::substr(md5($key . '_' . $lang['iso_code']), 0, 15)), 0, 128);
if(isset($carrier->delay[$lang['id_lang']])) {
$carrier->delay[$lang['id_lang']] = ' ';
}
}
$id_tax_rules_group = (int)\Configuration::get('mbe_tax_rule_' . \Tools::strtolower($key2));
$carrier->setTaxRulesGroup($id_tax_rules_group);
$carrier->shipping_external = true;
$carrier->is_module = true;
$carrier->external_module_name = 'mbeshipping';
$carrier->need_range = true;
$id_carrier = \Db::getInstance()->getValue('SELECT `id_carrier` FROM `' . _DB_PREFIX_ . 'carrier` where name = "' . pSQL($carrier->name) . '" AND deleted="0"');
$logger->logDebug(__METHOD__ . " - id_carrier: $id_carrier");
try {
if (!$id_carrier) {
if ($carrier->add()) {
$logger->logDebug(__METHOD__ . " - carrier added: $carrier->id");
$groups = \Group::getGroups(true);
$logger->logDebug(__METHOD__ . ' - groups');
foreach ($groups as $group) {
\Db::getInstance()->insert('carrier_group', [
'id_carrier' => (int)$carrier->id,
'id_group' => (int)$group['id_group'],
]);
$logger->logDebug(__METHOD__ . " - added group: {$group['id_group']}");
}
\Db::getInstance()->insert('carrier_tax_rules_group_shop', [
'id_carrier' => (int)$carrier->id,
'id_tax_rules_group' => (int)$id_tax_rules_group,
'id_shop' => (int)\Context::getContext()->shop->id,
]);
$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()->insert(
'carrier_zone',
['id_carrier' => (int)$carrier->id, 'id_zone' => (int)$z['id_zone']]);
\Db::getInstance()->insert(
'delivery',
['id_carrier' => (int)$carrier->id, 'id_range_price' => (int)$rangePrice->id, 'id_range_weight' => null, 'id_zone' => (int)$z['id_zone'], 'price' => '0'],
true,
0,
\Db::INSERT_IGNORE);
\Db::getInstance()->insert(
'delivery',
['id_carrier' => (int)$carrier->id, 'id_range_price' => null, 'id_range_weight' => (int)$rangeWeight->id, 'id_zone' => (int)$z['id_zone'], 'price' => '0'],
true,
0,
\Db::INSERT_IGNORE);
}
if (_PS_VERSION_ >= 1.7) {
$logoPath = realpath(_PS_MODULE_DIR_ . 'mbeshipping' . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'img' . DIRECTORY_SEPARATOR . 'logo1-7.jpg');
}
else {
$logoPath = realpath(_PS_MODULE_DIR_ . 'mbeshipping' . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'img' . DIRECTORY_SEPARATOR . 'logo.jpg');
}
$logoPathDestination = _PS_ROOT_DIR_ . DIRECTORY_SEPARATOR . 'img' . DIRECTORY_SEPARATOR . 's' . DIRECTORY_SEPARATOR . $carrier->id . '.jpg';
copy($logoPath, $logoPathDestination);
$this->setCarrierIfDelilveryPoint($key2 , $id_carrier);
return $carrier;
}
}
else {
foreach (\Language::getLanguages() as $lang) {
$v = \Tools::substr(\Configuration::get('mbeshippingdelay_' . \Tools::substr(md5($key . '_' . $lang['iso_code']), 0, 15)), 0, 128);
\Db::getInstance()->update('carrier_lang', ['delay' => pSQL($v)], 'id_carrier = ' . (int)$id_carrier . ' and id_lang = ' . (int)$lang['id_lang'], \Db::INSERT_IGNORE);
}
$this->setCarrierIfDelilveryPoint($key2, $id_carrier);
return new \Carrier($id_carrier);
}
}
catch (\Exception $e) {
$logger->logDebug(__METHOD__ . " - Exception: {$e->getMessage()}");
$logger->logDebug(print_r($e->getTrace(), true));
}
}
public function setCarrierIfDelilveryPoint($shipment_code, $id)
{
$gel_code = ['GPP', '12'];
$mbe_code = ['NMDP', '11'];
// If Delivery Point
if(\MbeShippingDPHelper::isDeliveryPointByShipmentCode($shipment_code)){
$dp_type = 'UNIFIED';
\Configuration::updateValue('MBE_SHIPPING_DP_CARRIER_ID', $id);
if(in_array($shipment_code, $gel_code)) {
$dp_type = 'GEL';
}
if(in_array($shipment_code, $mbe_code)) {
$dp_type = 'MBE';
}
\Configuration::updateValue('MBE_SHIPPING_DP_TYPE', $dp_type);
}
}
public function getTrackingUrlBySystem($system): string
{
$result = '';
if ($system === 'IT') {
$result = self::ITALIAN_URL;
} elseif ($system === 'ES') {
$result = self::SPAIN_URL;
} elseif ($system === 'DE') {
$result = self::GERMANY_URL;
} elseif ($system === 'AT') {
$result = self::AUSTRIA_URL;
} elseif ($system === 'FR') {
$result = self::FRANCE_URL;
} elseif ($system === 'PL') {
$result = self::POLAND_URL;
} elseif ($system === 'HR') {
$result = self::CROATIA_URL;
} elseif ($system === 'UK') {
$result = self::UNITEDKINGDOM_URL;
}
return $result;
}
public function enabledCountry($id_address)
{
$address = new \Address($id_address);
$country = new \Country($address->id_country);
if ((bool)\Configuration::get('sallowspecific') === true) {
return in_array($country->iso_code, explode('-', \Configuration::get('specificcountry')), true);
}
return true;
}
public function getTotalNumOfBoxes($weight)
{
$helper = new DataHelper();
$numBoxes = 1;
$maxPackageWeight = $helper->getMaxPackageWeight();
if ($weight > $maxPackageWeight && $maxPackageWeight != 0) {
$numBoxes = ceil($weight / $maxPackageWeight);
}
return $numBoxes;
}
protected function getSubtotalForInsurance($item) {
$insuranceValue = 0;
if (\Configuration::get('mbe_shipments_ins_mode') === DataHelper::MBE_INSURANCE_WITH_TAXES) {
$insuranceValue += $item['price_wt'] * $item['cart_quantity'];
} else {
$insuranceValue += $item['price'] * $item['cart_quantity'];
}
return $insuranceValue;
}
/**
* @param $boxes
* If shipping mode is SHIPMENT_CONFIGURATION_MODE_ONE_SHIPMENT_PER_ITEM $boxes is the last one used for getRates, it's always a "settings" box as CSV it's not used for this mode,
* so it must be used for dimensions check only since it contains only 1 item
* In the other cases it's the proper list of boxes for the shipment
* @param $items
*
* @return bool
*/
private function isUapEnabled( $boxes, $items )
{
$helper = new DataHelper();
$oneParcel = (
( $helper->getShipmentConfigurationMode() == self::SHIPMENT_CONFIGURATION_MODE_ONE_SHIPMENT_PER_ITEM ) ||
( $helper->countBoxesArray( $boxes ) === 1 &&
in_array( $helper->getShipmentConfigurationMode(), [
self::SHIPMENT_CONFIGURATION_MODE_ONE_SHIPMENT_PER_SHOPPING_CART_SINGLE_PARCEL,
self::SHIPMENT_CONFIGURATION_MODE_ONE_SHIPMENT_PER_SHOPPING_CART_MULTI_PARCEL
] )
)
);
// Check longest size of the last box used for getRates. This must be modified if CSV will be enabled for SHIPMENT_CONFIGURATION_MODE_ONE_SHIPMENT_PER_ITEM shipping mode
// Nested if to avoid useless check
if ( $oneParcel ) {
$longestSize = $helper->longestSizeBoxesArray( $boxes );
$box = $boxes[ $helper->arrayKeyFirst( $boxes ) ]; // since it's one parcel we can check only the first element of the array
if ( $longestSize <= MBE_UAP_LONGEST_LIMIT_97_CM ) {
// Longest Size Ok
if ( ( $longestSize + ( 2 * $box['dimensions']['width'] ) + ( 2 * $box['dimensions']['height'] ) ) <= MBE_UAP_TOTAL_SIZE_LIMIT_300_CM ) {
// Total Size Ok
$weightOk = true;
if ( $helper->getShipmentConfigurationMode() == self::SHIPMENT_CONFIGURATION_MODE_ONE_SHIPMENT_PER_ITEM ) {
foreach ( $items as $item ) {
if ( $helper->convertWeight( $item['weight'] ) > MBE_UAP_WEIGHT_LIMIT_20_KG ) {
$weightOk = false;
break;
}
}
} else {
$weightOk = $helper->convertWeight( $helper->totalWeightBoxesArray( $boxes ) ) <= MBE_UAP_WEIGHT_LIMIT_20_KG;
}
if ( $weightOk ) {
// All the checks are OK
return true;
}
}
}
}
return false;
}
/**
* Check if "Tax and Duty" service should be used
*
* @return bool
*/
private function useTaxAndDutyService(): bool
{
$ws = new Ws();
return (bool)$ws->getCustomerPermission('enabledTaxAndDuties') === true &&
(bool)\Configuration::get('MBESHIPPING_TAX_DUTY_SERVICE') === true;
}
/**
* Add "Tax and Duty" service to custom rates
*
* @param array $custom_rates
* @param array $mbe_rates
* @return void
*/
private function addTaxAndDutyService(array &$custom_rates, array $mbe_rates): void
{
foreach ($custom_rates as &$custom_rate) {
$service_name = str_replace(DataHelper::MBE_SHIPPING_WITH_INSURANCE_CODE_SUFFIX, '', $custom_rate->Service);
if (!$mbe_rate = $this->findRateByService($mbe_rates, $service_name)) {
continue;
}
if (!isset($mbe_rate->NetTaxAndDutyTotalPrice)) {
continue;
}
$updated_rate = clone $custom_rate;
$updated_rate->NetTaxAndDutyTotalPrice = $mbe_rate->NetTaxAndDutyTotalPrice;
if (isset($mbe_rate->CustomDutiesGuaranteed)) {
$updated_rate->CustomDutiesGuaranteed = $mbe_rate->CustomDutiesGuaranteed;
}
$custom_rate = $updated_rate;
}
}
/**
* @param array $rates
* @param string $service
* @return false|object
*/
private function findRateByService(array $rates, string $service)
{
foreach ($rates as $rate) {
if ((string)$rate->Service === $service) {
return $rate;
}
}
return false;
}
}