Skip to content

Commit 8f6d824

Browse files
author
Eric Bohanon
committed
MAGETWO-70861: Error is thrown when saving a shipment label using DHL
1 parent e8976ad commit 8f6d824

12 files changed

+564
-59
lines changed

app/code/Magento/Dhl/Model/Carrier.php

Lines changed: 34 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88

99
use Magento\Catalog\Model\Product\Type;
1010
use Magento\Framework\Module\Dir;
11+
use Magento\Sales\Exception\DocumentValidationException;
1112
use Magento\Sales\Model\Order\Shipment;
1213
use Magento\Quote\Model\Quote\Address\RateRequest;
1314
use Magento\Quote\Model\Quote\Address\RateResult\Error;
1415
use Magento\Shipping\Model\Carrier\AbstractCarrier;
1516
use Magento\Shipping\Model\Rate\Result;
1617
use Magento\Framework\Xml\Security;
18+
use Magento\Dhl\Model\Validator\XmlValidator;
1719

1820
/**
1921
* DHL International (API v1.4)
@@ -197,6 +199,13 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
197199
'SiteID', 'Password'
198200
];
199201

202+
/**
203+
* Xml response validator
204+
*
205+
* @var \Magento\Dhl\Model\Validator\XmlValidator
206+
*/
207+
private $xmlValidator;
208+
200209
/**
201210
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
202211
* @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory
@@ -223,6 +232,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
223232
* @param \Magento\Framework\Stdlib\DateTime $dateTime
224233
* @param \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory
225234
* @param array $data
235+
* @param \Magento\Dhl\Model\Validator\XmlValidatorFactory $xmlValidatorFactory
226236
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
227237
*/
228238
public function __construct(
@@ -250,7 +260,8 @@ public function __construct(
250260
\Magento\Framework\Filesystem\Directory\ReadFactory $readFactory,
251261
\Magento\Framework\Stdlib\DateTime $dateTime,
252262
\Magento\Framework\HTTP\ZendClientFactory $httpClientFactory,
253-
array $data = []
263+
array $data = [],
264+
\Magento\Dhl\Model\Validator\XmlValidator $xmlValidator = null
254265
) {
255266
$this->readFactory = $readFactory;
256267
$this->_carrierHelper = $carrierHelper;
@@ -282,6 +293,8 @@ public function __construct(
282293
if ($this->getConfigData('content_type') == self::DHL_CONTENT_TYPE_DOC) {
283294
$this->_freeMethod = 'free_method_doc';
284295
}
296+
$this->xmlValidator = $xmlValidator
297+
?: \Magento\Framework\App\ObjectManager::getInstance()->get(XmlValidator::class);
285298
}
286299

287300
/**
@@ -1042,63 +1055,30 @@ protected function _setQuotesRequestXmlDate(\SimpleXMLElement $requestXml, $date
10421055
* @param string $response
10431056
* @return bool|\Magento\Framework\DataObject|Result|Error
10441057
* @throws \Magento\Framework\Exception\LocalizedException
1045-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
1046-
* @SuppressWarnings(PHPMD.NPathComplexity)
1058+
* @since 2.0.0
10471059
*/
10481060
protected function _parseResponse($response)
10491061
{
10501062
$responseError = __('The response is in wrong format.');
1051-
1052-
if (strlen(trim($response)) > 0) {
1053-
if (strpos(trim($response), '<?xml') === 0) {
1054-
$xml = $this->parseXml($response, \Magento\Shipping\Model\Simplexml\Element::class);
1055-
if (is_object($xml)) {
1056-
if (in_array($xml->getName(), ['ErrorResponse', 'ShipmentValidateErrorResponse'])
1057-
|| isset($xml->GetQuoteResponse->Note->Condition)
1058-
) {
1059-
$code = null;
1060-
$data = null;
1061-
if (isset($xml->Response->Status->Condition)) {
1062-
$nodeCondition = $xml->Response->Status->Condition;
1063-
} else {
1064-
$nodeCondition = $xml->GetQuoteResponse->Note->Condition;
1065-
}
1066-
1067-
if ($this->_isShippingLabelFlag) {
1068-
foreach ($nodeCondition as $condition) {
1069-
$code = isset($condition->ConditionCode) ? (string)$condition->ConditionCode : 0;
1070-
$data = isset($condition->ConditionData) ? (string)$condition->ConditionData : '';
1071-
if (!empty($code) && !empty($data)) {
1072-
break;
1073-
}
1074-
}
1075-
throw new \Magento\Framework\Exception\LocalizedException(
1076-
__('Error #%1 : %2', trim($code), trim($data))
1077-
);
1078-
}
1079-
1080-
$code = isset($nodeCondition->ConditionCode) ? (string)$nodeCondition->ConditionCode : 0;
1081-
$data = isset($nodeCondition->ConditionData) ? (string)$nodeCondition->ConditionData : '';
1082-
$this->_errors[$code] = __('Error #%1 : %2', trim($code), trim($data));
1083-
} else {
1084-
if (isset($xml->GetQuoteResponse->BkgDetails->QtdShp)) {
1085-
foreach ($xml->GetQuoteResponse->BkgDetails->QtdShp as $quotedShipment) {
1086-
$this->_addRate($quotedShipment);
1087-
}
1088-
} elseif (isset($xml->AirwayBillNumber)) {
1089-
return $this->_prepareShippingLabelContent($xml);
1090-
} else {
1091-
$this->_errors[] = $responseError;
1092-
}
1093-
}
1063+
try {
1064+
$this->xmlValidator->validate($response);
1065+
$xml = simplexml_load_string($response);
1066+
if (isset($xml->GetQuoteResponse->BkgDetails->QtdShp)) {
1067+
foreach ($xml->GetQuoteResponse->BkgDetails->QtdShp as $quotedShipment) {
1068+
$this->_addRate($quotedShipment);
10941069
}
1070+
} elseif (isset($xml->AirwayBillNumber)) {
1071+
return $this->_prepareShippingLabelContent($xml);
10951072
} else {
10961073
$this->_errors[] = $responseError;
10971074
}
1098-
} else {
1099-
$this->_errors[] = $responseError;
1075+
} catch (DocumentValidationException $e) {
1076+
if ($e->getCode() > 0) {
1077+
$this->_errors[$e->getCode()] = $e->getMessage();
1078+
} else {
1079+
$this->_errors[] = $e->getMessage();
1080+
}
11001081
}
1101-
11021082
/* @var $result Result */
11031083
$result = $this->_rateFactory->create();
11041084
if ($this->_rates) {
@@ -1547,14 +1527,15 @@ protected function _doRequest()
15471527
$xml->addChild('LabelImageFormat', 'PDF', '');
15481528

15491529
$request = $xml->asXML();
1550-
if (!$request && !mb_detect_encoding($request) == 'UTF-8') {
1530+
if (!$request && !(mb_detect_encoding($request) == 'UTF-8')) {
15511531
$request = utf8_encode($request);
15521532
}
15531533

15541534
$responseBody = $this->_getCachedQuotes($request);
15551535
if ($responseBody === null) {
15561536
$debugData = ['request' => $request];
15571537
try {
1538+
/** @var \Magento\Framework\HTTP\ZendClient $client */
15581539
$client = $this->_httpClientFactory->create();
15591540
$client->setUri((string)$this->getConfigData('gateway_url'));
15601541
$client->setConfig(['maxredirects' => 0, 'timeout' => 30]);
@@ -1664,7 +1645,7 @@ protected function _shipmentDetails($xml, $rawRequest, $originRegion = '')
16641645
$packageType = 'CP';
16651646
}
16661647
$nodeShipmentDetails->addChild('PackageType', $packageType);
1667-
$nodeShipmentDetails->addChild('Weight', $rawRequest->getPackageWeight());
1648+
$nodeShipmentDetails->addChild('Weight', sprintf('%.3f', $rawRequest->getPackageWeight()));
16681649
$nodeShipmentDetails->addChild('DimensionUnit', substr($this->_getDimensionUnit(), 0, 1));
16691650
$nodeShipmentDetails->addChild('WeightUnit', substr($this->_getWeightUnit(), 0, 1));
16701651
$nodeShipmentDetails->addChild('GlobalProductCode', $rawRequest->getShippingMethod());
@@ -1748,7 +1729,8 @@ protected function _getXMLTracking($trackings)
17481729
if ($responseBody === null) {
17491730
$debugData = ['request' => $request];
17501731
try {
1751-
$client = new \Magento\Framework\HTTP\ZendClient();
1732+
/** @var \Magento\Framework\HTTP\ZendClient $client */
1733+
$client = $this->_httpClientFactory->create();
17521734
$client->setUri((string)$this->getConfigData('gateway_url'));
17531735
$client->setConfig(['maxredirects' => 0, 'timeout' => 30]);
17541736
$client->setRawData($request);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Dhl\Model\Validator;
8+
9+
/**
10+
* Performs XML and string processing for errors produced by the DHL shipping service
11+
*/
12+
class ResponseErrorProcessor
13+
{
14+
/**
15+
* Processes error encountered in DHL XML response
16+
*
17+
* @param \SimpleXMLElement $xml
18+
* @param bool $isShippingLabel
19+
* @return \Magento\Framework\Phrase
20+
*/
21+
public function process($xml, $isShippingLabel)
22+
{
23+
$code = null;
24+
$data = null;
25+
$nodeCondition = isset($xml->Response->Status->Condition)
26+
? $xml->Response->Status->Condition : $xml->GetQuoteResponse->Note->Condition;
27+
28+
if ($isShippingLabel) {
29+
foreach ($nodeCondition as $condition) {
30+
$code = (string)$condition->ConditionCode;
31+
$data = (string)$condition->ConditionData;
32+
if (!empty($code) && !empty($data)) {
33+
break;
34+
}
35+
}
36+
return __('Error #%1 : %2', trim($code), trim($data));
37+
}
38+
39+
$code = (string)$nodeCondition->ConditionCode ?: 0;
40+
$data = (string)$nodeCondition->ConditionData ?: '';
41+
return __('Error #%1 : %2', trim($code), trim($data));
42+
}
43+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Dhl\Model\Validator;
8+
9+
use Magento\Sales\Exception\DocumentValidationException;
10+
11+
/**
12+
* Validates XML responses from DHL's web service
13+
*/
14+
class XmlValidator
15+
{
16+
/**
17+
* @var \Magento\Framework\Xml\Security
18+
*/
19+
private $xmlSecurity;
20+
21+
/**
22+
* @var ResponseErrorProcessor
23+
*/
24+
private $errorProcessor;
25+
26+
/**
27+
* Initialize XmlValidator dependencies
28+
*
29+
* @param \Magento\Framework\Xml\Security $xmlSecurity
30+
* @param ResponseErrorProcessor $errorProcessor
31+
*/
32+
public function __construct(
33+
\Magento\Framework\Xml\Security $xmlSecurity,
34+
ResponseErrorProcessor $errorProcessor
35+
) {
36+
$this->xmlSecurity = $xmlSecurity;
37+
$this->errorProcessor = $errorProcessor;
38+
}
39+
40+
/**
41+
* Validate DHL XML responses
42+
*
43+
* @param string $xmlResponse
44+
* @param bool $isShippingLabel
45+
* @return void
46+
* @throws DocumentValidationException
47+
*/
48+
public function validate($xmlResponse, $isShippingLabel = false)
49+
{
50+
if (strlen(trim($xmlResponse)) > 0 && strpos(trim($xmlResponse), '<?xml') === 0) {
51+
if (!$this->xmlSecurity->scan($xmlResponse)) {
52+
throw new DocumentValidationException(__('Security validation of XML document has been failed.'));
53+
}
54+
$xml = simplexml_load_string($xmlResponse, \Magento\Shipping\Model\Simplexml\Element::class);
55+
56+
if (in_array($xml->getName(), ['ErrorResponse', 'ShipmentValidateErrorResponse'])
57+
|| isset($xml->GetQuoteResponse->Note->Condition)
58+
) {
59+
/** @var \Magento\Framework\Phrase $exceptionPhrase */
60+
$exceptionPhrase = $this->errorProcessor->process($xml, $isShippingLabel);
61+
throw new DocumentValidationException($exceptionPhrase, null, $exceptionPhrase->getArguments()[0]);
62+
}
63+
} else {
64+
throw new DocumentValidationException(__('The response is in the wrong format'));
65+
}
66+
}
67+
}

0 commit comments

Comments
 (0)