* @copyright 2016-2019 GFI Informatique, 2016-2019 TNT * @license https://opensource.org/licenses/MIT MIT License */ require_once _PS_MODULE_DIR_.'tntofficiel/libraries/TNTOfficiel_ClassLoader.php'; /** * Class TNTOfficielCarrier */ class TNTOfficielCarrier extends ObjectModel { // Hard to Reach Area. const URL_HRA_JSON = 'http://www.citsupport.fr/fichiers/tnt-zda.json'; const URL_HRA_HELP = 'http://www.tnt.fr/zone-difficilement-accessible'; const PATH_HRA_JSON = '/libraries/data/hra/zipcode.json'; // id_tntofficiel_carrier public $id; /** @var int Carrier ID. */ public $id_carrier; /** @var int Associated unique shop ID. */ public $id_shop; /** @var int Account ID who create this carrier. */ public $id_account; /** @var string Account Type. */ public $account_type; /** @var string Carrier Type. */ public $carrier_type; /** @var string Carrier Code 1. */ public $carrier_code1; /** @var string Carrier Code 2 (optional). */ public $carrier_code2; /** @var bool Is zones configuration enabled. */ public $zones_enabled; /** @var bool Is zones cloning configuration enabled. */ public $zones_cloning_enabled; /** @var string Serialized zones configuration. */ public $zones_config; /** @var array Model definition. */ public static $definition = array( 'table' => 'tntofficiel_carrier', 'primary' => 'id_tntofficiel_carrier', 'fields' => array( 'id_carrier' => array( 'type' => ObjectModel::TYPE_INT, 'size' => 10, 'validate' => 'isUnsignedId', 'required' => true ), 'id_shop' => array( 'type' => ObjectModel::TYPE_INT, 'size' => 10, 'validate' => 'isUnsignedId', ), 'id_account' => array( 'type' => ObjectModel::TYPE_INT, 'size' => 10, 'validate' => 'isUnsignedId', ), 'account_type' => array( 'type' => ObjectModel::TYPE_STRING, ), 'carrier_type' => array( 'type' => ObjectModel::TYPE_STRING, 'size' => 16 ), 'carrier_code1' => array( 'type' => ObjectModel::TYPE_STRING, 'size' => 1, ), 'carrier_code2' => array( 'type' => ObjectModel::TYPE_STRING, 'size' => 1, ), 'zones_enabled' => array( 'type' => ObjectModel::TYPE_BOOL, 'validate' => 'isBool' ), 'zones_cloning_enabled' => array( 'type' => ObjectModel::TYPE_BOOL, 'validate' => 'isBool' ), 'zones_config' => array( 'type' => ObjectModel::TYPE_STRING ), ), ); /** @var array Carrier Type (AKA Receiver Type) list. */ public static $arrCarrierTypeList = array ( 'ENTERPRISE', 'INDIVIDUAL', 'DROPOFFPOINT', 'DEPOT', ); /** @var array White list using Account Type, Carrier Type (AKA Receiver Type) and Carrier Code. */ public static $arrWhiteList = array( '*' => array( 'ENTERPRISE' => array( 'N' => true, 'A' => true, 'T' => true, 'M' => true, 'J' => true, 'P' => true ), 'DEPOT' => array( 'J' => true, 'P' => false ), 'DROPOFFPOINT' => array( 'JD' => true ), 'INDIVIDUAL' => array( 'AZ' => true, 'TZ' => true, 'MZ' => true, 'JZ' => true ) ), 'ALIMENT' => array( 'ENTERPRISE' => array( 'N' => false, 'A' => false, 'T' => false, 'M' => false, 'J' => false, 'P' => false ), 'DEPOT' => array( 'J' => false, 'P' => false ), 'DROPOFFPOINT' => array( 'JD' => false ), 'INDIVIDUAL' => array( 'AZ' => false, 'TZ' => false, 'MZ' => false, 'JZ' => false ) ), 'ASSU' => array( 'ENTERPRISE' => array( 'N' => false, 'A' => false, 'T' => false, 'M' => false, 'J' => false, 'P' => false ), 'DEPOT' => array( 'J' => false ), 'DROPOFFPOINT' => array( 'JD' => false ), 'INDIVIDUAL' => array( 'AZ' => false, 'TZ' => false, 'MZ' => false, 'JZ' => false ) ), 'RP' => array( 'ENTERPRISE' => array( 'AP' => true, 'TP' => true, 'MP' => true, 'JP' => true ), 'DEPOT' => array( 'JP' => true ) ), 'RP ALIMENT' => array( 'ENTERPRISE' => array( 'AP' => false, 'TP' => false, 'MP' => false, 'JP' => false ), 'DEPOT' => array( 'JP' => false ) ), 'RP ASSU' => array( 'ENTERPRISE' => array( 'AP' => false, 'TP' => false, 'MP' => false, 'JP' => false ), 'DEPOT' => array( 'JP' => false ) ), 'ESP' => array( 'ENTERPRISE' => array( 'AW' => true, 'TW' => true, 'MW' => true, 'JW' => true ), 'DEPOT' => array( 'JW' => true ) ), 'ESP ALIMENT' => array( 'ENTERPRISE' => array( 'AW' => false, 'TW' => false, 'MW' => false, 'JW' => false ), 'DEPOT' => array( 'JW' => false ) ), 'ESP ASSU' => array( 'ENTERPRISE' => array( 'AW' => false, 'TW' => false, 'MW' => false, 'JW' => false ), 'DEPOT' => array( 'JW' => false ) ), 'LPSE' => array( 'ENTERPRISE' => array( 'NE' => true, 'AE' => true, 'TE' => true, 'ME' => true, 'JE' => true, 'PE' => true ) ), 'FROID' => array( 'ENTERPRISE' => array( 'AF' => true, 'TF' => true, 'MF' => true, 'JF' => true ) ) ); /** @var array Displayed informations on Front. */ private static $arrCarrierCodeInfos = array( '*' => array( 'ENTERPRISE:N' => array( 'label' => '08:00 Express en entreprise', 'delay' => 'Livraison dès le lendemain de l\'expédition, avant 8 heures.', 'description' => 'Pour une livraison aux entreprises en France métropolitaine.
Livraison en mains propres et contre signature dès le lendemain de l\'expédition de votre commande, avant 8 heures.', ), 'ENTERPRISE:A' => array( 'label' => '09:00 Express en entreprise', 'delay' => 'Livraison dès le lendemain de l\'expédition, avant 9 heures.', 'description' => 'Pour une livraison aux entreprises en France métropolitaine.
Livraison en mains propres et contre signature dès le lendemain de l\'expédition de votre commande, avant 9 heures.', ), 'ENTERPRISE:T' => array( 'label' => '10:00 Express en entreprise', 'delay' => 'Livraison dès le lendemain de l\'expédition, avant 10 heures.', 'description' => 'Pour une livraison aux entreprises en France métropolitaine.
Livraison en mains propres et contre signature dès le lendemain de l\'expédition de votre commande, avant 10 heures.', ), 'ENTERPRISE:M' => array( 'label' => '12:00 Express en entreprise', 'delay' => 'Livraison en entreprise dès le lendemain de l\'expédition, avant midi.', 'description' => 'Pour une livraison aux entreprises en France métropolitaine.
Livraison en mains propres et contre signature dès le lendemain de l\'expédition de votre commande, avant midi.', ), 'ENTERPRISE:J' => array( 'label' => 'Express en entreprise', 'delay' => 'Livraison dès le lendemain de l\'expédition.', 'description' => 'Pour une livraison aux entreprises en France métropolitaine.
Livraison en mains propres et contre signature dès le lendemain de l\'expédition de votre commande (1).', 'reference' => '(1) avant 13 heures ou en début d\'après-midi en zone rurale.', ), 'ENTERPRISE:P' => array( 'label' => '18:00 Express en entreprise', 'delay' => 'Livraison dès le lendemain de l\'expédition, avant 18 heures.', 'description' => 'Pour une livraison aux entreprises en France métropolitaine.
Livraison en mains propres et contre signature dès le lendemain de l\'expédition de votre commande, avant 18 heures.', ), 'INDIVIDUAL:A' => array( 'label' => '09:00 Express à domicile', 'delay' => 'Livraison dès le lendemain de l\'expédition, avant 9 heures.', 'description' => 'Pour une livraison à domicile en France métropolitaine.
Livraison en mains propres et contre signature dès le lendemain de l\'expédition de votre commande, avant 9 heures.', ), 'INDIVIDUAL:T' => array( 'label' => '10:00 Express à domicile', 'delay' => 'Livraison dès le lendemain de l\'expédition, avant 10 heures.', 'description' => 'Pour une livraison à domicile en France métropolitaine.
Livraison en mains propres et contre signature dès le lendemain de l\'expédition de votre commande, avant 10 heures.', ), 'INDIVIDUAL:M' => array( 'label' => '12:00 Express à domicile', 'delay' => 'Livraison dès le lendemain de l\'expédition, avant midi.', 'description' => 'Pour une livraison à domicile en France métropolitaine.
Livraison en mains propres et contre signature dès le lendemain de l\'expédition de votre commande, avant midi.', ), 'INDIVIDUAL:J' => array( 'label' => 'Express à domicile', 'delay' => 'Livraison dès le lendemain de l\'expédition.', 'description' => 'Pour une livraison à domicile en France métropolitaine.
Livraison en mains propres et contre signature dès le lendemain de l\'expédition de votre commande (1).', 'reference' => '(1) avant 13 heures ou en début d\'après-midi en zone rurale.', ), 'DROPOFFPOINT:J' => array( 'label' => 'Express chez un commerçant partenaire', 'delay' => 'Livraison dès le lendemain de l\'expédition.', 'description' => 'Mise à disposition chez l\'un des 4500 commerçants partenaires en France métropolitaine.
Remise contre signature et présentation d\'une pièce d\'identité dès le lendemain de l\'expédition de votre commande (1).', 'reference' => '(1) avant 13 heures ou en début d\'après-midi en zone rurale.', ), 'DEPOT:J' => array( 'label' => 'Express en agence TNT', 'delay' => 'Livraison dès 8 heures le lendemain de l\'expédition. Mise à votre disposition pendant 10 Jours.', 'description' => 'Pour une livraison dans une de nos agences TNT en France métropolitaine.
Mise à votre disposition sur présentation d\'une pièce d\'identité et contre signature dès 8 heures le lendemain de l\'expédition de votre commande et ce pendant 10 Jours.', ) ) ); /** @var array Displayed informations on Front (optional). */ public static $arrCarrierTypeInfos = array( // https://www.tnt.com/express/fr_fr/site/home/comment-expedier/services-livraison/services-complementaires/livraison-avec-paiement.html 'RP' => 'Colis remis contre un règlement par chèque.', // https://www.tnt.com/express/fr_fr/site/home/comment-expedier/services-livraison/services-complementaires/livraison-sous-protection.html 'ESP' => 'Marchandises sensibles expédiées avec une sûreté renforcée du ramassage jusqu\'à la livraison.', 'FROID' => 'En cas d\'instance de votre colis, un traitement opérationnel spécifique prévoit sa mise en chambre froide.', 'LPSE' => 'En cas d\'absence, livraison possible sans émargement' ); /** @var Cache and prevent race condition. */ private static $arrLoadedEntities = array(); /** * Creates the tables needed by the model. * * @return bool */ public static function createTables() { TNTOfficiel_Logstack::log(); $strLogMessage = sprintf('%s::%s', __CLASS__, __FUNCTION__); $strTablePrefix = _DB_PREFIX_; $strTableEngine = _MYSQL_ENGINE_; $strTableName = $strTablePrefix.TNTOfficielCarrier::$definition['table']; // Create table. $strSQLCreateCarrier = <<execute($strSQLCreateCarrier)) { TNTOfficiel_Logger::logInstall($strLogMessage.' : '.$objDB->getMsgError(), false); return false; } TNTOfficiel_Logger::logInstall($strLogMessage); return true; } /** * Constructor. */ public function __construct($intArgId = null, $intArgLangId = null) { TNTOfficiel_Logstack::log(); parent::__construct($intArgId, $intArgLangId); } /** * Load existing object model or optionally create a new one for it's ID. * * @param $intArgCarrierID * @param bool $boolArgCreate * @param null $intArgLangID * * @return mixed|null|TNTOfficielCarrier */ public static function loadCarrierID($intArgCarrierID, $boolArgCreate = false, $intArgLangID = null) { TNTOfficiel_Logstack::log(); $intCarrierID = (int)$intArgCarrierID; // An existing Carrier ID is required (to load or create). if (!($intCarrierID > 0)) { return null; } $strEntityID = '_'.$intCarrierID.'-'.(int)$intArgLangID.'-'.(int)null; // If already loaded. if (array_key_exists($strEntityID, TNTOfficielCarrier::$arrLoadedEntities)) { $objTNTCarrierModel = TNTOfficielCarrier::$arrLoadedEntities[$strEntityID]; // Check. if ((int)$objTNTCarrierModel->id_carrier === $intCarrierID && Validate::isLoadedObject($objTNTCarrierModel) ) { return $objTNTCarrierModel; } } // Search row for carrier ID. $objDbQuery = new DbQuery(); $objDbQuery->select('*'); $objDbQuery->from(TNTOfficielCarrier::$definition['table']); $objDbQuery->where('id_carrier = '.$intCarrierID); $objDB = Db::getInstance(); $arrResult = $objDB->executeS($objDbQuery); // If row found and match carrier ID. if (count($arrResult) === 1 && $intCarrierID === (int)$arrResult[0]['id_carrier']) { // Load existing TNT carrier entry. $objTNTCarrierModel = new TNTOfficielCarrier((int)$arrResult[0]['id_tntofficiel_carrier'], $intArgLangID); } elseif ($boolArgCreate === true) { // Create a new TNT carrier entry. $objTNTCarrierModelCreate = new TNTOfficielCarrier(null, $intArgLangID); $objTNTCarrierModelCreate->id_carrier = $intCarrierID; // init zonesEnabled by default is true $objTNTCarrierModelCreate->setZonesEnabled(1); $objTNTCarrierModelCreate->save(); // Reload to get default DB values after creation. $objTNTCarrierModel = TNTOfficielCarrier::loadCarrierID($intCarrierID, false, $intArgLangID); } else { // Log only for TNT carrier. if (TNTOfficielCarrier::isTNTOfficielCarrierID($intCarrierID)) { $objException = new Exception('TNTOfficielCarrier not found for Carrier ID #'.$intCarrierID); TNTOfficiel_Logger::logException($objException); } return null; } // Check. if ((int)$objTNTCarrierModel->id_carrier !== $intCarrierID || !Validate::isLoadedObject($objTNTCarrierModel)) { return null; } $objTNTCarrierModel->id = (int)$objTNTCarrierModel->id; $objTNTCarrierModel->id_carrier = (int)$objTNTCarrierModel->id_carrier; $objTNTCarrierModel->id_shop = (int)$objTNTCarrierModel->id_shop; $objTNTCarrierModel->id_account = (int)$objTNTCarrierModel->id_account; TNTOfficielCarrier::$arrLoadedEntities[$strEntityID] = $objTNTCarrierModel; return $objTNTCarrierModel; } public static function isWhiteListed( $strArgAccountType, $strArgCarrierType, $strArgCarrierCode1, $strArgCarrierCode2 ) { TNTOfficiel_Logstack::log(); $strAccountType = (($strArgAccountType === '') ? '*' : $strArgAccountType); return (array_key_exists($strAccountType, TNTOfficielCarrier::$arrWhiteList) && is_array(TNTOfficielCarrier::$arrWhiteList[$strAccountType]) && array_key_exists($strArgCarrierType, TNTOfficielCarrier::$arrWhiteList[$strAccountType]) && is_array(TNTOfficielCarrier::$arrWhiteList[$strAccountType][$strArgCarrierType]) && array_key_exists( $strArgCarrierCode1.$strArgCarrierCode2, TNTOfficielCarrier::$arrWhiteList[$strAccountType][$strArgCarrierType] ) && TNTOfficielCarrier::$arrWhiteList[$strAccountType][$strArgCarrierType][ $strArgCarrierCode1.$strArgCarrierCode2 ] === true ); } /** * Load a Prestashop Carrier object from id. * * @param int $intArgCarrierID * * @return Carrier|null */ public static function getPSCarrier($intArgCarrierID) { TNTOfficiel_Logstack::log(); // Carrier ID must be an integer greater than 0. if (empty($intArgCarrierID) || $intArgCarrierID != (int)$intArgCarrierID || !((int)$intArgCarrierID > 0)) { return null; } $intCarrierID = (int)$intArgCarrierID; // Load carrier. $objPSCarrier = new Carrier($intCarrierID); // If carrier object not available. if (!(Validate::isLoadedObject($objPSCarrier) && (int)$objPSCarrier->id === $intCarrierID)) { return null; } return $objPSCarrier; } /** * Check if a Prestashop carrier ID is a TNTOfficel module one. * * @param int $intArgCarrierID * * @return boolean */ public static function isTNTOfficielCarrierID($intArgCarrierID) { TNTOfficiel_Logstack::log(); $objPSCarrier = TNTOfficielCarrier::getPSCarrier($intArgCarrierID); // If carrier object not available. if ($objPSCarrier === null) { return false; } return $objPSCarrier->external_module_name === TNTOfficiel::MODULE_NAME; } /** * Get the carrier Account model. * * @return TNTOfficielAccount|null */ public function getTNTAccountModel() { TNTOfficiel_Logstack::log(); return TNTOfficielAccount::loadAccountID($this->id_account); } /** * Get the Shop associated with this carrier. * * @return int|null */ public function getPSShop() { TNTOfficiel_Logstack::log(); $intShopID = (int)$this->id_shop; $objPSShop = new Shop($intShopID); if (!Validate::isLoadedObject($objPSShop) || (int)$objPSShop->id !== $intShopID ) { return null; } return $objPSShop; } /** * Check if a non deleted carrier is already existing for a shop. * * @param int $intArgShopID * @param string $strArgAccountType * @param string $strArgCarrierType * @param string $strArgCarrierCode1 * @param string $strArgCarrierCode2 * * @return bool */ public static function isExist( $intArgShopID, $strArgAccountType, $strArgCarrierType, $strArgCarrierCode1, $strArgCarrierCode2 ) { TNTOfficiel_Logstack::log(); $arrObjTNTCarrierModelList = array(); // Search row. $objDbQuery = new DbQuery(); $objDbQuery->select('*'); $objDbQuery->from(TNTOfficielCarrier::$definition['table'], 't'); $objDbQuery->where('id_shop = '.$intArgShopID); $objDbQuery->where('account_type = \''.pSQL($strArgAccountType).'\''); $objDbQuery->where('carrier_type = \''.pSQL($strArgCarrierType).'\''); $objDbQuery->where('carrier_code1 = \''.pSQL($strArgCarrierCode1).'\''); $objDbQuery->where('carrier_code2 = \''.pSQL($strArgCarrierCode2).'\''); /* $objDbQuery->innerJoin( 'carrier', 'c' , 't.id_carrier = c.id_carrier AND c.deleted = 0' ); */ $objDB = Db::getInstance(); $arrResult = $objDB->executeS($objDbQuery); // If row found and match accound ID. if (count($arrResult) > 0) { foreach ($arrResult as $arrValue) { $intCarrierID = (int)$arrValue['id_carrier']; $objTNTCarrierModel = TNTOfficielCarrier::loadCarrierID($intCarrierID, false); // If if ($objTNTCarrierModel !== null) { $objPSCarrier = TNTOfficielCarrier::getPSCarrier($intCarrierID); // If carrier object available and not deleted. if ($objPSCarrier !== null && !$objPSCarrier->deleted) { $arrObjTNTCarrierModelList[(int)$objTNTCarrierModel->id_carrier] = $objTNTCarrierModel; } } } } return count($arrObjTNTCarrierModelList) > 0; } /** * Get the Prestashop Carrier name. * * @return string */ public function getName() { TNTOfficiel_Logstack::log(); $objPSCarrier = TNTOfficielCarrier::getPSCarrier($this->id_carrier); // If carrier object not available. if ($objPSCarrier === null) { return 'N/A'; } return $objPSCarrier->name; } /** * Get carrier label. * * @return stdClass|null */ public static function getCarrierLabel($strArgAccountType, $strArgCarrierType, $strArgCarrierCode1) { TNTOfficiel_Logstack::log(); $strCarrierLabel = null; $strCarrierKey = $strArgCarrierType.':'.$strArgCarrierCode1; $arrCarrierCodeInfos = TNTOfficielCarrier::$arrCarrierCodeInfos['*']; if (array_key_exists($strArgAccountType, TNTOfficielCarrier::$arrCarrierCodeInfos)) { $arrCarrierCodeInfos = TNTOfficielCarrier::$arrCarrierCodeInfos[$strArgAccountType]; } if (array_key_exists($strCarrierKey, $arrCarrierCodeInfos)) { $strCarrierLabel = $arrCarrierCodeInfos[$strCarrierKey]['label']; if ($strArgAccountType !== '*') { $strCarrierLabel .= ' ('.$strArgAccountType.')'; } } return $strCarrierLabel; } /** * Get carrier information. * * @return stdClass|null */ public function getCarrierInfos() { TNTOfficiel_Logstack::log(); $objCarrierInfos = null; $strCarrierKey = $this->carrier_type.':'.$this->carrier_code1; $arrCarrierCodeInfos = TNTOfficielCarrier::$arrCarrierCodeInfos['*']; if (array_key_exists($this->account_type, TNTOfficielCarrier::$arrCarrierCodeInfos)) { $arrCarrierCodeInfos = TNTOfficielCarrier::$arrCarrierCodeInfos[$this->account_type]; } if (array_key_exists($strCarrierKey, $arrCarrierCodeInfos)) { $objCarrierInfos = (object)$arrCarrierCodeInfos[$strCarrierKey]; $objCarrierInfos->label = TNTOfficielCarrier::getCarrierLabel( $this->account_type, $this->carrier_type, $this->carrier_code1 ); if (array_key_exists($this->account_type, TNTOfficielCarrier::$arrCarrierTypeInfos)) { $objCarrierInfos->description2 = TNTOfficielCarrier::$arrCarrierTypeInfos[$this->account_type]; } } return $objCarrierInfos; } /** * Get the account type using carrier info from feasibility. * * @param string $strArgCarrierType * @param string $strArgCarrierCode2 * @param string $strArgCarrierLabel * * @return string ['*', 'ALIMENT', 'ASSU', 'RP', 'RP ALIMENT', 'RP ASSU', * 'ESP', 'ESP ALIMENT', 'ESP ASSU', 'LPSE', 'FROID'] */ public static function getAccountType($strArgCarrierType, $strArgCarrierCode2, $strArgCarrierLabel) { TNTOfficiel_Logstack::log(); $strAccountType = '*'; $arrAccountType = array(); if ($strArgCarrierCode2 === 'P') { $arrAccountType[] = 'RP'; } elseif ($strArgCarrierCode2 === 'W') { $arrAccountType[] = 'ESP'; } elseif ($strArgCarrierCode2 === 'D') { // Commerçants Partenaires. //$arrAccountType[] = 'DROPOFFPOINT'; } elseif ($strArgCarrierCode2 === 'Z') { //$arrAccountType[] = 'A Domicile'; } elseif ($strArgCarrierCode2 === 'E') { $arrAccountType[] = 'LPSE'; } // Aliment may not be detected. if (preg_match('/\bALIMENT\b/ui', $strArgCarrierLabel) === 1) { $arrAccountType[] = 'ALIMENT'; } if (preg_match('/\bFROID\b/ui', $strArgCarrierLabel) === 1) { $arrAccountType[] = 'FROID'; } if (preg_match('/\bASSU\b/ui', $strArgCarrierLabel) === 1) { $arrAccountType[] = 'ASSU'; } if ($strArgCarrierType === 'DEPOT') { // Agences TNT. //$arrAccountType[] = 'DEPOT'; } if (count($arrAccountType) > 0) { $strAccountType = implode(' ', $arrAccountType); } return $strAccountType; } /** * Modify a current TNT carrier ID to a new one. * * @param int $intArgCarrierOldID * @param int $intArgCarrierNewID * * @return bool */ public static function updateCarrierID($intArgCarrierOldID, $intArgCarrierNewID) { TNTOfficiel_Logstack::log(); // Load the carrier ID. $objTNTCarrierModelOld = TNTOfficielCarrier::loadCarrierID($intArgCarrierOldID, false); // If fail or unexist. if ($objTNTCarrierModelOld === null) { return false; } // Create a new model for copy. $objTNTCarrierModel = TNTOfficielCarrier::loadCarrierID($intArgCarrierNewID, true); // If fail. if ($objTNTCarrierModel === null) { return false; } // Copy. $objTNTCarrierModel->id_shop = $objTNTCarrierModelOld->id_shop; $objTNTCarrierModel->id_account = $objTNTCarrierModelOld->id_account; $objTNTCarrierModel->account_type = $objTNTCarrierModelOld->account_type; $objTNTCarrierModel->carrier_type = $objTNTCarrierModelOld->carrier_type; $objTNTCarrierModel->carrier_code1 = $objTNTCarrierModelOld->carrier_code1; $objTNTCarrierModel->carrier_code2 = $objTNTCarrierModelOld->carrier_code2; $objTNTCarrierModel->zones_enabled = $objTNTCarrierModelOld->zones_enabled; $objTNTCarrierModel->zones_cloning_enabled = $objTNTCarrierModelOld->zones_cloning_enabled; $objTNTCarrierModel->zones_config = $objTNTCarrierModelOld->zones_config; return $objTNTCarrierModel->save(); } /** * Search for a list of non deleted existing carrier object model, associated to a shop context. * * @param float $fltArgHeaviestProduct filter result using the heaviest product weight. * @param bool $boolArgIsReceiverB2B filter result as B2B (true) or B2C (false). null for no filter. * * @return array list of TNTOfficielCarrier model found. */ public static function getContextCarrierModelList( $fltArgHeaviestProduct = 0.0, $boolArgIsReceiverB2B = null ) { TNTOfficiel_Logstack::log(); $fltHeaviestProduct = (float)$fltArgHeaviestProduct; $arrObjTNTCarrierModelList = array(); $arrArgIntShopIDList = Shop::getContextListShopID(); $arrIntShopIDList = array_map('intval', $arrArgIntShopIDList); try { // Search row for account ID. $objDbQuery = new DbQuery(); $objDbQuery->select('*'); $objDbQuery->from(TNTOfficielCarrier::$definition['table'], 't'); $objDbQuery->where('id_shop IN ('.implode(',', $arrIntShopIDList).')'); /* $objDbQuery->innerJoin( 'carrier', 'c' , 't.id_carrier = c.id_carrier AND c.deleted = 0' ); */ $objDB = Db::getInstance(); $arrResult = $objDB->executeS($objDbQuery); // If row found and match accound ID. if (count($arrResult) > 0) { foreach ($arrResult as $arrValue) { $intCarrierID = (int)$arrValue['id_carrier']; $objTNTCarrierModel = TNTOfficielCarrier::loadCarrierID($intCarrierID, false); // If if ($objTNTCarrierModel !== null) { $objPSCarrier = TNTOfficielCarrier::getPSCarrier($intCarrierID); // If Carrier object available and not deleted. if ($objPSCarrier !== null && !$objPSCarrier->deleted // Filter using receiver type (B2B, B2C or unknown). && $objTNTCarrierModel->isAvailableForReceiverType($boolArgIsReceiverB2B) // Filter using heaviest product weight (against package maximum weight). && $objTNTCarrierModel->isAvailableForProductWeight($fltHeaviestProduct) ) { $arrObjTNTCarrierModelList[$objTNTCarrierModel->id_carrier] = $objTNTCarrierModel; } } } } } catch (Exception $objException) { TNTOfficiel_Logger::logException($objException); } return $arrObjTNTCarrierModelList; } /** * Get the list of carrier object model, through feasibility webservice. * * @param float $fltArgHeaviestProduct * @param int $intArgAddressIDDelivery * * @return array */ public static function getFeasibilitiesContextCarrierModelList( $fltArgHeaviestProduct = 0.0, $intArgAddressIDDelivery = null ) { TNTOfficiel_Logstack::log(); $fltHeaviestProduct = (float)$fltArgHeaviestProduct; $arrResult = array(); // A delivery address is optional. $objPSAddressDelivery = TNTOfficielReceiver::getPSAddress($intArgAddressIDDelivery); // If delivery address object is available. if ($objPSAddressDelivery !== null) { $boolIsReceiverB2B = !!$objPSAddressDelivery->company; $strCountryISO = Country::getIsoById((int)$objPSAddressDelivery->id_country); $strReceiverZipCode = $objPSAddressDelivery->postcode; $strReceiverCity = $objPSAddressDelivery->city; $arrObjTNTCarrierModelList = TNTOfficielCarrier::getContextCarrierModelList( $fltHeaviestProduct, $boolIsReceiverB2B ); // Adding matching carriers with feasibilities. foreach ($arrObjTNTCarrierModelList as $intCarrierID => $objTNTCarrierModel) { $objTNTCarrierAccountModel = $objTNTCarrierModel->getTNTAccountModel(); if ($objTNTCarrierAccountModel === null) { continue; } // Get cities from the webservice from the given postal code. $arrResultCitiesGuide = $objTNTCarrierAccountModel->citiesGuide( $strCountryISO, $strReceiverZipCode, $strReceiverCity ); // If the country is not supported // or the city does not match the postcode for the delivery address (without communication error). if (!$arrResultCitiesGuide['boolIsCountrySupported'] || (!$arrResultCitiesGuide['boolIsRequestComError'] && !$arrResultCitiesGuide['boolIsCityNameValid'] )) { continue; } $arrTNTServiceList = $objTNTCarrierAccountModel->feasibilities( $strReceiverZipCode, $strReceiverCity, array($objTNTCarrierModel->carrier_type) ); foreach ($arrTNTServiceList as $arrTNTService) { if ($objTNTCarrierModel->account_type === $arrTNTService['accountType'] && $objTNTCarrierModel->carrier_type === $arrTNTService['carrierType'] && $objTNTCarrierModel->carrier_code1 === $arrTNTService['carrierCode1'] && $objTNTCarrierModel->carrier_code2 === $arrTNTService['carrierCode2'] ) { $arrResult[$intCarrierID] = $objTNTCarrierModel; } } } } else { // If there is no delivery address, use all carriers. $arrResult = TNTOfficielCarrier::getContextCarrierModelList($fltHeaviestProduct); } return $arrResult; } /** * Force all current carrier settings. * * @return bool */ public static function forceAllCarrierDefaultValues() { TNTOfficiel_Logstack::log(); $boolResult = true; $arrObjTNTCarrierModelList = TNTOfficielCarrier::getContextCarrierModelList(); foreach ($arrObjTNTCarrierModelList as /*$intCarrierID =>*/ $objTNTCarrierModel) { $boolResult = $objTNTCarrierModel->forceCarrierDefaultValues() && $boolResult; } TNTOfficielCarrier::autoClean(); return $boolResult; } /** * Force a current carrier settings. * * @param string $strArgCarrierCode * * @return bool */ public function forceCarrierDefaultValues() { TNTOfficiel_Logstack::log(); $this->forceAssoUniqueShop(); //$this->forceAssoExcludeGroup(); return true; } /** * Force the groups exclusion. * * @return boolean */ protected function forceAssoExcludeGroup() { TNTOfficiel_Logstack::log(); // Users groups to exclude. $arrCarrierGroupExcludeConfigList = array( //'PS_UNIDENTIFIED_GROUP', //'PS_GUEST_GROUP' ); $objPSCarrier = TNTOfficielCarrier::getPSCarrier($this->id_carrier); // If Carrier object available. if ($objPSCarrier !== null) { // Get all users groups associated with the TNT carrier. $arrCarrierGroups = $objPSCarrier->getGroups(); // If there is currently at least one users groups set. if (is_array($arrCarrierGroups) && count($arrCarrierGroups) > 0) { // Current users groups set. $arrCarrierGroupSetIDList = array(); foreach ($arrCarrierGroups as $arrRowCarrierGroup) { // DB request fail. stop here. if (!array_key_exists('id_group', $arrRowCarrierGroup)) { return false; } $arrCarrierGroupSetIDList[] = (int)$arrRowCarrierGroup['id_group']; } // Get users groups ID list to exclude. $arrCarrierGroupExcludeIDList = array(); foreach ($arrCarrierGroupExcludeConfigList as $strGroupExcludeConfig) { $arrCarrierGroupExcludeIDList[] = (int)Configuration::get($strGroupExcludeConfig); } // Get groups previously set, minus groups to exclude. $arrCarrierGroupsApply = array_diff($arrCarrierGroupSetIDList, $arrCarrierGroupExcludeIDList); // If groups change. if (count(array_diff($arrCarrierGroupSetIDList, $arrCarrierGroupsApply)) > 0) { // Force carrier users groups (delete all, then set). $objPSCarrier->setGroups($arrCarrierGroupsApply, true); } } } return true; } /** * Force the shop associations to an unique one. * * @return bool|void */ protected function forceAssoUniqueShop() { TNTOfficiel_Logstack::log(); $objContext = Context::getContext(); if (!property_exists($objContext, 'employee') || !$objContext->employee) { return false; } if (!Shop::isFeatureActive()) { return false; } if (!Shop::isTableAssociated('carrier')) { return false; } $intTNTCarrierID = (int)$this->id_carrier; $objDB = Db::getInstance(); /* * Check current shop association. */ $arrCarrierAssoCurrentShopIDList = array(); $strSQLSelectCarrierAssoCurrentShopIDList = 'SELECT id_shop FROM `'._DB_PREFIX_.'carrier_shop` WHERE `id_carrier` = '.$intTNTCarrierID; $arrSQLResultCarrierAssoCurrentShopIDList = $objDB->executeS($strSQLSelectCarrierAssoCurrentShopIDList); foreach ($arrSQLResultCarrierAssoCurrentShopIDList as $arrRowAssoCurrentShop) { $arrCarrierAssoCurrentShopIDList[] = (int)$arrRowAssoCurrentShop['id_shop']; } // If no change needed. if (count($arrCarrierAssoCurrentShopIDList) === 1 && in_array($intTNTCarrierID, $arrCarrierAssoCurrentShopIDList, true) ) { return false; } $arrCarrierAssoForcedShopIDList = array( (int)$this->id_shop ); // Get list of shop id we want to exclude from asso deletion $arrExcludeShopIDList = $arrCarrierAssoForcedShopIDList; // Exclude employee unauthorized shop ID for the carrier. $strSQLSelectAllShopIDList = 'SELECT id_shop FROM '._DB_PREFIX_.'shop'; $arrSQLResultAllShopIDList = $objDB->executeS($strSQLSelectAllShopIDList); foreach ($arrSQLResultAllShopIDList as $arrRowShop) { if (!$objContext->employee->hasAuthOnShop($arrRowShop['id_shop'])) { $arrExcludeShopIDList[] = (int)$arrRowShop['id_shop']; } } // Delete shop ID list for the carrier. $objDB->delete( 'carrier_shop', '`id_carrier` = '.(int)$intTNTCarrierID .($arrExcludeShopIDList ? ' AND id_shop NOT IN ('.implode(',', $arrExcludeShopIDList).')' : '') ); $arrRowInsertCarrierAssoForcedShopIDList = array(); foreach ($arrCarrierAssoForcedShopIDList as $intForcedShopID) { $arrRowInsertCarrierAssoForcedShopIDList[] = array( 'id_carrier' => (int)$intTNTCarrierID, 'id_shop' => (int)$intForcedShopID, ); } return $objDB->insert('carrier_shop', $arrRowInsertCarrierAssoForcedShopIDList, false, true, Db::INSERT_IGNORE); } /** * Auto delete unused TNT carrier. */ public static function autoClean() { TNTOfficiel_Logstack::log(); $arrAllCarrier = Carrier::getCarriers( //(int)$this->context->language->id, (int)Configuration::get('PS_LANG_DEFAULT'), false, false, false, null, Carrier::CARRIERS_MODULE ); foreach ($arrAllCarrier as $arrCarrier) { $intCarrierID = (int)$arrCarrier['id_carrier']; // If Carrier is TNT Carrier. if (TNTOfficielCarrier::isTNTOfficielCarrierID($intCarrierID)) { $objPSCarrier = TNTOfficielCarrier::getPSCarrier($intCarrierID); // If Carrier object available. if ($objPSCarrier !== null) { $objTNTCarrierModel = TNTOfficielCarrier::loadCarrierID($intCarrierID, false); // If TNT carrier model does not exist. if ($objTNTCarrierModel === null) { // Delete carrier. $objPSCarrier->active = false; $objPSCarrier->deleted = true; $objPSCarrier->save(); } else { $objTNTCarrierAccountModel = $objTNTCarrierModel->getTNTAccountModel(); // If no TNT account or account is deleted. if ($objTNTCarrierAccountModel === null || $objTNTCarrierAccountModel->deleted ) { $objPSCarrier->active = false; $objPSCarrier->deleted = true; $objPSCarrier->save(); } } } } } } /** * Is carrier available for a product weight. * * @param float $fltArgHeaviestProduct the heaviest product weight. * * @return bool */ public function isAvailableForProductWeight($fltArgHeaviestProduct = 0.0) { TNTOfficiel_Logstack::log(); $fltHeaviestProduct = (float)$fltArgHeaviestProduct; // Filter Weight : If heaviest product is in B2C range (less or equal to 20 kg) // or in B2B range (greater than 20 kg and less or equal to 30 kg) with B2B option. return ($fltHeaviestProduct <= $this->getMaxPackageWeight()); } /** * Is carrier available for a receiver. * * @param bool $boolArgIsReceiverB2B true for B2B, false for B2C, null for unknown. * * @return bool */ public function isAvailableForReceiverType($boolArgIsReceiverB2B = null) { TNTOfficiel_Logstack::log(); // Filter B2B/B2C : If receiver business type is unknown, // or receiver and carrier are B2B, or receiver and carrier are B2C. return ($boolArgIsReceiverB2B === null || (in_array($this->carrier_type, array('DROPOFFPOINT', 'DEPOT'))) || ($boolArgIsReceiverB2B === true && $this->carrier_type === 'ENTERPRISE') || ($boolArgIsReceiverB2B === false && $this->carrier_type === 'INDIVIDUAL') ); } /** * Get the maximum package weight. * * @return float */ public function getMaxPackageWeight() { TNTOfficiel_Logstack::log(); if (in_array($this->carrier_type, array('ENTERPRISE', 'DEPOT'))) { return 30.0; } // INDIVIDUAL, DROPOFFPOINT. return 20.0; } /** * Update the hard to reach areas zipcode list. * * @return boolean */ public static function updateHRAZipCodeList() { TNTOfficiel_Logstack::log(); $strFileLocation = _PS_MODULE_DIR_.TNTOfficiel::MODULE_NAME.TNTOfficielCarrier::PATH_HRA_JSON; $arrResult = TNTOfficiel_Tools::cURLRequest( TNTOfficielCarrier::URL_HRA_JSON, array( CURLOPT_HTTPHEADER => array( 'User-Agent: PHP/cURL', 'Accept: application/json', 'Connection: close', ), ) ); $arrResponse = Tools::jsonDecode($arrResult['response'], true); if (is_array($arrResponse) && array_key_exists('default', $arrResponse)) { return file_put_contents($strFileLocation, $arrResult['response']) > 0; } return false; } /** * Get the hard to reach areas zipcode list, if it was downloaded. * * @return array|null null if file unexist. */ public static function getHRAZipCodeList() { TNTOfficiel_Logstack::log(); $strFileLocation = _PS_MODULE_DIR_.TNTOfficiel::MODULE_NAME.TNTOfficielCarrier::PATH_HRA_JSON; if (file_exists($strFileLocation)) { $strFileContent = Tools::file_get_contents($strFileLocation); if ($strFileContent !== false) { $arrFileContent = Tools::jsonDecode($strFileContent, true); if (array_key_exists('default', $arrFileContent)) { return $arrFileContent['default']; } } } return null; } /** * Check if a zipcode match the hard to reach areas. * * @param type $strArgZipCode * * @return type */ public static function isAnHRAZipCode($strArgZipCode) { TNTOfficiel_Logstack::log(); $arrHRAZipcodeList = TNTOfficielCarrier::getHRAZipCodeList(); return is_array($arrHRAZipcodeList) && in_array($strArgZipCode, $arrHRAZipcodeList, true); } /** * Get list including estimated delivery date. * * @param string $strArgReceiverZipCode * @param string $strArgReceiverCity * * @return string|null */ public function feasibilities($strArgReceiverZipCode, $strArgReceiverCity) { TNTOfficiel_Logstack::log(); $objTNTCarrierAccountModel = $this->getTNTAccountModel(); // If no account available for this carrier. if ($objTNTCarrierAccountModel === null) { return null; } $arrTNTServiceList = $objTNTCarrierAccountModel->feasibilities( $strArgReceiverZipCode, $strArgReceiverCity, array($this->carrier_type) ); $arrFeasibilitiesList = array(); foreach ($arrTNTServiceList as $arrTNTService) { if ($this->account_type === $arrTNTService['accountType'] && $this->carrier_type === $arrTNTService['carrierType'] && $this->carrier_code1 === $arrTNTService['carrierCode1'] && $this->carrier_code2 === $arrTNTService['carrierCode2'] ) { $arrFeasibilitiesList[] = array( 'shippingDate' => $arrTNTService['shippingDate'], 'dueDate' => $arrTNTService['dueDate'], 'saturdayDelivery' => (bool)$arrTNTService['saturdayDelivery'], 'afternoonDelivery' => (bool)$arrTNTService['afternoonDelivery'], 'insurance' => (bool)$arrTNTService['insurance'], 'priorityGuarantee' => (bool)$arrTNTService['priorityGuarantee'] ); } } return $arrFeasibilitiesList; } /** * Get the estimated delivery date. * * @param string $strArgReceiverZipCode * @param string $strArgReceiverCity * * @return array|null */ public function feasibility( $strArgReceiverZipCode, $strArgReceiverCity, $strArgShippingDate = null ) { TNTOfficiel_Logstack::log(); $objTNTCarrierAccountModel = $this->getTNTAccountModel(); // If no account available for this carrier. if ($objTNTCarrierAccountModel === null) { return null; } $arrTNTServiceList = $objTNTCarrierAccountModel->feasibility( $strArgReceiverZipCode, $strArgReceiverCity, $strArgShippingDate, array($this->carrier_type) ); $arrFeasibilityList = array(); foreach ($arrTNTServiceList as $arrTNTService) { if ($this->account_type === $arrTNTService['accountType'] && $this->carrier_type === $arrTNTService['carrierType'] && $this->carrier_code1 === $arrTNTService['carrierCode1'] && $this->carrier_code2 === $arrTNTService['carrierCode2'] ) { $arrFeasibilityList[] = array( 'shippingDate' => $arrTNTService['shippingDate'], 'dueDate' => $arrTNTService['dueDate'], 'saturdayDelivery' => (bool)$arrTNTService['saturdayDelivery'], 'afternoonDelivery' => (bool)$arrTNTService['afternoonDelivery'], 'insurance' => (bool)$arrTNTService['insurance'], 'priorityGuarantee' => (bool)$arrTNTService['priorityGuarantee'] ); } } return $arrFeasibilityList; } /** * Get delivery points list. * Only available in for carrier type DROPOFFPOINT or DEPOT. * * @param $strArgReceiverZipCode * @param $strArgReceiverCity * * @return array|null */ public function getDeliveryPoints($strArgReceiverZipCode, $strArgReceiverCity) { TNTOfficiel_Logstack::log(); $objTNTCarrierAccountModel = $this->getTNTAccountModel(); // If no account available for this carrier. if ($objTNTCarrierAccountModel === null) { return null; } $arrResultDeliveryPoints = null; if ($this->carrier_type === 'DROPOFFPOINT') { // Get an Estimated delivery date from the carrier selected in cart. $strArgEDD = null; $arrFeasibilitiesList = $this->feasibilities($strArgReceiverZipCode, $strArgReceiverCity); foreach ($arrFeasibilitiesList as $arrFeasibility) { $strArgEDD = $arrFeasibility['dueDate']; break; } // Call WS to get list of delivery points. $arrResultDeliveryPoints = $objTNTCarrierAccountModel->dropOffPoints( $strArgReceiverZipCode, $strArgReceiverCity, $strArgEDD ); } elseif ($this->carrier_type === 'DEPOT') { // Call WS to get list of delivery points $arrResultDeliveryPoints = $objTNTCarrierAccountModel->tntDepots( $strArgReceiverZipCode, $strArgReceiverCity ); } return $arrResultDeliveryPoints; } /** * @return boolean */ public function isZonesEnabled() { TNTOfficiel_Logstack::log(); return (bool)$this->zones_enabled; } /** * @param boolean $zones_enabled */ public function setZonesEnabled($zones_enabled) { TNTOfficiel_Logstack::log(); $this->zones_enabled = (bool)$zones_enabled; return $this->save(); } /** * @return boolean */ public function isZonesCloningEnabled() { TNTOfficiel_Logstack::log(); return $this->zones_cloning_enabled; } /** * @param $zones__cloning_enabled */ public function setZonesCloningEnabled($zones_cloning_enabled) { TNTOfficiel_Logstack::log(); $this->zones_cloning_enabled = $zones_cloning_enabled; return $this->save(); } /** * Get all zones configuration or the specified one if exist. * * @param int $intArgZoneConfID * * @return array|null */ public function getZonesConf($intArgZoneConfID = null) { TNTOfficiel_Logstack::log(); $arrZonesConfList = Tools::unSerialize($this->zones_config); if (!is_array($arrZonesConfList)) { $arrZoneConfDefault = array ( 'strRangeType' => 'weight', 'arrRangeWeightList' => array (), 'fltRangeWeightPricePerKg' => 0.0, 'fltRangeWeightLimitMax' => 0.0, 'arrRangePriceList' => array (), 'strOutOfRangeBehavior' => 'lastrange', 'fltHRAAdditionalCost' => 0.0, 'fltMarginPercent' => 0.0, ); $arrZonesConfList = array( $arrZoneConfDefault, $arrZoneConfDefault, $arrZoneConfDefault, ); } // If the zone ID is specified. if ($intArgZoneConfID !== null) { // If found. if (array_key_exists($intArgZoneConfID, $arrZonesConfList)) { // Get it. return $arrZonesConfList[$intArgZoneConfID]; } // Not found. return array(); } // All Zones return $arrZonesConfList; } /** * Save a zone configuration. * * @param int $intArgZoneConfID * @param array $arrArgZoneConf * * @return bool */ private function saveZoneConf($intArgZoneConfID, $arrArgZoneConf) { TNTOfficiel_Logstack::log(); $arrZonesConfList = $this->getZonesConf(); $arrZonesConfList[$intArgZoneConfID] = $arrArgZoneConf; // Filtering zones index. $arrZonesConfListSave = array_intersect_key( $arrZonesConfList, array(array(), array(), array()) ); $this->zones_config = serialize($arrZonesConfListSave); return $this->save(); } /** * Check if a zone is configured using a minimum of one limit in corresponding range type. * * @param int $intArgZoneConfID * * @return bool */ public function isZoneConfigured($intArgZoneConfID) { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intArgZoneConfID); if ($this->isZoneRangeByWeight($intArgZoneConfID) && is_array($arrZoneConf) && array_key_exists('arrRangeWeightList', $arrZoneConf) && is_array($arrZoneConf['arrRangeWeightList']) && count($arrZoneConf['arrRangeWeightList']) > 0 ) { return true; } if (!$this->isZoneRangeByWeight($intArgZoneConfID) && is_array($arrZoneConf) && array_key_exists('arrRangePriceList', $arrZoneConf) && is_array($arrZoneConf['arrRangePriceList']) && count($arrZoneConf['arrRangePriceList']) > 0 ) { return true; } return false; } /** * * @param int $intArgZoneConfID * @param string $strArgRangeType * * @return bool */ public function setZoneRangeType($intArgZoneConfID, $strArgRangeType = 'weight') { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intArgZoneConfID); $strRangeType = 'price'; if ($strArgRangeType === 'weight') { $strRangeType = 'weight'; } $arrZoneConf['strRangeType'] = $strRangeType; return $this->saveZoneConf($intArgZoneConfID, $arrZoneConf); } /** * * @param int $intArgZoneConfID * * @return bool */ public function isZoneRangeByWeight($intArgZoneConfID) { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intArgZoneConfID); if (is_array($arrZoneConf) && array_key_exists('strRangeType', $arrZoneConf) && $arrZoneConf['strRangeType'] === 'weight' ) { return true; } return false; } /** * * @param int $intArgZoneConfID * @param array $arrArgRangeWeightList * @param float $fltArgRangeWeightPricePerKg * @param float $fltArgRangeWeightLimitMax * * @return bool */ public function setZoneRangeWeightList( $intArgZoneConfID, array $arrArgRangeWeightList = array(), $fltArgRangeWeightPricePerKg = 0.0, $fltArgRangeWeightLimitMax = 0.0 ) { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intArgZoneConfID); $arrRangeWeightList = array(); foreach ($arrArgRangeWeightList as $key => &$value) { $arrRangeWeightList[(string)$key] = (float)$value; } $arrZoneConf['arrRangeWeightList'] = $arrRangeWeightList; $arrZoneConf['fltRangeWeightPricePerKg'] = (float)$fltArgRangeWeightPricePerKg; $arrZoneConf['fltRangeWeightLimitMax'] = (float)$fltArgRangeWeightLimitMax; return $this->saveZoneConf($intArgZoneConfID, $arrZoneConf); } /** * * @param int $intArgZoneConfID * @param float $fltArgCartWeight * * @return float|false false if disabled. */ public function getZoneRangeWeightCost($intArgZoneConfID, $fltArgCartWeight) { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intArgZoneConfID); $arrRangeWeightList = $arrZoneConf['arrRangeWeightList']; $fltRangeWeightPricePerKg = $arrZoneConf['fltRangeWeightPricePerKg']; $fltRangeWeightLimitMax = $arrZoneConf['fltRangeWeightLimitMax']; $fltWeightCost = 0.0; $strFltRangeLimitMatch = (string)-1; $strFltRangeLimitLast = (string)-1; $strFltRangeLimitWeight = (string)-1; $fltRangeLimitCost = 0; foreach ($arrRangeWeightList as $strFltRangeLimitWeight => $fltRangeLimitCost) { if ($strFltRangeLimitMatch == -1 && $fltArgCartWeight <= $strFltRangeLimitWeight) { $strFltRangeLimitMatch = (string)$strFltRangeLimitWeight; } $strFltRangeLimitLast = (string)$strFltRangeLimitWeight; } // If no max limit defined, but there is a price per kg. if (!($fltRangeWeightLimitMax > 0) && $fltRangeWeightPricePerKg > 0) { // Max limit is set to the cart weight, to keep usage of the price per kg. $fltRangeWeightLimitMax = $fltArgCartWeight; } // If max defined and is greater than last limit. if ($fltRangeWeightLimitMax > $strFltRangeLimitLast) { while (++$strFltRangeLimitWeight <= $fltRangeWeightLimitMax) { $fltRangeLimitCost += $fltRangeWeightPricePerKg; // Extending range. $arrRangeWeightList[(string)$strFltRangeLimitWeight] = $fltRangeLimitCost; if ($strFltRangeLimitMatch == -1 && $fltArgCartWeight <= $strFltRangeLimitWeight) { $strFltRangeLimitMatch = (string)$strFltRangeLimitWeight; } } $strFltRangeLimitLast = (string)$fltRangeWeightLimitMax; // Termination. if (!array_key_exists((string)$fltRangeWeightLimitMax, $arrRangeWeightList)) { $fltRangeLimitCost += $fltRangeWeightPricePerKg; $arrRangeWeightList[(string)$fltRangeWeightLimitMax] = $fltRangeLimitCost; if ($strFltRangeLimitMatch == -1 && $fltArgCartWeight <= $fltRangeWeightLimitMax) { $strFltRangeLimitMatch = (string)$fltRangeWeightLimitMax; } } } // Range match. if (array_key_exists($strFltRangeLimitMatch, $arrRangeWeightList)) { $fltWeightCost = $arrRangeWeightList[$strFltRangeLimitMatch]; } TNTOfficiel_Logstack::dump(array( 'id_carrier' => $this->id_carrier, 'intArgZoneConfID' => $intArgZoneConfID, 'fltArgCartWeight' => $fltArgCartWeight, 'arrRangeWeightList' => $arrRangeWeightList, 'fltRangeLimitMatch' => $strFltRangeLimitMatch, 'fltRangeLimitLast' => $strFltRangeLimitLast, 'fltWeightCost' => $fltWeightCost, 'boolIsOutOfRange' => ($strFltRangeLimitLast == -1 || ($fltArgCartWeight > $strFltRangeLimitLast)) )); // Out of range. if ($strFltRangeLimitLast == -1 || ($fltArgCartWeight > $strFltRangeLimitLast)) { if ($this->isZoneOutOfRangeDisabled($intArgZoneConfID)) { // Carrier is disabled. return false; } else { // Use the last limit. if (array_key_exists($strFltRangeLimitLast, $arrRangeWeightList)) { $fltWeightCost = $arrRangeWeightList[$strFltRangeLimitLast]; } } } return $fltWeightCost; } /** * * @param int $intArgZoneConfID * @param array $arrArgRangePriceList * * @return bool */ public function setZoneRangePriceList( $intArgZoneConfID, array $arrArgRangePriceList = array() ) { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intArgZoneConfID); $arrRangePriceList = array(); foreach ($arrArgRangePriceList as $key => &$value) { $arrRangePriceList[(string)$key] = (float)$value; } $arrZoneConf['arrRangePriceList'] = $arrRangePriceList; return $this->saveZoneConf($intArgZoneConfID, $arrZoneConf); } /** * * @param int $intArgZoneConfID * @param float $fltArgCartPrice * * @return float|false false if disabled. */ public function getZoneRangePriceCost($intArgZoneConfID, $fltArgCartPrice) { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intArgZoneConfID); $arrRangePriceList = $arrZoneConf['arrRangePriceList']; $fltPriceCost = 0.0; $strFltRangeLimitMatch = (string)-1; $strFltRangeLimitLast = (string)-1; foreach ($arrRangePriceList as $strFltRangeLimitPrice => $fltRangeLimitCost) { if ($strFltRangeLimitMatch == -1 && $fltArgCartPrice < $strFltRangeLimitPrice) { $strFltRangeLimitMatch = (string)$strFltRangeLimitPrice; } $strFltRangeLimitLast = (string)$strFltRangeLimitPrice; } // Range match. if (array_key_exists($strFltRangeLimitMatch, $arrRangePriceList)) { $fltPriceCost = $arrRangePriceList[$strFltRangeLimitMatch]; } TNTOfficiel_Logstack::dump(array( 'id_carrier' => $this->id_carrier, 'intArgZoneConfID' => $intArgZoneConfID, 'fltArgCartPrice' => $fltArgCartPrice, 'arrRangePriceList' => $arrRangePriceList, 'fltRangeLimitMatch' => $strFltRangeLimitMatch, 'fltRangeLimitLast' => $strFltRangeLimitLast, 'fltPriceCost' => $fltPriceCost, 'boolIsOutOfRange' => ($strFltRangeLimitLast == -1 || ($fltArgCartPrice > $strFltRangeLimitLast)) )); // Out of range. if ($strFltRangeLimitLast == -1 || ($fltArgCartPrice >= $strFltRangeLimitLast)) { if ($this->isZoneOutOfRangeDisabled($intArgZoneConfID)) { // Carrier is disabled. return false; } else { if (array_key_exists($strFltRangeLimitLast, $arrRangePriceList)) { $fltPriceCost = $arrRangePriceList[$strFltRangeLimitLast]; } } } return $fltPriceCost; } /** * Set a zone configuration out of range behavior. * * @param int $intArgZoneConfID * @param string $strArgOutOfRangeBehavior * * @return bool */ public function setZoneOutOfRangeBehavior($intArgZoneConfID, $strArgOutOfRangeBehavior = 'lastrange') { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intArgZoneConfID); $strOutOfRangeBehavior = 'disabled'; if ($strArgOutOfRangeBehavior === 'lastrange') { $strOutOfRangeBehavior = 'lastrange'; } $arrZoneConf['strOutOfRangeBehavior'] = $strOutOfRangeBehavior; return $this->saveZoneConf($intArgZoneConfID, $arrZoneConf); } /** * * @param int $intZoneConfID * * @return bool */ public function isZoneOutOfRangeDisabled($intZoneConfID) { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intZoneConfID); if (is_array($arrZoneConf) && array_key_exists('strOutOfRangeBehavior', $arrZoneConf) && $arrZoneConf['strOutOfRangeBehavior'] === 'lastrange' ) { return false; } return true; } /** * * @param int $intArgZoneConfID * @param float $fltArgHRAAdditionalCost * * @return bool */ public function setZoneHRAAdditionalCost($intArgZoneConfID, $fltArgHRAAdditionalCost) { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intArgZoneConfID); $fltHRAAdditionalCost = 0.0; if ($fltArgHRAAdditionalCost > 0.0) { $fltHRAAdditionalCost = $fltArgHRAAdditionalCost; } $arrZoneConf['fltHRAAdditionalCost'] = $fltHRAAdditionalCost; return $this->saveZoneConf($intArgZoneConfID, $arrZoneConf); } /** * * @param int $intArgZoneConfID * * @return float */ public function getZoneHRAAdditionalCost($intArgZoneConfID) { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intArgZoneConfID); if (is_array($arrZoneConf) && array_key_exists('fltHRAAdditionalCost', $arrZoneConf) && $arrZoneConf['fltHRAAdditionalCost'] > 0.0 ) { return $arrZoneConf['fltHRAAdditionalCost']; } return 0.0; } /** * * @param int $intArgZoneConfID * @param float $fltArgMarginPercent * * @return bool */ public function setZoneMarginPercent($intArgZoneConfID, $fltArgMarginPercent) { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intArgZoneConfID); $fltMarginPercent = 0.0; if ($fltArgMarginPercent > 0.0) { $fltMarginPercent = $fltArgMarginPercent; } $arrZoneConf['fltMarginPercent'] = $fltMarginPercent; return $this->saveZoneConf($intArgZoneConfID, $arrZoneConf); } /** * * @param int $intArgZoneConfID * * @return float */ public function getZoneMarginPercent($intArgZoneConfID) { TNTOfficiel_Logstack::log(); $arrZoneConf = $this->getZonesConf($intArgZoneConfID); if (is_array($arrZoneConf) && array_key_exists('fltMarginPercent', $arrZoneConf) && $arrZoneConf['fltMarginPercent'] > 0.0 ) { return $arrZoneConf['fltMarginPercent']; } return 0.0; } /** * * @return real|false|null false if carrier is not available, null if must use native Prestashop configuration. */ public function getPrice($fltArgCartWeight, $fltArgCartPrice, $intArgAddressIDDelivery = null) { TNTOfficiel_Logstack::log(); if (!$this->zones_enabled) { // Use Prestashop configuration. return null; } $objTNTCarrierAccountModel = $this->getTNTAccountModel(); if ($objTNTCarrierAccountModel === null) { // Use Prestashop configuration. return null; } // Default Zone. $intZoneConfID = 0; $boolIsAnHRAZipCode = false; $objPSAddressDelivery = TNTOfficielReceiver::getPSAddress($intArgAddressIDDelivery); // If delivery address object is available. if ($objPSAddressDelivery !== null) { $strReceiverZipCode = $objPSAddressDelivery->postcode; $intZoneConfID = $objTNTCarrierAccountModel->getZipCodeZone($strReceiverZipCode); $boolIsAnHRAZipCode = $this->isAnHRAZipCode($strReceiverZipCode); } // If matching zone is not configured. if (!$this->isZoneConfigured($intZoneConfID)) { // Use default zone. $intZoneConfID = 0; } if ($this->isZoneRangeByWeight($intZoneConfID)) { $fltPrice = $this->getZoneRangeWeightCost($intZoneConfID, $fltArgCartWeight); } else { $fltPrice = $this->getZoneRangePriceCost($intZoneConfID, $fltArgCartPrice); } // Disabled. if ($fltPrice === false) { // Carrier is disabled. return false; } // Add HRA Additional cost only for non free shipping. if ($boolIsAnHRAZipCode && $fltPrice > 0.0) { $fltPrice += $this->getZoneHRAAdditionalCost($intZoneConfID); } // Add Margin. $fltPrice += ($this->getZoneMarginPercent($intZoneConfID) * $fltPrice / 100.0); return $fltPrice; } }