493 lines
17 KiB
PHP
493 lines
17 KiB
PHP
|
<?php
|
|||
|
/**
|
|||
|
* TNT OFFICIAL MODULE FOR PRESTASHOP.
|
|||
|
*
|
|||
|
* @author GFI Informatique <www.gfi.fr>
|
|||
|
* @copyright 2016-2017 GFI Informatique, 2016-2017 TNT
|
|||
|
* @license https://opensource.org/licenses/MIT MIT License
|
|||
|
*/
|
|||
|
|
|||
|
require_once _PS_MODULE_DIR_.'tntofficiel/tntofficiel.php';
|
|||
|
require_once _PS_MODULE_DIR_.'tntofficiel/classes/TNTOfficielCart.php';
|
|||
|
require_once _PS_MODULE_DIR_.'tntofficiel/libraries/TNTOfficiel_Debug.php';
|
|||
|
require_once _PS_MODULE_DIR_.'tntofficiel/libraries/TNTOfficiel_Parcel.php';
|
|||
|
require_once _PS_MODULE_DIR_.'tntofficiel/libraries/TNTOfficiel_SoapClient.php';
|
|||
|
require_once _PS_MODULE_DIR_.'tntofficiel/libraries/helper/TNTOfficiel_OrderHelper.php';
|
|||
|
require_once _PS_MODULE_DIR_.'tntofficiel/libraries/exceptions/TNTOfficiel_MaxPackageWeightException.php';
|
|||
|
|
|||
|
class TNTOfficiel_ParcelsHelper
|
|||
|
{
|
|||
|
/** @var TNTOfficiel_ParcelsHelper */
|
|||
|
private static $_instance = null;
|
|||
|
|
|||
|
/**
|
|||
|
* Constructor.
|
|||
|
*/
|
|||
|
public function __construct()
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Creates a singleton.
|
|||
|
*
|
|||
|
* @param void
|
|||
|
*
|
|||
|
* @return TNTOfficiel_ParcelsHelper
|
|||
|
*/
|
|||
|
public static function getInstance()
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
if (is_null(TNTOfficiel_ParcelsHelper::$_instance)) {
|
|||
|
TNTOfficiel_ParcelsHelper::$_instance = new TNTOfficiel_ParcelsHelper();
|
|||
|
}
|
|||
|
|
|||
|
return TNTOfficiel_ParcelsHelper::$_instance;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Creates the parcels for an order.
|
|||
|
*
|
|||
|
* @param $objCart
|
|||
|
* @param $intArgOrderID
|
|||
|
*
|
|||
|
* @return bool
|
|||
|
*/
|
|||
|
public function createParcels($objCart, $intArgOrderID)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
$orderedProducts = $this->_getProductsOrderedByWeight($objCart->getProducts());
|
|||
|
$fltMaxParcelWeight = $this->_getMaxPackageWeight($intArgOrderID);
|
|||
|
$parcels = array();
|
|||
|
$parcel = new TNTOfficiel_Parcel();
|
|||
|
foreach ($orderedProducts as $product) {
|
|||
|
$productQuantity = $product['quantity'];
|
|||
|
for ($i = 0; $i < $productQuantity; ++$i) {
|
|||
|
//check if parcel's weight exceeds the maximum parcel weight
|
|||
|
//and remove the last added product in the parcel if it's not the only product in it
|
|||
|
if (($parcel->getWeight() + $product['weight']) <= $fltMaxParcelWeight) {
|
|||
|
$parcel->addProduct($product);
|
|||
|
} else {
|
|||
|
$parcels[] = $parcel;
|
|||
|
$parcel = new TNTOfficiel_Parcel();
|
|||
|
$parcel->addProduct($product);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
//if the parcels contains at least one product we add it to the list
|
|||
|
if (count($parcel->getProductList())) {
|
|||
|
$parcels[] = $parcel;
|
|||
|
}
|
|||
|
|
|||
|
//save the parcels
|
|||
|
$this->_saveParcels($parcels, $intArgOrderID);
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Order a list of products by weight.
|
|||
|
*
|
|||
|
* @param $products
|
|||
|
*
|
|||
|
* @return array
|
|||
|
*/
|
|||
|
private function _getProductsOrderedByWeight($products)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
usort($products, array(__CLASS__, 'compareProductByWeight'));
|
|||
|
|
|||
|
return $products;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Compare two products by their weight.
|
|||
|
*
|
|||
|
* @param $productA
|
|||
|
* @param $productB
|
|||
|
*
|
|||
|
* @return int
|
|||
|
*/
|
|||
|
public static function compareProductByWeight($productA, $productB)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
if ($productA['weight'] == $productB['weight']) {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
return ($productA['weight'] < $productB['weight']) ? -1 : 1;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Save the parcels in the database.
|
|||
|
*
|
|||
|
* @param $parcels array
|
|||
|
* @param $orderId int
|
|||
|
*/
|
|||
|
private function _saveParcels($parcels, $orderId)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
foreach ($parcels as $parcel) {
|
|||
|
//insert into the parcel table
|
|||
|
$this->addParcel($orderId, $parcel->getWeight(), true);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Get the parcels of an order.
|
|||
|
*
|
|||
|
* @param $orderId int
|
|||
|
*
|
|||
|
* @return array
|
|||
|
*/
|
|||
|
public function getParcels($orderId)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
$sql = 'SELECT * FROM '._DB_PREFIX_.'tntofficiel_order_parcels WHERE id_order ='.(int)$orderId;
|
|||
|
$parcels = Db::getInstance()->executeS($sql);
|
|||
|
|
|||
|
return $parcels;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Remove a parcel.
|
|||
|
*
|
|||
|
* @param $parcelId int
|
|||
|
*
|
|||
|
* @return bool
|
|||
|
*/
|
|||
|
public function removeParcel($parcelId)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
return Db::getInstance()->delete('tntofficiel_order_parcels', 'id_parcel = '.(int)$parcelId);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Add a parcel.
|
|||
|
*
|
|||
|
* @param $intArgOrderID int
|
|||
|
* @param $fltArgWeight float
|
|||
|
* @param $isOrderCreation
|
|||
|
*
|
|||
|
* @return array
|
|||
|
*
|
|||
|
* @throws TNTOfficiel_MaxPackageWeightException
|
|||
|
*/
|
|||
|
public function addParcel($intArgOrderID, $fltArgWeight, $isOrderCreation = true)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
$fltMaxPackageWeight = $this->_getMaxPackageWeight($intArgOrderID);
|
|||
|
//Does not throw an exception when this is an order creation
|
|||
|
//the parcel can contains one product which weight exceeds the maximum weight
|
|||
|
if ((float)$fltArgWeight > $fltMaxPackageWeight && !$isOrderCreation) {
|
|||
|
throw new TNTOfficiel_MaxPackageWeightException('Le poids d\'un colis ne peut dépasser '.$fltMaxPackageWeight.'Kg');
|
|||
|
}
|
|||
|
|
|||
|
Db::getInstance()->insert('tntofficiel_order_parcels', array(
|
|||
|
'id_order' => (int)$intArgOrderID,
|
|||
|
'weight' => max(round((float)$fltArgWeight, 1, PHP_ROUND_HALF_UP), 0.1),
|
|||
|
));
|
|||
|
$sql = 'SELECT * FROM '._DB_PREFIX_.'tntofficiel_order_parcels WHERE id_parcel ='.Db::getInstance()->Insert_ID();
|
|||
|
|
|||
|
return Db::getInstance()->executeS($sql);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Update a parcel.
|
|||
|
*
|
|||
|
* @param $parcelId int
|
|||
|
* @param $weight float
|
|||
|
* @param $intArgOrderID int
|
|||
|
*
|
|||
|
* @return bool
|
|||
|
*
|
|||
|
* @throws TNTOfficiel_MaxPackageWeightException
|
|||
|
*/
|
|||
|
public function updateParcel($parcelId, $weight, $intArgOrderID)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
$fltMaxPackageWeight = $this->_getMaxPackageWeight($intArgOrderID);
|
|||
|
if ((float)$weight > $fltMaxPackageWeight) {
|
|||
|
throw new TNTOfficiel_MaxPackageWeightException('Le poids d\'un colis ne peut dépasser '.$fltMaxPackageWeight.'Kg');
|
|||
|
}
|
|||
|
$weight = max(round($weight, 1, PHP_ROUND_HALF_UP), 0.1);
|
|||
|
$result = array();
|
|||
|
$result['result'] = Db::getInstance()->update(
|
|||
|
'tntofficiel_order_parcels',
|
|||
|
array('weight' => (float)$weight),
|
|||
|
'id_parcel = '.(int)$parcelId
|
|||
|
);
|
|||
|
$result['weight'] = $weight;
|
|||
|
|
|||
|
return $result;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @param $parcel array
|
|||
|
*
|
|||
|
* @return array
|
|||
|
*/
|
|||
|
public function getTrackingData($parcel)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
$response = $this->_callTntWs($parcel['parcel_number']);
|
|||
|
|
|||
|
$response = (array)$response;
|
|||
|
$returnData = '';
|
|||
|
if (count($response) && isset($response['Parcel'])) {
|
|||
|
$returnData = $response['Parcel'];
|
|||
|
}
|
|||
|
if ($returnData) {
|
|||
|
$this->_savePdl($returnData, $parcel['id_parcel']);
|
|||
|
$returnData = array(
|
|||
|
'history' => $this->_getHistory($returnData),
|
|||
|
'status' => $this->_getStatus($returnData),
|
|||
|
'allStatus' => $this->_getAllStatus($this->_getStatus($returnData)),
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
return $returnData;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Get the maximum package weight for the order.
|
|||
|
*
|
|||
|
* @param $intArgOrderID
|
|||
|
*
|
|||
|
* @return float
|
|||
|
*
|
|||
|
* @throws Exception
|
|||
|
*/
|
|||
|
private function _getMaxPackageWeight($intArgOrderID)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
try {
|
|||
|
$arrTNTOrder = TNTOfficiel_OrderHelper::getInstance()->getOrderData($intArgOrderID);
|
|||
|
$strCarrierCode = $arrTNTOrder['carrier_code'];
|
|||
|
} catch (Exception $objException) {
|
|||
|
|
|||
|
// TODO : Should not happen ! Why using carrier code from cart ??
|
|||
|
|
|||
|
$objContext = Context::getContext();
|
|||
|
$objCart = $objContext->cart;
|
|||
|
$intCartID = (int)$objCart->id;
|
|||
|
|
|||
|
// Load TNT cart info or create a new one for it's ID.
|
|||
|
$objTNTCartModel = TNTOfficielCart::loadCartID($intCartID);
|
|||
|
if(Validate::isLoadedObject($objTNTCartModel)) {
|
|||
|
$strCarrierCode = $objTNTCartModel->carrier_code;
|
|||
|
}
|
|||
|
|
|||
|
// throw $objException;
|
|||
|
|
|||
|
}
|
|||
|
// If carrier code is B2B.
|
|||
|
if (strpos($strCarrierCode, 'ENTERPRISE')) {
|
|||
|
$fltMaxPackageWeight = (float)Configuration::get('TNT_CARRIER_MAX_PACKAGE_B2B');
|
|||
|
} else {
|
|||
|
$fltMaxPackageWeight = (float)Configuration::get('TNT_CARRIER_MAX_PACKAGE_B2C');
|
|||
|
}
|
|||
|
|
|||
|
return $fltMaxPackageWeight;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Call the tnt.
|
|||
|
*
|
|||
|
* @param $parcelNumber
|
|||
|
*
|
|||
|
* @return stdClass
|
|||
|
*/
|
|||
|
private function _callTntWs($parcelNumber)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
$client = new TNTOfficiel_SoapClient();
|
|||
|
$result = $client->trackingByConsignment($parcelNumber);
|
|||
|
|
|||
|
return $result;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Return All Status de display : depends on status -> maximum 5 status.
|
|||
|
*
|
|||
|
* @param $status
|
|||
|
*
|
|||
|
* @return array
|
|||
|
*/
|
|||
|
protected function _getAllStatus($status)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
$statusArray = array(
|
|||
|
1 => TNTOfficiel_ParcelsHelper::translate('Colis chez l’expéditeur'),
|
|||
|
2 => TNTOfficiel_ParcelsHelper::translate('Ramassage du Colis'),
|
|||
|
3 => TNTOfficiel_ParcelsHelper::translate('Acheminement'),
|
|||
|
4 => TNTOfficiel_ParcelsHelper::translate('Livraison en cours'),
|
|||
|
5 => TNTOfficiel_ParcelsHelper::translate('Livré'),
|
|||
|
);
|
|||
|
|
|||
|
switch ($status) {
|
|||
|
case 6:
|
|||
|
$statusArray[5] = TNTOfficiel_ParcelsHelper::translate('Incident');
|
|||
|
break;
|
|||
|
case 7:
|
|||
|
$statusArray[5] = TNTOfficiel_ParcelsHelper::translate("Retourné à l'expéditeur");
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return $statusArray;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @param $parcel
|
|||
|
*
|
|||
|
* @return bool|int
|
|||
|
*/
|
|||
|
protected function _getStatus($parcel)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
$parcel = (array)$parcel;
|
|||
|
$statusLabel = isset($parcel['shortStatus']) ? $parcel['shortStatus'] : false;
|
|||
|
if (!$statusLabel) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
$mapping = array(
|
|||
|
TNTOfficiel_ParcelsHelper::translate('En attente') => 1,
|
|||
|
'--' => 2,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('En cours d\'acheminement') => 3,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('En cours de livraison') => 4,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('En agence TNT') => 4,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('Récupéré à l\'agence TNT') => 5,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('Livré') => 5,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('En attente de vos instructions') => 6,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('En attente d\'instructions') => 6,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('En attente d\'instructions') => 6,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('Incident de livraison') => 6,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('Incident intervention') => 6,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('Colis refusé par le destinataire') => 6,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('Livraison reprogrammée') => 6,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('Prise de rendez-vous en cours') => 6,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('Prise de rendez-vous en cours') => 6,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('Problème douane') => 6,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('Enlevé au dépôt') => 3,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('En dépôt restant') => 3,
|
|||
|
TNTOfficiel_ParcelsHelper::translate('Retourné à l\'expéditeur') => 7,
|
|||
|
);
|
|||
|
|
|||
|
return isset($mapping[$statusLabel]) ? $mapping[$statusLabel] : 1;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @param $parcel
|
|||
|
*
|
|||
|
* @return bool
|
|||
|
*/
|
|||
|
protected function _getHistory($parcel)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
if (!$parcel->events) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
$history = array();
|
|||
|
$states = array(1 => 'request', 2 => 'process', 3 => 'arrival', 4 => 'deliveryDeparture', 5 => 'delivery');
|
|||
|
$events = (array)$parcel->events;
|
|||
|
foreach ($states as $idx => $state) {
|
|||
|
if ((isset($events[$state.'Center']) || isset($events[$state.'Date']))
|
|||
|
&& Tools::strlen($events[$state.'Date'])
|
|||
|
) {
|
|||
|
$history[$idx] = array(
|
|||
|
'label' => $this->_getLabel($state),
|
|||
|
'date' => isset($events[$state.'Date']) ? $events[$state.'Date'] : '',
|
|||
|
'center' => isset($events[$state.'Center']) ? $events[$state.'Center'] : '',
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return $history;
|
|||
|
}
|
|||
|
|
|||
|
protected function _getLabel($state)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
$labels = array(
|
|||
|
'request' => TNTOfficiel_ParcelsHelper::translate('Colis chez l’expéditeur'),
|
|||
|
'process' => TNTOfficiel_ParcelsHelper::translate('Ramassage du colis'),
|
|||
|
'arrival' => TNTOfficiel_ParcelsHelper::translate('Acheminement du colis'),
|
|||
|
'deliveryDeparture' => TNTOfficiel_ParcelsHelper::translate('Livraison du colis en cours'),
|
|||
|
'delivery' => TNTOfficiel_ParcelsHelper::translate('Livraison du colis'),
|
|||
|
);
|
|||
|
|
|||
|
return isset($labels[$state]) ? $labels[$state] : '';
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Save the PDL.
|
|||
|
*
|
|||
|
* @param $data
|
|||
|
* @param $parcelId
|
|||
|
*
|
|||
|
* @return bool
|
|||
|
*/
|
|||
|
protected function _savePdl($data, $parcelId)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
$result = false;
|
|||
|
$pdl = $this->_getPdl($data);
|
|||
|
if ($pdl) {
|
|||
|
$result = Db::getInstance()->update('tntofficiel_order_parcels', array('pdl' => pSQL($pdl)), 'id_parcel = '.(int)$parcelId);
|
|||
|
}
|
|||
|
|
|||
|
return $result;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Get POD Url from parcel data.
|
|||
|
*
|
|||
|
* @param $data
|
|||
|
*
|
|||
|
* @return bool|string
|
|||
|
*/
|
|||
|
protected function _getPdl($data)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
$data = (array)$data;
|
|||
|
|
|||
|
return isset($data['primaryPODUrl']) && $data['primaryPODUrl'] ? $data['primaryPODUrl'] :
|
|||
|
(isset($data['secondaryPODUrl']) && $data['secondaryPODUrl'] ? $data['secondaryPODUrl'] : false);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* get translation.
|
|||
|
*
|
|||
|
* @param $string
|
|||
|
*
|
|||
|
* @return string
|
|||
|
*/
|
|||
|
public static function translate($string)
|
|||
|
{
|
|||
|
TNTOfficiel_Debug::log(array('msg' => '>>', 'file' => __FILE__, 'line' => __LINE__));
|
|||
|
|
|||
|
// TODO
|
|||
|
return Translate::getModuleTranslation(TNTOfficiel::MODULE_NAME, $string, 'parcelshelper');
|
|||
|
}
|
|||
|
}
|