123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726 |
- <?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
- *
- * @api
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- * @since 100.0.2
- */
- abstract class AbstractCarrierOnline extends AbstractCarrier
- {
- const USA_COUNTRY_ID = 'US';
- const PUERTORICO_COUNTRY_ID = 'PR';
- const GUAM_COUNTRY_ID = 'GU';
- const GUAM_REGION_CODE = 'GU';
- /**
- * Array of quotes
- *
- * @var array
- */
- protected static $_quotesCache = [];
- /**
- * Flag for check carriers for activity
- *
- * @var string
- */
- protected $_activeFlag = 'active';
- /**
- * Directory data
- *
- * @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;
- /**
- * The security scanner XML document
- *
- * @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
- * @api
- */
- 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
- * @api
- */
- 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)
- * @api
- */
- 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)
- {
- $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 = preg_replace($phonePattern, '', $phoneNumber);
- $request->setShipperContactPhoneNumber($phoneNumber);
- $phoneNumber = $request->getRecipientContactPhoneNumber();
- $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)
- * @api
- */
- 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)
- * @api
- */
- public function isGirthAllowed($countyDest = null, $carrierMethodCode = null)
- {
- return false;
- }
- /**
- * Set Raw Request
- *
- * @param \Magento\Framework\DataObject|null $request
- * @return $this
- * @api
- */
- 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
- * @api
- */
- public function getMethodPrice($cost, $method = '')
- {
- return $method == $this->getConfigData(
- $this->_freeMethod
- ) && $this->getConfigFlag(
- 'free_shipping_enable'
- ) && $this->getConfigData(
- 'free_shipping_subtotal'
- ) <= $this->_rawRequest->getBaseSubtotalInclTax() ? '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
- *
- * @api
- */
- 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;
- }
- }
- }
|