![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/app/code/Cnc/Shipping/Preference/Model/Ups/ |
<?php declare(strict_types=1); namespace Cnc\Shipping\Preference\Model\Ups; use Magento\CatalogInventory\Api\StockRegistryInterface; use Magento\Directory\Helper\Data; use Magento\Directory\Model\CountryFactory; use Magento\Directory\Model\CurrencyFactory; use Magento\Directory\Model\RegionFactory; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\HTTP\AsyncClient\HttpResponseDeferredInterface; use Magento\Framework\HTTP\AsyncClient\Request; use Magento\Framework\HTTP\AsyncClientInterface; use Magento\Framework\HTTP\ClientFactory; use Magento\Framework\Locale\FormatInterface; use Magento\Framework\Xml\Security; use Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory as RateErrorFactory; use Magento\Quote\Model\Quote\Address\RateResult\MethodFactory as RateMethodFactory; use Magento\Shipping\Model\Rate\Result\ProxyDeferredFactory; use Magento\Shipping\Model\Rate\ResultFactory as RateFactory; use Magento\Shipping\Model\Simplexml\Element; use Magento\Shipping\Model\Simplexml\ElementFactory; use Magento\Shipping\Model\Tracking\Result\ErrorFactory as TrackErrorFactory; use Magento\Shipping\Model\Tracking\Result\StatusFactory as TrackStatusFactory; use Magento\Shipping\Model\Tracking\ResultFactory as TrackFactory; use Magento\Ups\Helper\Config; use Psr\Log\LoggerInterface; use RuntimeException; use Throwable; use Magento\Ups\Model\Carrier as BaseUpsCarrier; /** * Override for a quick fix * @fixme - find better way to fix the issue */ class Carrier extends BaseUpsCarrier { /** * @var AsyncClientInterface */ private $asyncHttpClient; /** * @var ProxyDeferredFactory */ private $deferredProxyFactory; public function __construct( ScopeConfigInterface $scopeConfig, RateErrorFactory $rateErrorFactory, LoggerInterface $logger, Security $xmlSecurity, ElementFactory $xmlElFactory, RateFactory $rateFactory, RateMethodFactory $rateMethodFactory, TrackFactory $trackFactory, TrackErrorFactory $trackErrorFactory, TrackStatusFactory $trackStatusFactory, RegionFactory $regionFactory, CountryFactory $countryFactory, CurrencyFactory $currencyFactory, Data $directoryData, StockRegistryInterface $stockRegistry, FormatInterface $localeFormat, Config $configHelper, ClientFactory $httpClientFactory, array $data = [], ?AsyncClientInterface $asyncHttpClient = null, ?ProxyDeferredFactory $proxyDeferredFactory = null ) { $this->asyncHttpClient = $asyncHttpClient ?? ObjectManager::getInstance()->get(AsyncClientInterface::class); $this->deferredProxyFactory = $proxyDeferredFactory ?? ObjectManager::getInstance()->get(ProxyDeferredFactory::class); parent::__construct($scopeConfig, $rateErrorFactory, $logger, $xmlSecurity, $xmlElFactory, $rateFactory, $rateMethodFactory, $trackFactory, $trackErrorFactory, $trackStatusFactory, $regionFactory, $countryFactory, $currencyFactory, $directoryData, $stockRegistry, $localeFormat, $configHelper, $httpClientFactory, $data, $asyncHttpClient, $proxyDeferredFactory); } /** * KALIOP MODIFICATOIN IN THIS METHOD * @inheritDoc */ 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()); } // phpcs:disable try { $quoteIds = $this->requestQuotes($request); $labels = $this->requestShipments($quoteIds); } catch (LocalizedException $exception) { $this->_logger->critical($exception); return new DataObject(['errors' => [$exception->getMessage()]]); } catch (RuntimeException $exception) { $this->_logger->critical($exception); //KALIOP MODIFICATION -> Expose full error for better issues tracking return new DataObject(['errors' => __($exception->getMessage())]); } // phpcs:enable return new DataObject(['info' => $labels]); } /** * Map currency alias to currency code * * @param string $code * @return string */ private function mapCurrencyCode($code) { $currencyMapping = [ 'RMB' => 'CNY', 'CNH' => 'CNY' ]; return $currencyMapping[$code] ?? $code; } /** * Processing rate for ship element * * @param \Magento\Framework\Simplexml\Element $shipElement * @param array $allowedMethods * @param array $allowedCurrencies * @param array $costArr * @param array $priceArr * @param bool $negotiatedActive * @param \Magento\Framework\Simplexml\Config $xml * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ private function processShippingRateForItem( \Magento\Framework\Simplexml\Element $shipElement, array $allowedMethods, array $allowedCurrencies, array &$costArr, array &$priceArr, bool $negotiatedActive, \Magento\Framework\Simplexml\Config $xml ): void { $code = (string)$shipElement->Service->Code; if (in_array($code, $allowedMethods)) { //The location of tax information is in a different place // depending on whether we are using negotiated rates or not if ($negotiatedActive) { $includeTaxesArr = $xml->getXpath( "//RatingServiceSelectionResponse/RatedShipment/NegotiatedRates" . "/NetSummaryCharges/TotalChargesWithTaxes" ); $includeTaxesActive = $this->getConfigFlag('include_taxes') && !empty($includeTaxesArr); if ($includeTaxesActive) { $cost = $shipElement->NegotiatedRates ->NetSummaryCharges ->TotalChargesWithTaxes ->MonetaryValue; $responseCurrencyCode = $this->mapCurrencyCode( (string)$shipElement->NegotiatedRates ->NetSummaryCharges ->TotalChargesWithTaxes ->CurrencyCode ); } else { $cost = $shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->MonetaryValue; $responseCurrencyCode = $this->mapCurrencyCode( (string)$shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->CurrencyCode ); } } else { $includeTaxesArr = $xml->getXpath( "//RatingServiceSelectionResponse/RatedShipment/TotalChargesWithTaxes" ); $includeTaxesActive = $this->getConfigFlag('include_taxes') && !empty($includeTaxesArr); if ($includeTaxesActive) { $cost = $shipElement->TotalChargesWithTaxes->MonetaryValue; $responseCurrencyCode = $this->mapCurrencyCode( (string)$shipElement->TotalChargesWithTaxes->CurrencyCode ); } else { $cost = $shipElement->TotalCharges->MonetaryValue; $responseCurrencyCode = $this->mapCurrencyCode( (string)$shipElement->TotalCharges->CurrencyCode ); } } //convert price with Origin country currency code to base currency code $successConversion = true; if ($responseCurrencyCode) { if (in_array($responseCurrencyCode, $allowedCurrencies)) { $cost = (double)$cost * $this->_getBaseCurrencyRate($responseCurrencyCode); } else { $errorTitle = __( 'We can\'t convert a rate from "%1-%2".', $responseCurrencyCode, $this->_request->getPackageCurrency()->getCode() ); $error = $this->_rateErrorFactory->create(); $error->setCarrier('ups'); $error->setCarrierTitle($this->getConfigData('title')); $error->setErrorMessage($errorTitle); $successConversion = false; } } if ($successConversion) { $costArr[$code] = $cost; $priceArr[$code] = $this->getMethodPrice((float)$cost, $code); } } } /** * Process tracking info from activity tag * * @param \Magento\Framework\Simplexml\Element $activityTag * @param int $index * @param array $resultArr * @param array $packageProgress */ private function processActivityTagInfo( \Magento\Framework\Simplexml\Element $activityTag, int &$index, array &$resultArr, array &$packageProgress ) { $addressArr = []; if (isset($activityTag->ActivityLocation->Address->City)) { $addressArr[] = (string)$activityTag->ActivityLocation->Address->City; } if (isset($activityTag->ActivityLocation->Address->StateProvinceCode)) { $addressArr[] = (string)$activityTag->ActivityLocation->Address->StateProvinceCode; } if (isset($activityTag->ActivityLocation->Address->CountryCode)) { $addressArr[] = (string)$activityTag->ActivityLocation->Address->CountryCode; } $dateArr = []; $date = (string)$activityTag->Date; //YYYYMMDD $dateArr[] = substr($date, 0, 4); $dateArr[] = substr($date, 4, 2); $dateArr[] = substr($date, -2, 2); $timeArr = []; $time = (string)$activityTag->Time; //HHMMSS $timeArr[] = substr($time, 0, 2); $timeArr[] = substr($time, 2, 2); $timeArr[] = substr($time, -2, 2); if ($index === 1) { $resultArr['status'] = (string)$activityTag->Status->StatusType->Description; $resultArr['deliverydate'] = implode('-', $dateArr); //YYYY-MM-DD $resultArr['deliverytime'] = implode(':', $timeArr); //HH:MM:SS $resultArr['deliverylocation'] = (string)$activityTag->ActivityLocation->Description; $resultArr['signedby'] = (string)$activityTag->ActivityLocation->SignedForByName; if ($addressArr) { $resultArr['deliveryto'] = implode(', ', $addressArr); } } else { $tempArr = []; $tempArr['activity'] = (string)$activityTag->Status->StatusType->Description; $tempArr['deliverydate'] = implode('-', $dateArr); //YYYY-MM-DD $tempArr['deliverytime'] = implode(':', $timeArr); //HH:MM:SS if ($addressArr) { $tempArr['deliverylocation'] = implode(', ', $addressArr); } $packageProgress[] = $tempArr; } $index++; } /** * Form XML for shipment request * * @param DataObject $request * @return string * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ protected function _formShipmentRequest(DataObject $request) { $packages = $request->getPackages(); $shipmentItems = []; foreach ($packages as $package) { $shipmentItems[] = $package['items']; } $shipmentItems = array_merge(...$shipmentItems); $xmlRequest = $this->_xmlElFactory->create( ['data' => '<?xml version = "1.0" ?><ShipmentConfirmRequest xml:lang="en-US"/>'] ); $requestPart = $xmlRequest->addChild('Request'); $requestPart->addChild('RequestAction', 'ShipConfirm'); $requestPart->addChild('RequestOption', 'nonvalidate'); $shipmentPart = $xmlRequest->addChild('Shipment'); if ($request->getIsReturn()) { $returnPart = $shipmentPart->addChild('ReturnService'); // UPS Print Return Label $returnPart->addChild('Code', '9'); } $shipmentPart->addChild('Description', $this->generateShipmentDescription($shipmentItems)); //empirical $shipperPart = $shipmentPart->addChild('Shipper'); if ($request->getIsReturn()) { $shipperPart->addChild('Name', $request->getRecipientContactCompanyName()); $shipperPart->addChild('AttentionName', $request->getRecipientContactPersonName()); $shipperPart->addChild('ShipperNumber', $this->getConfigData('shipper_number')); $shipperPart->addChild('PhoneNumber', $request->getRecipientContactPhoneNumber()); $addressPart = $shipperPart->addChild('Address'); $addressPart->addChild('AddressLine1', $request->getRecipientAddressStreet()); $addressPart->addChild('AddressLine2', $request->getRecipientAddressStreet2()); $addressPart->addChild('City', $request->getRecipientAddressCity()); $addressPart->addChild('CountryCode', $request->getRecipientAddressCountryCode()); $addressPart->addChild('PostalCode', $request->getRecipientAddressPostalCode()); if ($request->getRecipientAddressStateOrProvinceCode()) { $addressPart->addChild('StateProvinceCode', $request->getRecipientAddressStateOrProvinceCode()); } } else { $shipperPart->addChild('Name', $request->getShipperContactCompanyName()); $shipperPart->addChild('AttentionName', $request->getShipperContactPersonName()); $shipperPart->addChild('ShipperNumber', $this->getConfigData('shipper_number')); $shipperPart->addChild('PhoneNumber', $request->getShipperContactPhoneNumber()); $addressPart = $shipperPart->addChild('Address'); $addressPart->addChild('AddressLine1', $request->getShipperAddressStreet1()); $addressPart->addChild('AddressLine2', $request->getShipperAddressStreet2()); $addressPart->addChild('City', $request->getShipperAddressCity()); $addressPart->addChild('CountryCode', $request->getShipperAddressCountryCode()); $addressPart->addChild('PostalCode', $request->getShipperAddressPostalCode()); if ($request->getShipperAddressStateOrProvinceCode()) { $addressPart->addChild('StateProvinceCode', $request->getShipperAddressStateOrProvinceCode()); } } $shipToPart = $shipmentPart->addChild('ShipTo'); $shipToPart->addChild('AttentionName', $request->getRecipientContactPersonName()); $shipToPart->addChild( 'CompanyName', $request->getRecipientContactCompanyName() ? $request->getRecipientContactCompanyName() : 'N/A' ); $shipToPart->addChild('PhoneNumber', $request->getRecipientContactPhoneNumber()); $addressPart = $shipToPart->addChild('Address'); $addressPart->addChild('AddressLine1', $request->getRecipientAddressStreet1()); $addressPart->addChild('AddressLine2', $request->getRecipientAddressStreet2()); $addressPart->addChild('City', $request->getRecipientAddressCity()); $addressPart->addChild('CountryCode', $request->getRecipientAddressCountryCode()); $addressPart->addChild('PostalCode', $request->getRecipientAddressPostalCode()); if ($request->getRecipientAddressStateOrProvinceCode()) { $addressPart->addChild('StateProvinceCode', $request->getRecipientAddressRegionCode()); } if ($this->getConfigData('dest_type') == 'RES') { $addressPart->addChild('ResidentialAddress'); } if ($request->getIsReturn()) { $shipFromPart = $shipmentPart->addChild('ShipFrom'); $shipFromPart->addChild('AttentionName', $request->getShipperContactPersonName()); $shipFromPart->addChild( 'CompanyName', $request->getShipperContactCompanyName() ? $request ->getShipperContactCompanyName() : $request ->getShipperContactPersonName() ); $shipFromAddress = $shipFromPart->addChild('Address'); $shipFromAddress->addChild('AddressLine1', $request->getShipperAddressStreet1()); $shipFromAddress->addChild('AddressLine2', $request->getShipperAddressStreet2()); $shipFromAddress->addChild('City', $request->getShipperAddressCity()); $shipFromAddress->addChild('CountryCode', $request->getShipperAddressCountryCode()); $shipFromAddress->addChild('PostalCode', $request->getShipperAddressPostalCode()); if ($request->getShipperAddressStateOrProvinceCode()) { $shipFromAddress->addChild('StateProvinceCode', $request->getShipperAddressStateOrProvinceCode()); } $addressPart = $shipToPart->addChild('Address'); $addressPart->addChild('AddressLine1', $request->getShipperAddressStreet1()); $addressPart->addChild('AddressLine2', $request->getShipperAddressStreet2()); $addressPart->addChild('City', $request->getShipperAddressCity()); $addressPart->addChild('CountryCode', $request->getShipperAddressCountryCode()); $addressPart->addChild('PostalCode', $request->getShipperAddressPostalCode()); if ($request->getShipperAddressStateOrProvinceCode()) { $addressPart->addChild('StateProvinceCode', $request->getShipperAddressStateOrProvinceCode()); } if ($this->getConfigData('dest_type') == 'RES') { $addressPart->addChild('ResidentialAddress'); } } $servicePart = $shipmentPart->addChild('Service'); /** * KALIOP OVERRIDE STARTS HERE * //TODO - change from preference for better solution? * Shipping method may be an array due to EcomBricks modification, we need to pass * string to be able to generate label from native module. */ // $servicePart->addChild('Code', $request->getShippingMethod()); $shippingMethod = $request->getShippingMethod(); if (is_array($shippingMethod)) { $shippingMethod = reset($shippingMethod); } $servicePart->addChild('Code', $shippingMethod); /** KALIOP OVERRIDE ENDS HERE */ $packagePart = []; $customsTotal = 0; $packagingTypes = []; $deliveryConfirmationLevel = $this->_getDeliveryConfirmationLevel( $request->getRecipientAddressCountryCode() ); foreach ($packages as $packageId => $package) { $packageItems = $package['items']; $packageParams = new DataObject($package['params']); $packagingType = $package['params']['container']; $packagingTypes[] = $packagingType; $height = $packageParams->getHeight(); $width = $packageParams->getWidth(); $length = $packageParams->getLength(); $weight = $packageParams->getWeight(); $weightUnits = $packageParams->getWeightUnits() == \Zend_Measure_Weight::POUND ? 'LBS' : 'KGS'; $dimensionsUnits = $packageParams->getDimensionUnits() == \Zend_Measure_Length::INCH ? 'IN' : 'CM'; $deliveryConfirmation = $packageParams->getDeliveryConfirmation(); $customsTotal += $packageParams->getCustomsValue(); $packagePart[$packageId] = $shipmentPart->addChild('Package'); $packagePart[$packageId]->addChild('Description', $this->generateShipmentDescription($packageItems)); //empirical $packagePart[$packageId]->addChild('PackagingType')->addChild('Code', $packagingType); $packageWeight = $packagePart[$packageId]->addChild('PackageWeight'); $packageWeight->addChild('Weight', $weight); $packageWeight->addChild('UnitOfMeasurement')->addChild('Code', $weightUnits); // set dimensions if ($length || $width || $height) { $packageDimensions = $packagePart[$packageId]->addChild('Dimensions'); $packageDimensions->addChild('UnitOfMeasurement')->addChild('Code', $dimensionsUnits); $packageDimensions->addChild('Length', $length); $packageDimensions->addChild('Width', $width); $packageDimensions->addChild('Height', $height); } // ups support reference number only for domestic service if ($this->_isUSCountry($request->getRecipientAddressCountryCode()) && $this->_isUSCountry($request->getShipperAddressCountryCode()) ) { if ($request->getReferenceData()) { $referenceData = $request->getReferenceData() . $packageId; } else { $referenceData = 'Order #' . $request->getOrderShipment()->getOrder()->getIncrementId() . ' P' . $packageId; } $referencePart = $packagePart[$packageId]->addChild('ReferenceNumber'); $referencePart->addChild('Code', '02'); $referencePart->addChild('Value', $referenceData); } if ($deliveryConfirmation && $deliveryConfirmationLevel === self::DELIVERY_CONFIRMATION_PACKAGE) { $serviceOptionsNode = $packagePart[$packageId]->addChild('PackageServiceOptions'); $serviceOptionsNode->addChild( 'DeliveryConfirmation' )->addChild( 'DCISType', $deliveryConfirmation ); } } if (!empty($deliveryConfirmation) && $deliveryConfirmationLevel === self::DELIVERY_CONFIRMATION_SHIPMENT) { $serviceOptionsNode = $shipmentPart->addChild('ShipmentServiceOptions'); $serviceOptionsNode->addChild( 'DeliveryConfirmation' )->addChild( 'DCISType', $deliveryConfirmation ); } $shipmentPart->addChild('PaymentInformation') ->addChild('Prepaid') ->addChild('BillShipper') ->addChild('AccountNumber', $this->getConfigData('shipper_number')); if (!in_array($this->configHelper->getCode('container', 'ULE'), $packagingTypes) && $request->getShipperAddressCountryCode() == self::USA_COUNTRY_ID && ($request->getRecipientAddressCountryCode() == 'CA' || $request->getRecipientAddressCountryCode() == 'PR') ) { $invoiceLineTotalPart = $shipmentPart->addChild('InvoiceLineTotal'); $invoiceLineTotalPart->addChild('CurrencyCode', $request->getBaseCurrencyCode()); $invoiceLineTotalPart->addChild('MonetaryValue', ceil($customsTotal)); } $labelPart = $xmlRequest->addChild('LabelSpecification'); $labelPart->addChild('LabelPrintMethod')->addChild('Code', 'GIF'); $labelPart->addChild('LabelImageFormat')->addChild('Code', 'GIF'); return $xmlRequest->asXml(); } /** * Generates shipment description. * * @param array $items * @return string */ private function generateShipmentDescription(array $items): string { $itemsDesc = []; $itemsShipment = $items; foreach ($itemsShipment as $itemShipment) { $item = new \Magento\Framework\DataObject(); $item->setData($itemShipment); $itemsDesc[] = $item->getName(); } return substr(implode(' ', $itemsDesc), 0, 35); } /** * Request quotes for given packages. * * @param DataObject $request * @return string[] Quote IDs. * @throws LocalizedException * @throws RuntimeException */ private function requestQuotes(DataObject $request): array { /** @var HttpResponseDeferredInterface[] $quotesRequests */ //Getting quotes $this->_prepareShipmentRequest($request); $rawXmlRequest = $this->_formShipmentRequest($request); $this->setXMLAccessRequest(); $xmlRequest = $this->_xmlAccessRequest . $rawXmlRequest; $this->_debug(['request_quote' => $this->filterDebugData($this->_xmlAccessRequest) . $rawXmlRequest]); $quotesRequests[] = $this->asyncHttpClient->request( new Request( $this->getShipConfirmUrl(), Request::METHOD_POST, ['Content-Type' => 'application/xml'], $xmlRequest ) ); $ids = []; //Processing quote responses foreach ($quotesRequests as $quotesRequest) { $httpResponse = $quotesRequest->get(); if ($httpResponse->getStatusCode() >= 400) { throw new LocalizedException(__('Failed to get the quote')); } try { /** @var Element $response */ $response = $this->_xmlElFactory->create(['data' => $httpResponse->getBody()]); $this->_debug(['response_quote' => $response]); } catch (Throwable $e) { throw new RuntimeException($e->getMessage()); } if (isset($response->Response->Error) && in_array($response->Response->Error->ErrorSeverity, ['Hard', 'Transient']) ) { throw new RuntimeException((string)$response->Response->Error->ErrorDescription); } $ids[] = $response->ShipmentDigest; } return $ids; } /** * Request UPS to ship items based on quotes. * * @param string[] $quoteIds * @return DataObject[] * @throws LocalizedException * @throws RuntimeException */ private function requestShipments(array $quoteIds): array { /** @var HttpResponseDeferredInterface[] $shippingRequests */ $shippingRequests = []; foreach ($quoteIds as $quoteId) { /** @var Element $xmlRequest */ $xmlRequest = $this->_xmlElFactory->create( ['data' => '<?xml version = "1.0" ?><ShipmentAcceptRequest/>'] ); $request = $xmlRequest->addChild('Request'); $request->addChild('RequestAction', 'ShipAccept'); $xmlRequest->addChild('ShipmentDigest', $quoteId); $debugRequest = $this->filterDebugData($this->_xmlAccessRequest) . $xmlRequest->asXml(); $this->_debug( [ 'request_shipment' => $debugRequest ] ); $shippingRequests[] = $this->asyncHttpClient->request( new Request( $this->getShipAcceptUrl(), Request::METHOD_POST, ['Content-Type' => 'application/xml'], $this->_xmlAccessRequest . $xmlRequest->asXml() ) ); } //Processing shipment requests /** @var DataObject[] $results */ $results = []; foreach ($shippingRequests as $shippingRequest) { $httpResponse = $shippingRequest->get(); if ($httpResponse->getStatusCode() >= 400) { throw new LocalizedException(__('Failed to send the package')); } try { /** @var Element $response */ $response = $this->_xmlElFactory->create(['data' => $httpResponse->getBody()]); $this->_debug(['response_shipment' => $response]); } catch (Throwable $e) { throw new RuntimeException($e->getMessage()); } if (isset($response->Error)) { throw new RuntimeException((string)$response->Error->ErrorDescription); } foreach ($response->ShipmentResults->PackageResults as $packageResult) { $result = new DataObject(); $shippingLabelContent = (string)$packageResult->LabelImage->GraphicImage; $trackingNumber = (string)$packageResult->TrackingNumber; // phpcs:ignore Magento2.Functions.DiscouragedFunction $result->setLabelContent(base64_decode($shippingLabelContent)); $result->setTrackingNumber($trackingNumber); $results[] = $result; } } return $results; } }