| Current Path : /home/rtorresani/www/vendor/magento/module-shipping/Model/Carrier/ |
| Current File : //home/rtorresani/www/vendor/magento/module-shipping/Model/Carrier/AbstractCarrierOnline.php |
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Shipping\Model\Carrier;
use Magento\Framework\Exception\LocalizedException;
use Magento\Quote\Model\Quote\Address\RateRequest;
use Magento\Quote\Model\Quote\Address\RateResult\Error;
use Magento\Shipping\Model\Shipment\Request;
use Magento\Framework\Xml\Security;
/**
* Abstract online shipping carrier model
*
* phpcs:disable Magento2.Classes.AbstractApi
* @api
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @since 100.0.2
*/
abstract class AbstractCarrierOnline extends AbstractCarrier
{
public const USA_COUNTRY_ID = 'US';
public const PUERTORICO_COUNTRY_ID = 'PR';
public const GUAM_COUNTRY_ID = 'GU';
public const GUAM_REGION_CODE = 'GU';
/**
* @var array
*/
protected static $_quotesCache = [];
/**
* @var string
*/
protected $_activeFlag = 'active';
/**
* @var \Magento\Directory\Helper\Data
*/
protected $_directoryData = null;
/**
* @var \Magento\Shipping\Model\Simplexml\ElementFactory
*/
protected $_xmlElFactory;
/**
* @var \Magento\Shipping\Model\Rate\ResultFactory
*/
protected $_rateFactory;
/**
* @var \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory
*/
protected $_rateMethodFactory;
/**
* @var \Magento\Shipping\Model\Tracking\ResultFactory
*/
protected $_trackFactory;
/**
* @var \Magento\Shipping\Model\Tracking\Result\ErrorFactory
*/
protected $_trackErrorFactory;
/**
* @var \Magento\Shipping\Model\Tracking\Result\StatusFactory
*/
protected $_trackStatusFactory;
/**
* @var \Magento\Directory\Model\RegionFactory
*/
protected $_regionFactory;
/**
* @var \Magento\Directory\Model\CountryFactory
*/
protected $_countryFactory;
/**
* @var \Magento\Directory\Model\CurrencyFactory
*/
protected $_currencyFactory;
/**
* @var \Magento\CatalogInventory\Api\StockRegistryInterface
*/
protected $stockRegistry;
/**
* Raw rate request data
*
* @var \Magento\Framework\DataObject|null
*/
protected $_rawRequest = null;
/**
* @var Security
*/
protected $xmlSecurity;
/**
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory
* @param \Psr\Log\LoggerInterface $logger
* @param Security $xmlSecurity
* @param \Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory
* @param \Magento\Shipping\Model\Rate\ResultFactory $rateFactory
* @param \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory
* @param \Magento\Shipping\Model\Tracking\ResultFactory $trackFactory
* @param \Magento\Shipping\Model\Tracking\Result\ErrorFactory $trackErrorFactory
* @param \Magento\Shipping\Model\Tracking\Result\StatusFactory $trackStatusFactory
* @param \Magento\Directory\Model\RegionFactory $regionFactory
* @param \Magento\Directory\Model\CountryFactory $countryFactory
* @param \Magento\Directory\Model\CurrencyFactory $currencyFactory
* @param \Magento\Directory\Helper\Data $directoryData
* @param \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
* @param array $data
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory,
\Psr\Log\LoggerInterface $logger,
Security $xmlSecurity,
\Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory,
\Magento\Shipping\Model\Rate\ResultFactory $rateFactory,
\Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory,
\Magento\Shipping\Model\Tracking\ResultFactory $trackFactory,
\Magento\Shipping\Model\Tracking\Result\ErrorFactory $trackErrorFactory,
\Magento\Shipping\Model\Tracking\Result\StatusFactory $trackStatusFactory,
\Magento\Directory\Model\RegionFactory $regionFactory,
\Magento\Directory\Model\CountryFactory $countryFactory,
\Magento\Directory\Model\CurrencyFactory $currencyFactory,
\Magento\Directory\Helper\Data $directoryData,
\Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry,
array $data = []
) {
$this->_xmlElFactory = $xmlElFactory;
$this->_rateFactory = $rateFactory;
$this->_rateMethodFactory = $rateMethodFactory;
$this->_trackFactory = $trackFactory;
$this->_trackErrorFactory = $trackErrorFactory;
$this->_trackStatusFactory = $trackStatusFactory;
$this->_regionFactory = $regionFactory;
$this->_countryFactory = $countryFactory;
$this->_currencyFactory = $currencyFactory;
$this->_directoryData = $directoryData;
$this->stockRegistry = $stockRegistry;
parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);
$this->xmlSecurity = $xmlSecurity;
}
/**
* Set flag for check carriers for activity
*
* @param string $code
* @return $this
*/
public function setActiveFlag($code = 'active')
{
$this->_activeFlag = $code;
return $this;
}
/**
* Return code of carrier
*
* @return string|null
*/
public function getCarrierCode()
{
return $this->_code ?? null;
}
/**
* Get tracking information
*
* @param string $tracking
* @return string|false
*/
public function getTrackingInfo($tracking)
{
$result = $this->getTracking($tracking);
if ($result instanceof \Magento\Shipping\Model\Tracking\Result) {
$trackings = $result->getAllTrackings();
if ($trackings) {
return $trackings[0];
}
} elseif (is_string($result) && !empty($result)) {
return $result;
}
return false;
}
/**
* Check if carrier has shipping tracking option available
*
* All \Magento\Usa carriers have shipping tracking option available
*
* @return boolean
*/
public function isTrackingAvailable()
{
return true;
}
/**
* Check if city option required
*
* @return boolean
*/
public function isCityRequired()
{
return true;
}
/**
* Determine whether zip-code is required for the country of destination
*
* @param string|null $countryId
* @return bool
*/
public function isZipCodeRequired($countryId = null)
{
if ($countryId != null) {
return !$this->_directoryData->isZipCodeOptional($countryId);
}
return true;
}
/**
* Check if carrier has shipping label option available
*
* @return boolean
*/
public function isShippingLabelsAvailable()
{
return true;
}
/**
* Return items for further shipment rate evaluation. We need to pass children of a bundle instead passing the
* bundle itself, otherwise we may not get a rate at all (e.g. when total weight of a bundle exceeds max weight
* despite each item by itself is not)
*
* @param RateRequest $request
* @return array
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function getAllItems(RateRequest $request)
{
$items = [];
if ($request->getAllItems()) {
foreach ($request->getAllItems() as $item) {
/* @var $item \Magento\Quote\Model\Quote\Item */
if ($item->getProduct()->isVirtual() || $item->getParentItem()) {
// Don't process children here - we will process (or already have processed) them below
continue;
}
if ($item->getHasChildren() && $item->isShipSeparately()) {
foreach ($item->getChildren() as $child) {
if (!$child->getFreeShipping() && !$child->getProduct()->isVirtual()) {
$items[] = $child;
}
}
} else {
// Ship together - count compound item as one solid
$items[] = $item;
}
}
}
return $items;
}
/**
* Processing additional validation to check if carrier applicable.
*
* @param \Magento\Framework\DataObject $request
* @return $this|bool|\Magento\Framework\DataObject
* @deprecated 100.2.6
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
public function proccessAdditionalValidation(\Magento\Framework\DataObject $request)
{
return $this->processAdditionalValidation($request);
}
/**
* Processing additional validation to check if carrier applicable.
*
* @param \Magento\Framework\DataObject $request
* @return $this|bool|\Magento\Framework\DataObject
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @since 100.2.6
*/
public function processAdditionalValidation(\Magento\Framework\DataObject $request)
{
//Skip by item validation if there is no items in request
if (!count($this->getAllItems($request))) {
return $this;
}
$maxAllowedWeight = (double)$this->getConfigData('max_package_weight');
$errorMsg = '';
$configErrorMsg = $this->getConfigData('specificerrmsg');
$defaultErrorMsg = __('The shipping module is not available.');
$showMethod = $this->getConfigData('showmethod');
/** @var $item \Magento\Quote\Model\Quote\Item */
foreach ($this->getAllItems($request) as $item) {
$product = $item->getProduct();
if ($product && $product->getId()) {
$weight = $product->getWeight();
$stockItemData = $this->stockRegistry->getStockItem(
$product->getId(),
$item->getStore()->getWebsiteId()
);
$doValidation = true;
if ($stockItemData->getIsQtyDecimal() && $stockItemData->getIsDecimalDivided()) {
if ($stockItemData->getEnableQtyIncrements() && $stockItemData->getQtyIncrements()
) {
$weight = $weight * $stockItemData->getQtyIncrements();
} else {
$doValidation = false;
}
} elseif ($stockItemData->getIsQtyDecimal() && !$stockItemData->getIsDecimalDivided()) {
$weight = $weight * $item->getQty();
}
if ($doValidation && $weight > $maxAllowedWeight) {
$errorMsg = $configErrorMsg ? $configErrorMsg : $defaultErrorMsg;
break;
}
}
}
if (!$errorMsg && !$request->getDestPostcode() && $this->isZipCodeRequired($request->getDestCountryId())) {
$errorMsg = __('This shipping method is not available. Please specify the zip code.');
}
if ($errorMsg && $showMethod) {
$error = $this->_rateErrorFactory->create();
$error->setCarrier($this->_code);
$error->setCarrierTitle($this->getConfigData('title'));
$error->setErrorMessage($errorMsg);
return $error;
} elseif ($errorMsg) {
return false;
}
return $this;
}
/**
* Returns cache key for some request to carrier quotes service
*
* @param string|array $requestParams
* @return string
*/
protected function _getQuotesCacheKey($requestParams)
{
if (is_array($requestParams)) {
$requestParams = implode(
',',
array_merge([$this->getCarrierCode()], array_keys($requestParams), $requestParams)
);
}
return crc32($requestParams);
}
/**
* Checks whether some request to rates have already been done, so we have cache for it
*
* Used to reduce number of same requests done to carrier service during one session
* Returns cached response or null
*
* @param string|array $requestParams
* @return null|string
*/
protected function _getCachedQuotes($requestParams)
{
$key = $this->_getQuotesCacheKey($requestParams);
return self::$_quotesCache[$key] ?? null;
}
/**
* Sets received carrier quotes to cache
*
* @param string|array $requestParams
* @param string $response
* @return $this
*/
protected function _setCachedQuotes($requestParams, $response)
{
$key = $this->_getQuotesCacheKey($requestParams);
self::$_quotesCache[$key] = $response;
return $this;
}
/**
* Prepare service name. Strip tags and entities from name
*
* @param string|object $name service name or object with implemented __toString() method
* @return string prepared service name
*/
protected function _prepareServiceName($name)
{
// phpcs:ignore Magento2.Functions.DiscouragedFunction
$name = html_entity_decode((string)$name);
$name = strip_tags(preg_replace('#&\w+;#', '', $name));
return trim($name);
}
/**
* Prepare shipment request. Validate and correct request information
*
* @param \Magento\Framework\DataObject $request
* @return void
*/
protected function _prepareShipmentRequest(\Magento\Framework\DataObject $request)
{
$phonePattern = '/[\s\_\-\(\)]+/';
$phoneNumber = $request->getShipperContactPhoneNumber();
$phoneNumber = is_string($phoneNumber) ? preg_replace($phonePattern, '', $phoneNumber) : '';
$request->setShipperContactPhoneNumber($phoneNumber);
$phoneNumber = $request->getRecipientContactPhoneNumber();
$phoneNumber = is_string($phoneNumber) ? preg_replace($phonePattern, '', $phoneNumber) : '';
$request->setRecipientContactPhoneNumber($phoneNumber);
}
/**
* Do request to shipment
*
* @param Request $request
* @return \Magento\Framework\DataObject
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function requestToShipment($request)
{
$packages = $request->getPackages();
if (!is_array($packages) || !$packages) {
throw new LocalizedException(__('No packages for request'));
}
if ($request->getStoreId() != null) {
$this->setStore($request->getStoreId());
}
$data = [];
foreach ($packages as $packageId => $package) {
$request->setPackageId($packageId);
$request->setPackagingType($package['params']['container']);
$request->setPackageWeight($package['params']['weight']);
$request->setPackageParams(new \Magento\Framework\DataObject($package['params']));
$request->setPackageItems($package['items']);
$result = $this->_doShipmentRequest($request);
if ($result->hasErrors()) {
$this->rollBack($data);
break;
} else {
$data[] = [
'tracking_number' => $result->getTrackingNumber(),
'label_content' => $result->getShippingLabelContent(),
];
}
if (!isset($isFirstRequest)) {
$request->setMasterTrackingId($result->getTrackingNumber());
$isFirstRequest = false;
}
}
$response = new \Magento\Framework\DataObject(['info' => $data]);
if ($result->getErrors()) {
$response->setErrors($result->getErrors());
}
return $response;
}
/**
* Do request to RMA shipment
*
* @param Request $request
* @return \Magento\Framework\DataObject
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function returnOfShipment($request)
{
$request->setIsReturn(true);
$packages = $request->getPackages();
if (!is_array($packages) || !$packages) {
throw new LocalizedException(__('No packages for request'));
}
if ($request->getStoreId() != null) {
$this->setStore($request->getStoreId());
}
$data = [];
foreach ($packages as $packageId => $package) {
$request->setPackageId($packageId);
$request->setPackagingType($package['params']['container']);
$request->setPackageWeight($package['params']['weight']);
$request->setPackageParams(new \Magento\Framework\DataObject($package['params']));
$request->setPackageItems($package['items']);
$result = $this->_doShipmentRequest($request);
if ($result->hasErrors()) {
$this->rollBack($data);
break;
} else {
$data[] = [
'tracking_number' => $result->getTrackingNumber(),
'label_content' => $result->getShippingLabelContent(),
];
}
if (!isset($isFirstRequest)) {
$request->setMasterTrackingId($result->getTrackingNumber());
$isFirstRequest = false;
}
}
$response = new \Magento\Framework\DataObject(['info' => $data]);
if ($result->getErrors()) {
$response->setErrors($result->getErrors());
}
return $response;
}
/**
* For multi package shipments. Delete requested shipments if the current shipment. Request is failed
*
* @param array $data
* @return bool
*
* @todo implement rollback logic
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function rollBack($data)
{
return true;
}
/**
* Do shipment request to carrier web service, obtain Print Shipping Labels and process errors in response
*
* @param \Magento\Framework\DataObject $request
* @return \Magento\Framework\DataObject
*/
abstract protected function _doShipmentRequest(\Magento\Framework\DataObject $request);
/**
* Check is Country U.S. Possessions and Trust Territories
*
* @param string $countyId
* @return boolean
*/
protected function _isUSCountry($countyId)
{
switch ($countyId) {
case 'AS':
// Samoa American
case 'GU':
// Guam
case 'MP':
// Northern Mariana Islands
case 'PW':
// Palau
case 'PR':
// Puerto Rico
case 'VI':
// Virgin Islands US
case 'US':
// United States
return true;
}
return false;
}
/**
* Check whether girth is allowed for the carrier
*
* @param null|string $countyDest
* @param null|string $carrierMethodCode
* @return bool
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function isGirthAllowed($countyDest = null, $carrierMethodCode = null)
{
return false;
}
/**
* Set Raw Request
*
* @param \Magento\Framework\DataObject|null $request
* @return $this
*/
public function setRawRequest($request)
{
$this->_rawRequest = $request;
return $this;
}
/**
* Calculate price considering free shipping and handling fee
*
* @param string $cost
* @param string $method
* @return float|string
*/
public function getMethodPrice($cost, $method = '')
{
return $method == $this->getConfigData(
$this->_freeMethod
) && $this->getConfigFlag(
'free_shipping_enable'
) && $this->getConfigData(
'free_shipping_subtotal'
) <= $this->_rawRequest->getValueWithDiscount() ? '0.00' : $this->getFinalPriceWithHandlingFee(
$cost
);
}
/**
* Parse XML string and return XML document object or false
*
* @param string $xmlContent
* @param string $customSimplexml
* @return \SimpleXMLElement|bool
* @throws LocalizedException
*/
public function parseXml($xmlContent, $customSimplexml = 'SimpleXMLElement')
{
if (!$this->xmlSecurity->scan($xmlContent)) {
throw new LocalizedException(__('The security validation of the XML document has failed.'));
}
$xmlElement = simplexml_load_string($xmlContent, $customSimplexml);
return $xmlElement;
}
/**
* Checks if shipping method can collect rates
*
* @return bool
*/
public function canCollectRates()
{
return (bool)$this->getConfigFlag($this->_activeFlag);
}
/**
* Debug errors if showmethod is unset
*
* @param Error $errors
*
* @return void
*/
protected function debugErrors($errors)
{
if ($this->getConfigData('showmethod')) {
/* @var $error Error */
$this->_debug($errors);
}
}
/**
* Get error messages
*
* @return bool|Error
*/
protected function getErrorMessage()
{
if ($this->getConfigData('showmethod')) {
/* @var $error Error */
$error = $this->_rateErrorFactory->create();
$error->setCarrier($this->getCarrierCode());
$error->setCarrierTitle($this->getConfigData('title'));
$error->setErrorMessage($this->getConfigData('specificerrmsg'));
return $error;
} else {
return false;
}
}
}