1418 lines
61 KiB
PHP
1418 lines
61 KiB
PHP
<?php
|
|
/**
|
|
* TNT OFFICIAL MODULE FOR PRESTASHOP
|
|
*
|
|
* @author GFI Informatique <www.gfi.world>
|
|
* @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 TNTOfficiel_SoapClient
|
|
{
|
|
const URL_OASIS_ROOT = 'http://docs.oasis-open.org/wss/2004/01/';
|
|
// SOAP WSDL URL.
|
|
const URL_WSDL = 'https://www.tnt.fr/service/?wsdl';
|
|
|
|
private $strAccountNumber = null;
|
|
private $strAccountLogin = null;
|
|
private $strAccountPassword = null;
|
|
|
|
/**
|
|
* Prevent Construct.
|
|
*/
|
|
public function __construct($strArgAccountNumber, $strArgAccountLogin, $strArgAccountPassword)
|
|
{
|
|
$this->strAccountNumber = $strArgAccountNumber;
|
|
$this->strAccountLogin = $strArgAccountLogin;
|
|
$this->strAccountPassword = $strArgAccountPassword;
|
|
}
|
|
|
|
/**
|
|
* @param $strArgUserName
|
|
* @param $strArgPassword
|
|
* @param string $strArgPasswordType
|
|
*
|
|
* @return SoapHeader
|
|
*/
|
|
public static function getHeader($strArgUserName, $strArgPassword, $strArgPasswordType = 'PasswordDigest')
|
|
{
|
|
TNTOfficiel_Logstack::log();
|
|
|
|
$strURLOASISROOT = TNTOfficiel_SoapClient::URL_OASIS_ROOT;
|
|
$strElementCreated = '';
|
|
|
|
$intRand = mt_rand();
|
|
if ($strArgPasswordType !== 'PasswordDigest') {
|
|
$strArgPasswordType = 'PasswordText';
|
|
$strNonce = sha1($intRand);
|
|
} else {
|
|
$strTimestamp = gmdate('Y-m-d\TH:i:s\Z');
|
|
$strArgPassword = base64_encode(pack('H*', sha1(
|
|
pack('H*', $intRand).
|
|
pack('a*', $strTimestamp).
|
|
pack('a*', $strArgPassword)
|
|
)));
|
|
$strNonce = base64_encode(pack('H*', $intRand));
|
|
|
|
$strElementCreated = <<<XML
|
|
<wsu:Created xmlns:wsu="${strURLOASISROOT}oasis-200401-wss-wssecurity-utility-1.0.xsd">${strTimestamp}</wsu:Created>
|
|
XML;
|
|
}
|
|
|
|
$strArgUserName = htmlspecialchars($strArgUserName);
|
|
$strArgPassword = htmlspecialchars($strArgPassword);
|
|
|
|
$strXMLSecurityHeader = <<<XML
|
|
<wsse:Security SOAP-ENV:mustUnderstand="1" xmlns:wsse="${strURLOASISROOT}oasis-200401-wss-wssecurity-secext-1.0.xsd">
|
|
<wsse:UsernameToken>
|
|
<wsse:Username>${strArgUserName}</wsse:Username>
|
|
<wsse:Password Type="${strURLOASISROOT}oasis-200401-wss-username-token-profile-1.0#${strArgPasswordType}"
|
|
>${strArgPassword}</wsse:Password>
|
|
<wsse:Nonce EncodingType="${strURLOASISROOT}oasis-200401-wss-soap-message-security-1.0#Base64Binary"
|
|
>${strNonce}</wsse:Nonce>
|
|
${strElementCreated}
|
|
</wsse:UsernameToken>
|
|
</wsse:Security>
|
|
XML;
|
|
|
|
$objSoapHeader = new SoapHeader(
|
|
$strURLOASISROOT.'oasis-200401-wss-wssecurity-secext-1.0.xsd',
|
|
'Security',
|
|
new SoapVar($strXMLSecurityHeader, XSD_ANYXML)
|
|
);
|
|
//$objSoapHeader->mustUnderstand = true;
|
|
|
|
return $objSoapHeader;
|
|
}
|
|
|
|
/**
|
|
* Request a TNT SOAP service.
|
|
*
|
|
* @param string $strArgService
|
|
* @param array $arrArgParams
|
|
* @param string|null $strCacheKey
|
|
* @param int $intArgTTL
|
|
*
|
|
* @return stdClass SOAP Response, null for Communication Error, false for Authentication Error, string for Webservice Error Message.
|
|
*
|
|
* @throws Exception
|
|
*/
|
|
private function request($strArgService, $arrArgParams = array(), $strCacheKey = null, $intArgTTL = 0)
|
|
{
|
|
TNTOfficiel_Logstack::log();
|
|
|
|
$objSoapClient = null;
|
|
$objStdClassResponseSOAP = null;
|
|
$objException = null;
|
|
|
|
$fltRequestTimeStart = microtime(true);
|
|
|
|
// Check if already in cache.
|
|
if (TNTOfficiel_Cache::isStored($strCacheKey)) {
|
|
$objStdClassResponseSOAP = Tools::jsonDecode(TNTOfficiel_Cache::retrieve($strCacheKey), true);
|
|
} else {
|
|
try {
|
|
// Check extension.
|
|
if (!extension_loaded('soap')) {
|
|
throw new Exception(sprintf('PHP SOAP extension is required'));
|
|
}
|
|
|
|
// Set expiration timeout (in seconds).
|
|
ini_set('default_socket_timeout', TNTOfficiel::REQUEST_TIMEOUT);
|
|
|
|
$objSoapClient = new SoapClient(
|
|
TNTOfficiel_SoapClient::URL_WSDL,
|
|
array(
|
|
'soap_version' => SOAP_1_1,
|
|
//'cache_wsdl' => WSDL_CACHE_NONE
|
|
'trace' => true,
|
|
// Throw exceptions on error ?
|
|
//'exceptions' => 1,
|
|
// Compress request and response.
|
|
//'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,
|
|
'stream_context' => stream_context_create(array(
|
|
// Apply for HTTPS and FTPS.
|
|
'ssl' => array(
|
|
// Path to Certificate Authority (CA) bundle.
|
|
'cafile' => _PS_CACHE_CA_CERT_FILE_,
|
|
// Check server peer's certificate authenticity through certification authority (CA) for SSL/TLS.
|
|
'verify_peer' => true,
|
|
// Check server certificate's name against host. PHP 5.6.0+
|
|
'verify_peer_name' => false,
|
|
),
|
|
//'http' => array(),
|
|
/*'https' => array(
|
|
'timeout' => 1,
|
|
// Force IPV4.
|
|
'socket' => array(
|
|
'bindto' => '0:0' // PHP 5.1.0+
|
|
)
|
|
)*/
|
|
)),
|
|
// Proxy.
|
|
//'proxy_host' => '<HOST>',
|
|
//'proxy_port' => 80,
|
|
//'proxy_login' => null,
|
|
//'proxy_password' => null,
|
|
// Set connection timeout (in seconds).
|
|
'connection_timeout' => TNTOfficiel::REQUEST_CONNECTTIMEOUT,
|
|
'user_agent' => 'PHP/SOAP',
|
|
)
|
|
);
|
|
|
|
// Add WS-Security Header
|
|
$objSoapClient->__setSOAPHeaders(TNTOfficiel_SoapClient::getHeader(
|
|
$this->strAccountLogin,
|
|
$this->strAccountPassword,
|
|
'PasswordDigest'
|
|
));
|
|
|
|
// Call.
|
|
$fltRequestTimeStart = microtime(true);
|
|
$objStdClassResponseSOAP = $objSoapClient->__soapCall($strArgService, array($arrArgParams));
|
|
$fltRequestTimeEnd = microtime(true);
|
|
|
|
// Log success.
|
|
TNTOfficiel_Logger::logRequest(
|
|
'SOAP',
|
|
$strArgService,
|
|
true,
|
|
($fltRequestTimeEnd - $fltRequestTimeStart),
|
|
$this->strAccountNumber
|
|
);
|
|
|
|
// Cache.
|
|
if (is_string($strCacheKey)) {
|
|
TNTOfficiel_Cache::store($strCacheKey, Tools::jsonEncode($objStdClassResponseSOAP), $intArgTTL);
|
|
}
|
|
} catch (Exception $objException) {
|
|
$fltRequestTimeEnd = microtime(true);
|
|
// Log error.
|
|
TNTOfficiel_Logger::logRequest(
|
|
'SOAP',
|
|
$strArgService,
|
|
false,
|
|
($fltRequestTimeEnd - $fltRequestTimeStart),
|
|
$this->strAccountNumber.' '
|
|
.((get_class($objException) === 'SoapFault') ? '['.$objException->faultcode .'] ' : '')
|
|
.'Error '.$objException->getCode().': '
|
|
.$objException->getMessage()
|
|
);
|
|
}
|
|
|
|
ini_restore('default_socket_timeout');
|
|
|
|
TNTOfficiel_Logstack::dump(array(
|
|
'URL' => TNTOfficiel_SoapClient::URL_WSDL,
|
|
'Service' => $strArgService,
|
|
'Parameters' => $arrArgParams,
|
|
'Response' => $objStdClassResponseSOAP,
|
|
'ResponseTime' => $fltRequestTimeEnd - $fltRequestTimeStart,
|
|
'SoapFault' => $objException,
|
|
'LastRequestHeaders' => $objSoapClient ? $objSoapClient->__getLastRequestHeaders() : null,
|
|
'LastRequest' => $objSoapClient ? $objSoapClient->__getLastRequest() : null,
|
|
'LastResponseHeaders' => $objSoapClient ? $objSoapClient->__getLastResponseHeaders() : null,
|
|
'LastResponse' => $objSoapClient ? $objSoapClient->__getLastResponse() : null
|
|
));
|
|
}
|
|
|
|
if ($objException !== null) {
|
|
// SoapFault Exception.
|
|
if (get_class($objException) === 'SoapFault') {
|
|
if ($objException->faultcode === 'ns1:FailedAuthentication'
|
|
|| trim($objException->getMessage()) === 'The field \'accountNumber\' is not valid.'
|
|
|| preg_match('/^[0-9]{8}$/ui', $this->strAccountNumber) !== 1
|
|
) {
|
|
// Authentication Error.
|
|
return false;
|
|
} elseif ($objException->faultcode === 'WSDL') {
|
|
// Communication Error (Connection Timeout).
|
|
return null;
|
|
}
|
|
// Webservice Error.
|
|
return trim(preg_replace('/[[:cntrl:]]+/', ' ', $objException->getMessage()));
|
|
}
|
|
// Communication Error.
|
|
return null;
|
|
}
|
|
|
|
return $objStdClassResponseSOAP;
|
|
}
|
|
|
|
/**
|
|
* Check credential validity with authentication.
|
|
* No cache store.
|
|
*
|
|
* @return bool|null
|
|
*/
|
|
public function isCorrectAuthentication()
|
|
{
|
|
TNTOfficiel_Logstack::log();
|
|
|
|
$arrParamRequest = array(
|
|
'parameters' => array(
|
|
'accountNumber' => $this->strAccountNumber,
|
|
'sender' => array(
|
|
'zipCode' => '75001',
|
|
'city' => 'PARIS 01',
|
|
),
|
|
'receiver' => array(
|
|
'zipCode' => '75001',
|
|
'city' => 'PARIS 01',
|
|
'type' => 'INDIVIDUAL',
|
|
),
|
|
'shippingDelay' => 0
|
|
)
|
|
);
|
|
|
|
$objStdClassResponse = $this->request('feasibility', $arrParamRequest);
|
|
|
|
// Communication Error.
|
|
if ($objStdClassResponse === null) {
|
|
return null;
|
|
}
|
|
// Authentication Error.
|
|
if ($objStdClassResponse === false) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get cities from a zipcode.
|
|
* Cleaning PostCode and City Name, then checking City exist for PostCode.
|
|
* cleanNameCity, correctCityForPostCode
|
|
*
|
|
* @param string $strArgZipCode
|
|
* @param string $strArgCity
|
|
*
|
|
* @return array
|
|
*/
|
|
public function citiesGuide($strArgCountryISO, $strArgZipCode, $strArgCity = null)
|
|
{
|
|
TNTOfficiel_Logstack::log();
|
|
|
|
/*
|
|
* Input clean.
|
|
*/
|
|
|
|
$strArgCountryISO = Tools::strtoupper($strArgCountryISO);
|
|
|
|
if (!is_string($strArgZipCode) || preg_match('/^[0-9]{5}$/ui', $strArgZipCode) !== 1) {
|
|
$strArgZipCode = null;
|
|
}
|
|
|
|
if ($strArgZipCode == '75000') {
|
|
$strArgZipCode = '75001';
|
|
} elseif ($strArgZipCode == '69000') {
|
|
$strArgZipCode = '69001';
|
|
} elseif ($strArgZipCode == '13000') {
|
|
$strArgZipCode = '13001';
|
|
}
|
|
|
|
if (is_string($strArgCity) && Tools::strlen($strArgCity) > 0) {
|
|
// Accents.
|
|
$strArgCity = Tools::htmlentitiesUTF8($strArgCity);
|
|
$strArgCity = preg_replace(
|
|
'#&([A-za-z])(?:acute|cedil|caron|circ|grave|orn|ring|slash|th|tilde|uml);#',
|
|
'\1',
|
|
$strArgCity
|
|
);
|
|
$strArgCity = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $strArgCity);
|
|
$strArgCity = preg_replace('#&[^;]+;#', '', $strArgCity);
|
|
|
|
// Special Char.
|
|
$strArgCity = preg_replace('#[^A-Za-z0-9]+#', ' ', $strArgCity);
|
|
// Space.
|
|
$strArgCity = trim($strArgCity);
|
|
// UpperCase.
|
|
$strArgCity = Tools::strtoupper($strArgCity);
|
|
|
|
// Replacing words.
|
|
if ($strArgZipCode != '56110' && $strArgZipCode != '69125') {
|
|
$arrCityWord = explode(' ', $strArgCity);
|
|
foreach ($arrCityWord as $key => $word) {
|
|
$arrCityWord[ $key ] = preg_replace('#^SAINTE$#', 'STE', $arrCityWord[ $key ]);
|
|
$arrCityWord[ $key ] = preg_replace('#^SAINT$#', 'ST', $arrCityWord[ $key ]);
|
|
}
|
|
$strArgCity = implode(' ', $arrCityWord);
|
|
}
|
|
} else {
|
|
$strArgCity = null;
|
|
}
|
|
|
|
/*
|
|
* Output default.
|
|
*/
|
|
|
|
$arrResult = array(
|
|
'boolIsCountrySupported' => false,
|
|
'boolIsRequestComError' => false,
|
|
'strResponseMsgError' => null,
|
|
'strZipCode' => $strArgZipCode,
|
|
'strCity' => $strArgCity,
|
|
'boolIsZipCodeCedex' => false,
|
|
'arrCitiesNamePerZipCodeList' => array(),
|
|
'arrCitiesNameList' => array(),
|
|
'boolIsCityNameValid' => false
|
|
);
|
|
|
|
/*
|
|
* Cache
|
|
*/
|
|
|
|
// Get params (no timestamp).
|
|
$arrParamCache = array(
|
|
'countryISO' => $strArgCountryISO,
|
|
'zipCode' => $strArgZipCode,
|
|
'cityName' => $strArgCity
|
|
);
|
|
$strCacheKey = TNTOfficiel_Cache::getKeyIdentifier(__CLASS__, __FUNCTION__, $arrParamCache);
|
|
$intTTL = TNTOfficiel_Cache::getSecondsUntilMidnight();
|
|
|
|
// Check if already in cache.
|
|
if (TNTOfficiel_Cache::isStored($strCacheKey)) {
|
|
return Tools::jsonDecode(TNTOfficiel_Cache::retrieve($strCacheKey), true);
|
|
}
|
|
|
|
|
|
if ($strArgCountryISO === 'FR') {
|
|
$arrResult['boolIsCountrySupported'] = true;
|
|
|
|
if ($strArgZipCode !== null) {
|
|
$arrParamRequest = array(
|
|
'zipCode' => $strArgZipCode
|
|
);
|
|
$objStdClassResponse = $this->request('citiesGuide', $arrParamRequest);
|
|
} else {
|
|
$objStdClassResponse = false;
|
|
}
|
|
|
|
// Communication error.
|
|
if ($objStdClassResponse === null) {
|
|
$arrResult['boolIsRequestComError'] = true;
|
|
}
|
|
// Webservice response error.
|
|
if (is_string($objStdClassResponse)) {
|
|
$arrResult['strResponseMsgError'] = $objStdClassResponse;
|
|
}
|
|
|
|
//
|
|
if (is_object($objStdClassResponse)
|
|
&& property_exists($objStdClassResponse, 'City')
|
|
) {
|
|
// Convert an item to array of one item
|
|
if (is_object($objStdClassResponse->City)
|
|
&& property_exists($objStdClassResponse->City, 'name')
|
|
&& property_exists($objStdClassResponse->City, 'zipCode')
|
|
) {
|
|
$objStdClassResponse->City = array(
|
|
(object)array(
|
|
'name' => $objStdClassResponse->City->name,
|
|
'zipCode' => $objStdClassResponse->City->zipCode
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
if (is_array($objStdClassResponse->City)
|
|
&& count($objStdClassResponse->City) > 0
|
|
) {
|
|
foreach ($objStdClassResponse->City as $objItem) {
|
|
$arrResult['arrCitiesNamePerZipCodeList'][ $objItem->zipCode ][] = $objItem->name;
|
|
if ($objItem->zipCode === $strArgZipCode && $objItem->name === $strArgCity) {
|
|
$arrResult['boolIsCityNameValid'] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Cedex
|
|
*/
|
|
|
|
if ($strArgZipCode !== null
|
|
&& !array_key_exists($strArgZipCode, $arrResult['arrCitiesNamePerZipCodeList'])
|
|
) {
|
|
$strFileLocation = _PS_MODULE_DIR_.TNTOfficiel::MODULE_NAME.'/libraries/data/postcode/cedex/'.Tools::substr($strArgZipCode, 0, 2).'.json';
|
|
$strFileContent = Tools::file_get_contents($strFileLocation);
|
|
if ($strFileContent !== false) {
|
|
$arrFileContent = Tools::jsonDecode($strFileContent, true);
|
|
if (array_key_exists($strArgZipCode, $arrFileContent)) {
|
|
$arrResult['boolIsZipCodeCedex'] = true;
|
|
foreach ($arrFileContent[$strArgZipCode] as $arrItem) {
|
|
$arrResult['arrCitiesNamePerZipCodeList'][ $strArgZipCode ][] = $arrItem['city'];
|
|
if ($arrItem['city'] === $strArgCity) {
|
|
$arrResult['boolIsCityNameValid'] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (array_key_exists($strArgZipCode, $arrResult['arrCitiesNamePerZipCodeList'])) {
|
|
$arrResult['arrCitiesNameList'] = $arrResult['arrCitiesNamePerZipCodeList'][$strArgZipCode];
|
|
}
|
|
|
|
// If no communication error and no error message.
|
|
if ($objStdClassResponse !== null && !is_string($objStdClassResponse)) {
|
|
// Cache until midnight.
|
|
TNTOfficiel_Cache::store($strCacheKey, Tools::jsonEncode($arrResult), $intTTL);
|
|
}
|
|
}
|
|
|
|
return $arrResult;
|
|
}
|
|
|
|
/**
|
|
* Get dropOffPoints from the zipcode and cityname.
|
|
* Ready for use with estimated delivery date (but unused since WS does not manage it).
|
|
* EDD may be used to exclude delivery points that have a planned temporary closure, or alert user.
|
|
*
|
|
* @param string $strArgZipCode
|
|
* @param string $strArgCity
|
|
* @param string $strArgEDD
|
|
*
|
|
* @return array
|
|
*/
|
|
public function dropOffPoints($strArgZipCode, $strArgCity, $strArgEDD = null)
|
|
{
|
|
TNTOfficiel_Logstack::log();
|
|
|
|
$arrResultCitiesGuide = $this->citiesGuide('FR', $strArgZipCode, $strArgCity);
|
|
// Auto formatting.
|
|
$strZipCode = $arrResultCitiesGuide['strZipCode'];
|
|
$strCity = $arrResultCitiesGuide['strCity'];
|
|
|
|
// Auto-Select
|
|
if (/*$strCity === null*/ !$arrResultCitiesGuide['boolIsCityNameValid']
|
|
&& count($arrResultCitiesGuide['arrCitiesNameList']) > 0
|
|
) {
|
|
$strCity = $arrResultCitiesGuide['arrCitiesNameList'][0];
|
|
$arrResultCitiesGuide['boolIsCityNameValid'] = true;
|
|
}
|
|
|
|
// Date Today.
|
|
$objDateTimeToday = new DateTime('midnight');
|
|
// Date Tomorrow.
|
|
$objDateTimeTomorrow = new DateTime('midnight +1 day');
|
|
// Date In one Month.
|
|
$objDateTime1Month = new DateTime('midnight +1 month');
|
|
|
|
// Default EDD is tomorrow.
|
|
$strEDD = $objDateTimeTomorrow->format('Y-m-d');
|
|
|
|
// Check EDD.
|
|
if ($strArgEDD
|
|
&& preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/ui', $strArgEDD/*, $arrBackRef*/) === 1
|
|
//&& checkdate((int)$arrBackRef[2], (int)$arrBackRef[3], (int)$arrBackRef[1])
|
|
) {
|
|
$objDateTimeEDDCheck = DateTime::createFromFormat('Y-m-d', $strArgEDD);
|
|
if (is_object($objDateTimeEDDCheck)) {
|
|
$objDateTimeEDDCheck->modify('midnight');
|
|
$strEDLCheck = $objDateTimeEDDCheck->format('Y-m-d');
|
|
if ($strArgEDD === $strEDLCheck) {
|
|
$strEDD = $strArgEDD;
|
|
}
|
|
}
|
|
}
|
|
|
|
$objDateTimeEDD = DateTime::createFromFormat('Y-m-d', $strEDD);
|
|
$objDateTimeEDD->modify('midnight');
|
|
$objDateTimeEDD10 = DateTime::createFromFormat('Y-m-d', $strEDD);
|
|
$objDateTimeEDD10->modify('midnight +10 day');
|
|
|
|
|
|
$boolIsRequestComError = false;
|
|
$arrPointsList = array();
|
|
|
|
// Get params (no timestamp).
|
|
$arrParamCache = array(
|
|
'zipCode' => $strZipCode,
|
|
'cityName' => $strCity,
|
|
'EDD' => $strEDD
|
|
);
|
|
$strCacheKey = TNTOfficiel_Cache::getKeyIdentifier(__CLASS__, __FUNCTION__, $arrParamCache);
|
|
$intTTL = TNTOfficiel_Cache::getSecondsUntilMidnight();
|
|
|
|
// Check if already in cache.
|
|
if (TNTOfficiel_Cache::isStored($strCacheKey)) {
|
|
$arrResult = Tools::jsonDecode(TNTOfficiel_Cache::retrieve($strCacheKey), true);
|
|
} else {
|
|
// If zipCode and CityName Valid.
|
|
if ($arrResultCitiesGuide['boolIsCityNameValid']) {
|
|
$arrParamRequest = array(
|
|
'zipCode' => $strZipCode,
|
|
'city' => $strCity
|
|
);
|
|
$objStdClassResponse = $this->request('dropOffPoints', $arrParamRequest);
|
|
} else {
|
|
$objStdClassResponse = false;
|
|
}
|
|
|
|
// Communication error.
|
|
if ($objStdClassResponse === null) {
|
|
$boolIsRequestComError = true;
|
|
}
|
|
|
|
//
|
|
if (is_object($objStdClassResponse)
|
|
&& property_exists($objStdClassResponse, 'DropOffPoint')
|
|
) {
|
|
// Convert an item to array of one item
|
|
if (is_object($objStdClassResponse->DropOffPoint)
|
|
&& property_exists($objStdClassResponse->DropOffPoint, 'xETTCode')
|
|
&& property_exists($objStdClassResponse->DropOffPoint, 'name')
|
|
) {
|
|
$objStdClassResponse->DropOffPoint = array(
|
|
(object)array(
|
|
'xETTCode' => $objStdClassResponse->DropOffPoint->xETTCode,
|
|
'name' => $objStdClassResponse->DropOffPoint->name,
|
|
'address1' => $objStdClassResponse->DropOffPoint->address1,
|
|
'zipCode' => $objStdClassResponse->DropOffPoint->zipCode,
|
|
'city' => $objStdClassResponse->DropOffPoint->city,
|
|
'openingHours' => $objStdClassResponse->DropOffPoint->openingHours,
|
|
'message' => $objStdClassResponse->DropOffPoint->message,
|
|
'geolocationURL' => $objStdClassResponse->DropOffPoint->geolocalisationUrl,
|
|
'longitude' => $objStdClassResponse->DropOffPoint->longitude,
|
|
'latitude' => $objStdClassResponse->DropOffPoint->latitude
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
if (is_array($objStdClassResponse->DropOffPoint)
|
|
&& count($objStdClassResponse->DropOffPoint) > 0
|
|
) {
|
|
foreach ($objStdClassResponse->DropOffPoint as $objDropOffPointInfo) {
|
|
$objDropOffPointOpeningHours = (object)array(
|
|
'Monday' => array(),
|
|
'Tuesday' => array(),
|
|
'Wednesday' => array(),
|
|
'Thursday' => array(),
|
|
'Friday' => array(),
|
|
'Saturday' => array(),
|
|
'Sunday' => array(),
|
|
);
|
|
|
|
foreach ($objDropOffPointInfo->openingHours as $strDay => $objDay) {
|
|
foreach ($objDay as $strAmPm => $strRange) {
|
|
// Formatting : "monday": { "pm": "Fermé" }, "tuesday": { "am": "09:00 - 12:00" },
|
|
// To : "Monday": [], "Tuesday": ["AM": ["09:00", "12:00"]],
|
|
$strDayUpper = Tools::strtoupper(Tools::substr($strDay, 0, 1)).Tools::substr($strDay, 1);
|
|
$strAmPmUpper = Tools::strtoupper($strAmPm);
|
|
if (!in_array($strRange, array('FERME - FERME', 'Fermé'))) {
|
|
$arrRange = explode(' - ', $strRange);
|
|
$objDropOffPointOpeningHours->{$strDayUpper}[$strAmPmUpper] = $arrRange;
|
|
}
|
|
}
|
|
}
|
|
|
|
$objDropOffPointInfo->openingHours = $objDropOffPointOpeningHours;
|
|
|
|
/*
|
|
* Contrainte d'état du relais, date de fermeture et de ré-ouverture.
|
|
*/
|
|
|
|
$strRPState = 'A'; //$objDropOffPointInfo->getState();
|
|
|
|
$strRPDateClosing = ''; //$objDropOffPointInfo->getDateClosing();
|
|
$objRPDateTimeClosing = DateTime::createFromFormat('Ymd', $strRPDateClosing);
|
|
$intRPStampClosing = null;
|
|
if (is_object($objRPDateTimeClosing)) {
|
|
$objRPDateTimeClosing->modify('midnight');
|
|
$strRPDateClosingCheck = $objRPDateTimeClosing->format('Ymd');
|
|
$intRPStampClosing = $objRPDateTimeClosing->format('U');
|
|
}
|
|
if (!is_object($objRPDateTimeClosing) || $strRPDateClosing !== $strRPDateClosingCheck) {
|
|
$objRPDateTimeClosing = DateTime::createFromFormat('U', '0');
|
|
$objRPDateTimeClosing->modify('midnight');
|
|
}
|
|
|
|
$strRPDateReOpening = ''; //$objDropOffPointInfo->getDateReopening();
|
|
$objRPDateTimeReOpening = DateTime::createFromFormat('Ymd', $strRPDateReOpening);
|
|
$intRPStampReOpening = null;
|
|
if (is_object($objRPDateTimeReOpening)) {
|
|
$objRPDateTimeReOpening->modify('midnight');
|
|
$strRPDateReOpeningCheck = $objRPDateTimeReOpening->format('Ymd');
|
|
$intRPStampReOpening = $objRPDateTimeReOpening->format('U');
|
|
}
|
|
if (!is_object($objRPDateTimeReOpening) || $strRPDateReOpening !== $strRPDateReOpeningCheck) {
|
|
$objRPDateTimeReOpening = DateTime::createFromFormat('U', '0');
|
|
$objRPDateTimeReOpening->modify('midnight');
|
|
}
|
|
|
|
$boolRPEnable = false;
|
|
|
|
if (
|
|
(
|
|
// Si Actif
|
|
$strRPState === 'A'
|
|
&& (
|
|
(
|
|
// si la date de reprise est <= à la date de livraison
|
|
$objRPDateTimeReOpening <= $objDateTimeEDD
|
|
// et
|
|
&& (
|
|
// si la date de fin est < à la date de livraison
|
|
$objRPDateTimeClosing < $objDateTimeEDD
|
|
// ou si la date de fin est >= à la date de livraison + 10 jours
|
|
|| $objRPDateTimeClosing >= $objDateTimeEDD10
|
|
)
|
|
)
|
|
|| (
|
|
// Si la date de reprise est >= à la date de fin
|
|
$objRPDateTimeReOpening >= $objRPDateTimeClosing
|
|
// et si la date de fin est >= à la date de livraison + 10 jours
|
|
&& $objRPDateTimeClosing >= $objDateTimeEDD10
|
|
)
|
|
)
|
|
)
|
|
|| (
|
|
// Ou Si Créé ou Réactivé
|
|
($strRPState === 'C' || $strRPState === 'R')
|
|
&& (
|
|
// avec une date de reprise existante
|
|
$strRPDateReOpening !== ''
|
|
// et <= à la date de livraison
|
|
&& $objRPDateTimeReOpening <= $objDateTimeEDD
|
|
)
|
|
)
|
|
) {
|
|
$boolRPEnable = true;
|
|
}
|
|
|
|
|
|
if ($boolRPEnable === true) {
|
|
// Closing Date exist.
|
|
if ($intRPStampClosing !== null) {
|
|
// Check Closing Date Validity.
|
|
// et si la date de fermeture n'est pas expirée,
|
|
// et qu'elle n'est pas plus tard que dans un mois.
|
|
if (is_object($objRPDateTimeClosing)
|
|
&& $objRPDateTimeClosing->format('U') === $intRPStampClosing
|
|
&& $objRPDateTimeClosing > $objDateTimeToday
|
|
&& $objRPDateTimeClosing <= $objDateTime1Month
|
|
) {
|
|
$intRPStampClosing = $objRPDateTimeClosing->format('d/m/Y');
|
|
} else {
|
|
$intRPStampClosing = null;
|
|
}
|
|
}
|
|
|
|
// ReOpening Date exist.
|
|
if ($intRPStampReOpening !== null) {
|
|
// Check ReOpening Date Validity.
|
|
// et si la date de réouverture n'est pas expirée,
|
|
if (is_object($objRPDateTimeReOpening)
|
|
&& $objRPDateTimeReOpening->format('U') === $intRPStampReOpening
|
|
&& $objRPDateTimeReOpening > $objDateTimeToday
|
|
) {
|
|
$intRPStampReOpening = $objRPDateTimeReOpening->format('d/m/Y');
|
|
} else {
|
|
$intRPStampReOpening = null;
|
|
}
|
|
}
|
|
|
|
$arrPointsList[] = array(
|
|
'xett' => $objDropOffPointInfo->xETTCode,
|
|
'name' => $objDropOffPointInfo->name,
|
|
'city' => $objDropOffPointInfo->city,
|
|
'postcode' => $objDropOffPointInfo->zipCode,
|
|
'address' => $objDropOffPointInfo->address1,
|
|
'schedule' => $objDropOffPointInfo->openingHours,
|
|
'latitude' => $objDropOffPointInfo->latitude,
|
|
'longitude' => $objDropOffPointInfo->longitude,
|
|
'enabled' => $boolRPEnable,
|
|
'closing' => $intRPStampClosing,
|
|
'reopening' => $intRPStampReOpening
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$arrResult = array(
|
|
'boolIsRequestComError' => $boolIsRequestComError,
|
|
'strResponseMsgError' => is_string($objStdClassResponse) ? $objStdClassResponse : null,
|
|
'strZipCode' => $strZipCode,
|
|
'strCity' => $strCity,
|
|
'arrCitiesNameList' => $arrResultCitiesGuide['arrCitiesNameList'],
|
|
'arrPointsList' => $arrPointsList
|
|
);
|
|
|
|
// If no communication error and no error message.
|
|
if ($objStdClassResponse !== null && !is_string($objStdClassResponse)) {
|
|
// Cache until midnight.
|
|
TNTOfficiel_Cache::store($strCacheKey, Tools::jsonEncode($arrResult), $intTTL);
|
|
}
|
|
}
|
|
|
|
return $arrResult;
|
|
}
|
|
|
|
/**
|
|
* Get tntDepots from the zipcode and cityname.
|
|
*
|
|
* @param string $strArgZipCode
|
|
* @param string $strArgCity
|
|
* @param string $strArgEDD used only for cache.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function tntDepots($strArgZipCode, $strArgCity, $strArgEDD = null)
|
|
{
|
|
TNTOfficiel_Logstack::log();
|
|
|
|
$arrResultCitiesGuide = $this->citiesGuide('FR', $strArgZipCode, $strArgCity);
|
|
// Auto formatting.
|
|
$strZipCode = $arrResultCitiesGuide['strZipCode'];
|
|
$strCity = $arrResultCitiesGuide['strCity'];
|
|
|
|
// Auto-Select
|
|
if (/*$strCity === null*/ !$arrResultCitiesGuide['boolIsCityNameValid']
|
|
&& count($arrResultCitiesGuide['arrCitiesNameList']) > 0
|
|
) {
|
|
$strCity = $arrResultCitiesGuide['arrCitiesNameList'][0];
|
|
$arrResultCitiesGuide['boolIsCityNameValid'] = true;
|
|
}
|
|
|
|
// Date Tomorrow.
|
|
$objDateTimeTomorrow = new DateTime('midnight +1 day');
|
|
|
|
|
|
// Default EDD is tomorrow..
|
|
$strEDD = $objDateTimeTomorrow->format('Y-m-d');
|
|
|
|
// Check EDD.
|
|
if ($strArgEDD
|
|
&& preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/ui', $strArgEDD/*, $arrBackRef*/) === 1
|
|
//&& checkdate((int)$arrBackRef[2], (int)$arrBackRef[3], (int)$arrBackRef[1])
|
|
) {
|
|
$objDateTimeEDDCheck = DateTime::createFromFormat('Y-m-d', $strArgEDD);
|
|
if (is_object($objDateTimeEDDCheck)) {
|
|
$objDateTimeEDDCheck->modify('midnight');
|
|
$strEDDCheck = $objDateTimeEDDCheck->format('Y-m-d');
|
|
if ($strArgEDD === $strEDDCheck) {
|
|
$strEDD = $strArgEDD;
|
|
}
|
|
}
|
|
}
|
|
|
|
$boolIsRequestComError = false;
|
|
$arrPointsList = array();
|
|
|
|
// Get params (no timestamp).
|
|
$arrParamCache = array(
|
|
'zipCode' => $strZipCode,
|
|
'cityName' => $strCity,
|
|
'EDD' => $strEDD
|
|
);
|
|
$strCacheKey = TNTOfficiel_Cache::getKeyIdentifier(__CLASS__, __FUNCTION__, $arrParamCache);
|
|
$intTTL = TNTOfficiel_Cache::getSecondsUntilMidnight();
|
|
|
|
// Check if already in cache.
|
|
if (TNTOfficiel_Cache::isStored($strCacheKey)) {
|
|
$arrResult = Tools::jsonDecode(TNTOfficiel_Cache::retrieve($strCacheKey), true);
|
|
} else {
|
|
// If zipCode and CityName Valid.
|
|
if ($arrResultCitiesGuide['boolIsCityNameValid']) {
|
|
$arrParamRequest = array(
|
|
'department' => Tools::substr($strZipCode, 0, 2)
|
|
);
|
|
$objStdClassResponse = $this->request('tntDepots', $arrParamRequest);
|
|
} else {
|
|
$objStdClassResponse = false;
|
|
}
|
|
|
|
// Communication error.
|
|
if ($objStdClassResponse === null) {
|
|
$boolIsRequestComError = true;
|
|
}
|
|
|
|
//
|
|
if (is_object($objStdClassResponse)
|
|
&& property_exists($objStdClassResponse, 'DepotInfo')
|
|
) {
|
|
// Convert an item to array of one item
|
|
if (is_object($objStdClassResponse->DepotInfo)
|
|
&& property_exists($objStdClassResponse->DepotInfo, 'pexCode')
|
|
&& property_exists($objStdClassResponse->DepotInfo, 'name')
|
|
) {
|
|
$objStdClassResponse->DepotInfo = array(
|
|
(object)array(
|
|
'pexCode' => $objStdClassResponse->DepotInfo->pexCode,
|
|
'name' => $objStdClassResponse->DepotInfo->name,
|
|
'address1' => $objStdClassResponse->DepotInfo->address1,
|
|
'address2' => $objStdClassResponse->DepotInfo->address2,
|
|
'zipCode' => $objStdClassResponse->DepotInfo->zipCode,
|
|
'city' => $objStdClassResponse->DepotInfo->city,
|
|
'openingHours' => $objStdClassResponse->DepotInfo->openingHours,
|
|
'message' => $objStdClassResponse->DepotInfo->message,
|
|
'geolocationURL' => $objStdClassResponse->DepotInfo->geolocalisationUrl,
|
|
'longitude' => $objStdClassResponse->DepotInfo->longitude,
|
|
'latitude' => $objStdClassResponse->DepotInfo->latitude
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
if (is_array($objStdClassResponse->DepotInfo)
|
|
&& count($objStdClassResponse->DepotInfo) > 0
|
|
) {
|
|
foreach ($objStdClassResponse->DepotInfo as $objDepotInfo) {
|
|
$objDepotInfoOpeningHours = (object)array(
|
|
'Monday' => array(),
|
|
'Tuesday' => array(),
|
|
'Wednesday' => array(),
|
|
'Thursday' => array(),
|
|
'Friday' => array(),
|
|
'Saturday' => array(),
|
|
'Sunday' => array(),
|
|
);
|
|
|
|
foreach ($objDepotInfo->openingHours as $strDay => $objDay) {
|
|
foreach ($objDay as $strAmPm => $strRange) {
|
|
// Formatting : "monday": { "pm": "Fermé" }, "tuesday": { "am": "09:00 - 12:00" },
|
|
// To : "Monday": [], "Tuesday": ["AM": ["09:00", "12:00"]],
|
|
$strDayUpper = Tools::strtoupper(Tools::substr($strDay, 0, 1)).Tools::substr($strDay, 1);
|
|
$strAmPmUpper = Tools::strtoupper($strAmPm);
|
|
if (!in_array($strRange, array('FERME - FERME', 'Fermé'))) {
|
|
$arrRange = explode(' - ', $strRange);
|
|
$objDepotInfoOpeningHours->{$strDayUpper}[$strAmPmUpper] = $arrRange;
|
|
}
|
|
}
|
|
}
|
|
|
|
$objDepotInfo->openingHours = $objDepotInfoOpeningHours;
|
|
if (!property_exists($objDepotInfo, 'address2')) {
|
|
$objDepotInfo->address2 = '';
|
|
}
|
|
|
|
$arrPointsList[] = array(
|
|
'pex' => $objDepotInfo->pexCode,
|
|
'name' => $objDepotInfo->name,
|
|
'city' => $objDepotInfo->city,
|
|
'postcode' => $objDepotInfo->zipCode,
|
|
'address1' => $objDepotInfo->address1,
|
|
'address2' => $objDepotInfo->address2,
|
|
'schedule' => $objDepotInfo->openingHours,
|
|
'latitude' => $objDepotInfo->latitude,
|
|
'longitude' => $objDepotInfo->longitude,
|
|
'enabled' => true,
|
|
'closing' => null,
|
|
'reopening' => null
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
$arrResult = array(
|
|
'boolIsRequestComError' => $boolIsRequestComError,
|
|
'strResponseMsgError' => is_string($objStdClassResponse) ? $objStdClassResponse : null,
|
|
'strZipCode' => $strZipCode,
|
|
'strCity' => $strCity,
|
|
'arrCitiesNameList' => $arrResultCitiesGuide['arrCitiesNameList'],
|
|
'arrPointsList' => $arrPointsList
|
|
);
|
|
|
|
// If no communication error and no error message.
|
|
if ($objStdClassResponse !== null && !is_string($objStdClassResponse)) {
|
|
// Cache until midnight.
|
|
TNTOfficiel_Cache::store($strCacheKey, Tools::jsonEncode($arrResult), $intTTL);
|
|
}
|
|
}
|
|
|
|
return $arrResult;
|
|
}
|
|
|
|
public function feasibility(
|
|
$strArgReceiverType = 'INDIVIDUAL',
|
|
$strArgSenderZipCode = '75001', $strArgSenderCity = 'PARIS 01',
|
|
$strArgReceiverZipCode = '75001', $strArgReceiverCity = 'PARIS 01',
|
|
$intArgShippingDelay = 0, $strArgShippingDate = null
|
|
) {
|
|
TNTOfficiel_Logstack::log();
|
|
|
|
$arrResultCitiesGuideSender = $this->citiesGuide('FR', $strArgSenderZipCode, $strArgSenderCity);
|
|
// Auto formatting.
|
|
$strSenderZipCode = $arrResultCitiesGuideSender['strZipCode'];
|
|
$strSenderCity = $arrResultCitiesGuideSender['strCity'];
|
|
|
|
$arrResultCitiesGuideReceiver = $this->citiesGuide('FR', $strArgReceiverZipCode, $strArgReceiverCity);
|
|
// Auto formatting.
|
|
$strReceiverZipCode = $arrResultCitiesGuideReceiver['strZipCode'];
|
|
$strReceiverCity = $arrResultCitiesGuideReceiver['strCity'];
|
|
|
|
// Default is no date.
|
|
$strShippingDate = null;
|
|
|
|
// Check Shipping Date.
|
|
if (is_string($strArgShippingDate)
|
|
&& preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/ui', $strArgShippingDate, $arrBackRef) === 1
|
|
&& checkdate((int)$arrBackRef[2], (int)$arrBackRef[3], (int)$arrBackRef[1])
|
|
) {
|
|
$strShippingDate = $strArgShippingDate;
|
|
}
|
|
|
|
// The date has priority over the delay.
|
|
if ($strShippingDate !== null) {
|
|
$intArgShippingDelay = 0;
|
|
}
|
|
|
|
$intShippingDelay = (int)$intArgShippingDelay;
|
|
if (!($intShippingDelay > 0)) {
|
|
$intShippingDelay = 0;
|
|
}
|
|
|
|
$boolIsRequestComError = false;
|
|
$arrTNTServiceList = array();
|
|
|
|
// Get params (no timestamp).
|
|
$arrParamCache = array(
|
|
'parameters' => array(
|
|
//'accountLogin' => $this->strAccountLogin,
|
|
'accountNumber' => $this->strAccountNumber,
|
|
'sender' => array(
|
|
'zipCode' => $strSenderZipCode,
|
|
'city' => $strSenderCity,
|
|
),
|
|
'receiver' => array(
|
|
'zipCode' => $strReceiverZipCode,
|
|
'city' => $strReceiverCity,
|
|
'type' => $strArgReceiverType,
|
|
),
|
|
'shipping' => $strShippingDate !== null ? $strShippingDate : $intShippingDelay,
|
|
)
|
|
);
|
|
$strCacheKey = TNTOfficiel_Cache::getKeyIdentifier(__CLASS__, __FUNCTION__, $arrParamCache);
|
|
$intTTL = TNTOfficiel_Cache::getSecondsUntilMidnight();
|
|
|
|
// Check if already in cache.
|
|
if (TNTOfficiel_Cache::isStored($strCacheKey)) {
|
|
$arrResult = Tools::jsonDecode(TNTOfficiel_Cache::retrieve($strCacheKey), true);
|
|
} else {
|
|
// If zipCode and CityName Valid for sender and receiver.
|
|
if ($arrResultCitiesGuideSender['boolIsCityNameValid']
|
|
&& $arrResultCitiesGuideReceiver['boolIsCityNameValid']
|
|
) {
|
|
$arrParamRequest = array(
|
|
'parameters' => array(
|
|
'accountNumber' => $this->strAccountNumber,
|
|
'sender' => array(
|
|
'zipCode' => $strSenderZipCode,
|
|
'city' => $strSenderCity,
|
|
),
|
|
'receiver' => array(
|
|
'zipCode' => $strReceiverZipCode,
|
|
'city' => $strReceiverCity,
|
|
'type' => $strArgReceiverType,
|
|
)
|
|
)
|
|
);
|
|
// Using specified date.
|
|
if ($strShippingDate !== null) {
|
|
$arrParamRequest['parameters']['shippingDate'] = $strShippingDate;
|
|
} else {
|
|
$arrParamRequest['parameters']['shippingDelay'] = $intShippingDelay;
|
|
}
|
|
|
|
$objStdClassResponse = $this->request('feasibility', $arrParamRequest);
|
|
} else {
|
|
$objStdClassResponse = false;
|
|
}
|
|
|
|
// Communication error.
|
|
if ($objStdClassResponse === null) {
|
|
$boolIsRequestComError = true;
|
|
}
|
|
|
|
//
|
|
if (is_object($objStdClassResponse)
|
|
&& property_exists($objStdClassResponse, 'Service')
|
|
) {
|
|
// Convert an item to array of one item
|
|
if (is_object($objStdClassResponse->Service)
|
|
&& property_exists($objStdClassResponse->Service, 'serviceLabel')
|
|
&& property_exists($objStdClassResponse->Service, 'serviceCode')
|
|
) {
|
|
$objStdClassResponse->Service = array(
|
|
(object)array(
|
|
'serviceCode' => $objStdClassResponse->Service->serviceCode,
|
|
'serviceLabel' => $objStdClassResponse->Service->serviceLabel,
|
|
'shippingDate' => $objStdClassResponse->Service->shippingDate,
|
|
'dueDate' => $objStdClassResponse->Service->dueDate,
|
|
'saturdayDelivery' => $objStdClassResponse->Service->saturdayDelivery,
|
|
'afternoonDelivery' => $objStdClassResponse->Service->afternoonDelivery,
|
|
'insurance' => $objStdClassResponse->Service->insurance,
|
|
'priorityGuarantee' => $objStdClassResponse->Service->priorityGuarantee,
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
if (is_array($objStdClassResponse->Service)
|
|
&& count($objStdClassResponse->Service) > 0
|
|
) {
|
|
foreach ($objStdClassResponse->Service as $objService) {
|
|
$arrTNTServiceList[] = array(
|
|
'accountType' => TNTOfficielCarrier::getAccountType(
|
|
$strArgReceiverType,
|
|
Tools::substr($objService->serviceCode, 1, 1),
|
|
$objService->serviceLabel
|
|
),
|
|
'carrierType' => $strArgReceiverType,
|
|
'carrierCode1' => Tools::substr($objService->serviceCode, 0, 1),
|
|
'carrierCode2' => Tools::substr($objService->serviceCode, 1, 1),
|
|
'carrierLabel' => $objService->serviceLabel,
|
|
'shippingDate' => $objService->shippingDate,
|
|
'dueDate' => $objService->dueDate,
|
|
'saturdayDelivery' => $objService->saturdayDelivery,
|
|
'afternoonDelivery' => $objService->afternoonDelivery,
|
|
'insurance' => $objService->insurance,
|
|
'priorityGuarantee' => $objService->priorityGuarantee,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
$arrResult = array(
|
|
'boolIsRequestComError' => $boolIsRequestComError,
|
|
'strResponseMsgError' => is_string($objStdClassResponse) ? $objStdClassResponse : null,
|
|
'arrTNTServiceList' => $arrTNTServiceList
|
|
);
|
|
|
|
// If no communication error and no error message.
|
|
if ($objStdClassResponse !== null && !is_string($objStdClassResponse)) {
|
|
// Cache until midnight.
|
|
TNTOfficiel_Cache::store($strCacheKey, Tools::jsonEncode($arrResult), $intTTL);
|
|
}
|
|
}
|
|
|
|
return $arrResult;
|
|
}
|
|
|
|
/**
|
|
* Used only for Occasional pickup type.
|
|
* Get the pickup availabilities.
|
|
*
|
|
* @param string $strArgSenderZipCode
|
|
* @param string $strArgSenderCity
|
|
* @param null $strArgPickupDate
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getPickupContext(
|
|
$strArgSenderZipCode = '75001',
|
|
$strArgSenderCity = 'PARIS 01',
|
|
$strArgPickupDate = null
|
|
) {
|
|
TNTOfficiel_Logstack::log();
|
|
|
|
$arrResultCitiesGuideSender = $this->citiesGuide('FR', $strArgSenderZipCode, $strArgSenderCity);
|
|
// Auto formatting.
|
|
$strSenderZipCode = $arrResultCitiesGuideSender['strZipCode'];
|
|
$strSenderCity = $arrResultCitiesGuideSender['strCity'];
|
|
|
|
// Date Today.
|
|
$objDateTimeToday = new DateTime('midnight');
|
|
|
|
// Default Pickup date requested is today.
|
|
$strPickupDate = $objDateTimeToday->format('Y-m-d');
|
|
|
|
// Check pickup date for apply.
|
|
if (is_string($strArgPickupDate)
|
|
&& preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/ui', $strArgPickupDate, $arrBackRef) === 1
|
|
&& checkdate((int)$arrBackRef[2], (int)$arrBackRef[3], (int)$arrBackRef[1])
|
|
) {
|
|
$strPickupDate = $strArgPickupDate;
|
|
}
|
|
|
|
$boolIsRequestComError = false;
|
|
|
|
// Get params (no timestamp).
|
|
$arrParamCache = array(
|
|
'parameters' => array(
|
|
'zipCode' => $strSenderZipCode,
|
|
'city' => $strSenderCity,
|
|
'shipping' => $strPickupDate,
|
|
)
|
|
);
|
|
$strCacheKey = TNTOfficiel_Cache::getKeyIdentifier(__CLASS__, __FUNCTION__, $arrParamCache);
|
|
$intTTL = TNTOfficiel_Cache::getSecondsUntilMidnight();
|
|
|
|
// Check if already in cache.
|
|
if (TNTOfficiel_Cache::isStored($strCacheKey)) {
|
|
$arrResult = Tools::jsonDecode(TNTOfficiel_Cache::retrieve($strCacheKey), true);
|
|
} else {
|
|
// If zipCode and CityName Valid for sender and receiver.
|
|
if ($arrResultCitiesGuideSender['boolIsCityNameValid']) {
|
|
$arrParamRequest = array(
|
|
'parameters' => array(
|
|
'zipCode' => $strSenderZipCode,
|
|
'city' => $strSenderCity,
|
|
'shippingDate' => $strPickupDate
|
|
)
|
|
);
|
|
|
|
$objStdClassResponse = $this->request('getPickupContext', $arrParamRequest);
|
|
} else {
|
|
$objStdClassResponse = false;
|
|
}
|
|
|
|
// Communication error.
|
|
if ($objStdClassResponse === null) {
|
|
$boolIsRequestComError = true;
|
|
}
|
|
|
|
$arrResult = array(
|
|
'boolIsRequestComError' => $boolIsRequestComError,
|
|
'strResponseMsgError' => is_string($objStdClassResponse) ? $objStdClassResponse : null,
|
|
'pickupDate' => null,
|
|
'cutOffTime' => null,
|
|
'pickupOnMorning' => null
|
|
);
|
|
|
|
//
|
|
if (is_object($objStdClassResponse)
|
|
&& property_exists($objStdClassResponse, 'return')
|
|
) {
|
|
if (is_object($objStdClassResponse->return)
|
|
&& property_exists($objStdClassResponse->return, 'shippingDate')
|
|
&& property_exists($objStdClassResponse->return, 'cutOffTime')
|
|
) {
|
|
$arrResult['pickupDate'] = $objStdClassResponse->return->shippingDate;
|
|
$arrResult['cutOffTime'] = $objStdClassResponse->return->cutOffTime;
|
|
$arrResult['pickupOnMorning'] = $objStdClassResponse->return->pickupOnMorning;
|
|
}
|
|
}
|
|
|
|
// If no communication error and no error message.
|
|
if ($objStdClassResponse !== null && !is_string($objStdClassResponse)) {
|
|
// Cache until midnight.
|
|
TNTOfficiel_Cache::store($strCacheKey, Tools::jsonEncode($arrResult), $intTTL);
|
|
}
|
|
}
|
|
|
|
return $arrResult;
|
|
}
|
|
|
|
public function expeditionCreation(
|
|
$strArgSenderCompany, $strArgSenderAddress1, $strArgSenderAddress2,
|
|
$strArgSenderZipCode, $strArgSenderCity,
|
|
$strArgSenderLastName, $strArgSenderFirstName, $strArgSenderEmail, $strArgSenderPhone,
|
|
|
|
$strArgReceiverType, $strDeliveryPointCode,
|
|
$strArgReceiverCompany, $strArgReceiverAddress1, $strArgReceiverAddress2,
|
|
$strArgReceiverZipCode, $strArgReceiverCity,
|
|
$strArgReceiverLastName, $strArgReceiverFirstName, $strArgReceiverEMail, $strArgReceiverPhone,
|
|
$strArgReceiverBuilding, $strArgReceiverAccessCode, $strArgReceiverFloor, $boolArgDeliveryNotification,
|
|
|
|
$strArgCarrierCode, $strArgPickupDate, array $arrArgParcelRequest,
|
|
|
|
$boolIsPickupTypeOccasional, $strArgPickupLabelType, $strArgPickupClosingTime, $boolArgNewPickup,
|
|
|
|
$fltArgPaybackAmount
|
|
) {
|
|
TNTOfficiel_Logstack::log();
|
|
|
|
$arrResultCitiesGuideSender = $this->citiesGuide('FR', $strArgSenderZipCode, $strArgSenderCity);
|
|
// Auto formatting.
|
|
$strSenderZipCode = $arrResultCitiesGuideSender['strZipCode'];
|
|
$strSenderCity = $arrResultCitiesGuideSender['strCity'];
|
|
|
|
$arrResultCitiesGuideReceiver = $this->citiesGuide('FR', $strArgReceiverZipCode, $strArgReceiverCity);
|
|
// Auto formatting.
|
|
$strReceiverZipCode = $arrResultCitiesGuideReceiver['strZipCode'];
|
|
$strReceiverCity = $arrResultCitiesGuideReceiver['strCity'];
|
|
|
|
// Default is no date.
|
|
$strPickupDate = null;
|
|
|
|
// Check Shipping Date.
|
|
if (is_string($strArgPickupDate)
|
|
&& preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/ui', $strArgPickupDate, $arrBackRef) === 1
|
|
&& checkdate((int)$arrBackRef[2], (int)$arrBackRef[3], (int)$arrBackRef[1])
|
|
) {
|
|
$strPickupDate = $strArgPickupDate;
|
|
}
|
|
|
|
$boolIsRequestComError = false;
|
|
|
|
// If an address line is greater than 32 chars.
|
|
if (Tools::strlen($strArgReceiverAddress1) > 32 || Tools::strlen($strArgReceiverAddress2) > 32) {
|
|
$strAddressConcat = $strArgReceiverAddress1.' '.$strArgReceiverAddress2;
|
|
$strAddressSingleLine = preg_replace('/[[:cntrl:]]+/', ' ', $strAddressConcat);
|
|
$strAddressCleaned = trim(preg_replace('/[\s]{2,}/', ' ', $strAddressSingleLine));
|
|
// Split to 32 chars.
|
|
$arrReceiverAddress = TNTOfficiel_Tools::strSplitter($strAddressCleaned, 32);
|
|
// If result have no more than 2 lines of address.
|
|
if (is_array($arrReceiverAddress) && count($arrReceiverAddress) < 3) {
|
|
$strArgReceiverAddress1 ='';
|
|
if (array_key_exists(0, $arrReceiverAddress)) {
|
|
$strArgReceiverAddress1 = $arrReceiverAddress[0];
|
|
}
|
|
$strArgReceiverAddress2 = '';
|
|
if (array_key_exists(1, $arrReceiverAddress)) {
|
|
$strArgReceiverAddress2 = $arrReceiverAddress[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get params (no timestamp).
|
|
$arrParamRequest = array(
|
|
'parameters' => array(
|
|
//'accountLogin' => $this->strAccountLogin,
|
|
'accountNumber' => $this->strAccountNumber,
|
|
'sender' => array(
|
|
'name' => TNTOfficiel_Tools::translitASCII($strArgSenderCompany, 32),
|
|
'address1' => TNTOfficiel_Tools::translitASCII($strArgSenderAddress1, 32),
|
|
'address2' => TNTOfficiel_Tools::translitASCII($strArgSenderAddress2, 32),
|
|
'zipCode' => $strSenderZipCode,
|
|
'city' => $strSenderCity,
|
|
'contactLastName' => TNTOfficiel_Tools::translitASCII($strArgSenderLastName, 32),
|
|
'contactFirstName' => TNTOfficiel_Tools::translitASCII($strArgSenderFirstName, 32),
|
|
'phoneNumber' => $strArgSenderPhone,
|
|
),
|
|
'receiver' => array(
|
|
'type' => $strArgReceiverType,
|
|
// If field typeId is set (type DROPOFFPOINT or DEPOT), address infos below
|
|
// (name, address1, address2, zipCode, city) are not used, but always auto-filled on label.
|
|
'typeId' => Tools::strtoupper($strDeliveryPointCode),
|
|
'name' => TNTOfficiel_Tools::translitASCII($strArgReceiverCompany, 32),
|
|
'address1' => TNTOfficiel_Tools::translitASCII($strArgReceiverAddress1, 32),
|
|
'address2' => TNTOfficiel_Tools::translitASCII($strArgReceiverAddress2, 32),
|
|
'zipCode' => $strReceiverZipCode,
|
|
'city' => $strReceiverCity,
|
|
'contactLastName' => TNTOfficiel_Tools::translitASCII($strArgReceiverLastName, 0, 19),
|
|
'contactFirstName' => TNTOfficiel_Tools::translitASCII($strArgReceiverFirstName, 0, 12),
|
|
'emailAddress' => $strArgReceiverEMail,
|
|
'phoneNumber' => $strArgReceiverPhone,
|
|
'accessCode' => $strArgReceiverAccessCode,
|
|
'floorNumber' => Tools::substr($strArgReceiverFloor, 0, 2),
|
|
'buldingId' => Tools::substr($strArgReceiverBuilding, 0, 3),
|
|
'sendNotification' => 1, //$boolArgDeliveryNotification,
|
|
),
|
|
'serviceCode' => $strArgCarrierCode,
|
|
'shippingDate' => $strPickupDate,
|
|
// Packages [1,30]
|
|
'quantity' => count($arrArgParcelRequest),
|
|
'saturdayDelivery' => 0,
|
|
'parcelsRequest' => (object)array(
|
|
'parcelRequest' => $arrArgParcelRequest
|
|
),
|
|
'labelFormat' => $strArgPickupLabelType,
|
|
//'hazardousMaterial' => null, // LQ, EQ, BB, LB, GM
|
|
)
|
|
);
|
|
|
|
if ($fltArgPaybackAmount !== null
|
|
&& $fltArgPaybackAmount >= 0
|
|
&& $fltArgPaybackAmount <= 10000.0
|
|
) {
|
|
$arrParamRequest['parameters']['paybackInfo'] = array(
|
|
'useSenderAddress' => 1,
|
|
'paybackAmount' => $fltArgPaybackAmount,
|
|
//'name' => null,
|
|
//'address1' => null,
|
|
//'address2' => null,
|
|
//'zipCode' => null,
|
|
//'city' => null,
|
|
);
|
|
}
|
|
|
|
// Pickup request is done only for occasional pickup type, and if no pickup request was already done.
|
|
if ($boolIsPickupTypeOccasional && $boolArgNewPickup) {
|
|
$arrResultPickupContext = $this->getPickupContext(
|
|
$strArgSenderZipCode,
|
|
$strArgSenderCity,
|
|
$strPickupDate
|
|
);
|
|
$arrParamRequest['parameters']['shippingDate'] = $arrResultPickupContext['pickupDate'];
|
|
$arrParamRequest['parameters']['pickUpRequest'] = array(
|
|
'media' => 'EMAIL',
|
|
'emailAddress' => Tools::substr($strArgSenderEmail, 0, 80),
|
|
'notifySuccess' => 1,
|
|
'lastName' => $strArgSenderLastName,
|
|
'firstName' => $strArgSenderFirstName,
|
|
'phoneNumber' => $strArgSenderPhone,
|
|
'closingTime' => $strArgPickupClosingTime,
|
|
);
|
|
}
|
|
|
|
// If zipCode and CityName Valid for sender and receiver.
|
|
if ($arrResultCitiesGuideSender['boolIsCityNameValid']
|
|
&& $arrResultCitiesGuideReceiver['boolIsCityNameValid']
|
|
) {
|
|
$objStdClassResponse = $this->request('expeditionCreation', $arrParamRequest);
|
|
} else {
|
|
$objStdClassResponse = false;
|
|
}
|
|
|
|
// Communication error.
|
|
if ($objStdClassResponse === null) {
|
|
$boolIsRequestComError = true;
|
|
}
|
|
|
|
$arrResult = array(
|
|
'boolIsRequestComError' => $boolIsRequestComError,
|
|
'strResponseMsgError' => is_string($objStdClassResponse) ? $objStdClassResponse : null,
|
|
'PDFLabels' => null,
|
|
'parcelResponses' => null,
|
|
'pickupDate' => $arrParamRequest['parameters']['shippingDate'],
|
|
'pickUpNumber' => null,
|
|
);
|
|
|
|
//
|
|
if (is_object($objStdClassResponse)
|
|
&& property_exists($objStdClassResponse, 'Expedition')
|
|
) {
|
|
if (is_object($objStdClassResponse->Expedition)
|
|
&& property_exists($objStdClassResponse->Expedition, 'parcelResponses')
|
|
&& property_exists($objStdClassResponse->Expedition, 'PDFLabels')
|
|
) {
|
|
// Convert an parcelResponses item to array of one item.
|
|
if (is_object($objStdClassResponse->Expedition->parcelResponses)
|
|
&& property_exists($objStdClassResponse->Expedition->parcelResponses, 'parcelNumber')
|
|
&& property_exists($objStdClassResponse->Expedition->parcelResponses, 'trackingURL')
|
|
) {
|
|
$objStdClassResponse->Expedition->parcelResponses = array(
|
|
(object)array(
|
|
'sequenceNumber' => $objStdClassResponse->Expedition->parcelResponses->sequenceNumber,
|
|
'parcelNumber' => $objStdClassResponse->Expedition->parcelResponses->parcelNumber,
|
|
'trackingURL' => $objStdClassResponse->Expedition->parcelResponses->trackingURL,
|
|
'stickerNumber' => $objStdClassResponse->Expedition->parcelResponses->stickerNumber,
|
|
)
|
|
);
|
|
}
|
|
|
|
$arrResult['PDFLabels'] = $objStdClassResponse->Expedition->PDFLabels;
|
|
$arrResult['parcelResponses'] = $objStdClassResponse->Expedition->parcelResponses;
|
|
if (property_exists($objStdClassResponse->Expedition, 'pickUpNumber')) {
|
|
$arrResult['pickUpNumber'] = $objStdClassResponse->Expedition->pickUpNumber;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $arrResult;
|
|
}
|
|
|
|
/**
|
|
* @param $strArgParcelNumber
|
|
* @return bool|array
|
|
*/
|
|
public function trackingByConsignment($strArgParcelNumber)
|
|
{
|
|
TNTOfficiel_Logstack::log();
|
|
|
|
$arrParamRequest = array('parcelNumber' => $strArgParcelNumber);
|
|
|
|
$objStdClassResponse = $this->request('trackingByConsignment', $arrParamRequest);
|
|
|
|
return $objStdClassResponse;
|
|
}
|
|
}
|