741 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			741 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
<?php
 | 
						|
/**
 | 
						|
 * Copyright © Magento, Inc. All rights reserved.
 | 
						|
 * See COPYING.txt for license details.
 | 
						|
 */
 | 
						|
declare(strict_types=1);
 | 
						|
 | 
						|
namespace Magento\Dhl\Model;
 | 
						|
 | 
						|
use Magento\Framework\App\Config\ReinitableConfigInterface;
 | 
						|
use Magento\Framework\App\ProductMetadataInterface;
 | 
						|
use Magento\Framework\DataObject;
 | 
						|
use Magento\Framework\HTTP\AsyncClient\HttpException;
 | 
						|
use Magento\Framework\HTTP\AsyncClient\HttpResponseDeferredInterface;
 | 
						|
use Magento\Framework\HTTP\AsyncClient\Response;
 | 
						|
use Magento\Framework\HTTP\AsyncClientInterface;
 | 
						|
use Magento\Framework\Simplexml\Element;
 | 
						|
use Magento\Quote\Model\Quote\Address\RateRequest;
 | 
						|
use Magento\Quote\Model\Quote\Address\RateResult\Error;
 | 
						|
use Magento\Shipping\Model\Shipment\Request;
 | 
						|
use Magento\Shipping\Model\Simplexml\Element as ShippingElement;
 | 
						|
use Magento\Shipping\Model\Tracking\Result\Status;
 | 
						|
use Magento\Store\Model\ScopeInterface;
 | 
						|
use Magento\TestFramework\Helper\Bootstrap;
 | 
						|
use Magento\TestFramework\HTTP\AsyncClientInterfaceMock;
 | 
						|
use PHPUnit\Framework\TestCase;
 | 
						|
 | 
						|
/**
 | 
						|
 * Test for DHL integration.
 | 
						|
 *
 | 
						|
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 | 
						|
 */
 | 
						|
class CarrierTest extends TestCase
 | 
						|
{
 | 
						|
    private const PRODUCT_NAME_SPECIAL_CHARS = 'Φυστίκι Ψημένο με Αλάτι Συσκευασία';
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var Carrier
 | 
						|
     */
 | 
						|
    private $dhlCarrier;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var AsyncClientInterfaceMock
 | 
						|
     */
 | 
						|
    private $httpClient;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var ReinitableConfigInterface
 | 
						|
     */
 | 
						|
    private $config;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var ProductMetadataInterface
 | 
						|
     */
 | 
						|
    private $productMetadata;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    private $restoreCountry;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @inheritDoc
 | 
						|
     */
 | 
						|
    protected function setUp(): void
 | 
						|
    {
 | 
						|
        $objectManager = Bootstrap::getObjectManager();
 | 
						|
        $this->dhlCarrier = $objectManager->get(Carrier::class);
 | 
						|
        $this->httpClient = $objectManager->get(AsyncClientInterface::class);
 | 
						|
        $this->config = $objectManager->get(ReinitableConfigInterface::class);
 | 
						|
        $this->productMetadata = $objectManager->get(ProductMetadataInterface::class);
 | 
						|
        $this->restoreCountry = $this->config->getValue('shipping/origin/country_id', 'store', 'default_store');
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @inheritDoc
 | 
						|
     */
 | 
						|
    protected function tearDown(): void
 | 
						|
    {
 | 
						|
        $this->config->setValue(
 | 
						|
            'shipping/origin/country_id',
 | 
						|
            $this->restoreCountry,
 | 
						|
            'store',
 | 
						|
            'default_store'
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Test sending tracking requests.
 | 
						|
     *
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/id CustomerSiteID
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/password CustomerPassword
 | 
						|
     * @param string[] $trackingNumbers
 | 
						|
     * @param string $responseXml
 | 
						|
     * @param array $expectedTrackingData
 | 
						|
     * @param string $expectedRequestXml
 | 
						|
     * @dataProvider trackingDataProvider
 | 
						|
     */
 | 
						|
    public function testGetTracking(
 | 
						|
        $trackingNumbers,
 | 
						|
        string $responseXml,
 | 
						|
        $expectedTrackingData,
 | 
						|
        string $expectedRequestXml = ''
 | 
						|
    ) {
 | 
						|
        $this->httpClient->nextResponses([new Response(200, [], $responseXml)]);
 | 
						|
        $trackingResult = $this->dhlCarrier->getTracking($trackingNumbers);
 | 
						|
        $this->assertTrackingResult($expectedTrackingData, $trackingResult->getAllTrackings());
 | 
						|
        if ($expectedRequestXml !== '') {
 | 
						|
            $this->assertRequest($expectedRequestXml, $this->httpClient->getLastRequest()->getBody());
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get tracking data provider
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public function trackingDataProvider() : array
 | 
						|
    {
 | 
						|
        // phpcs:disable Magento2.Functions.DiscouragedFunction
 | 
						|
        $expectedMultiAWBRequestXml = file_get_contents(__DIR__ . '/../_files/TrackingRequest_MultipleAWB.xml');
 | 
						|
        $multiAWBResponseXml = file_get_contents(__DIR__ . '/../_files/TrackingResponse_MultipleAWB.xml');
 | 
						|
        $expectedSingleAWBRequestXml = file_get_contents(__DIR__ . '/../_files/TrackingRequest_SingleAWB.xml');
 | 
						|
        $singleAWBResponseXml = file_get_contents(__DIR__ . '/../_files/TrackingResponse_SingleAWB.xml');
 | 
						|
        $singleNoDataResponseXml = file_get_contents(__DIR__ . '/../_files/SingleknownTrackResponse-no-data-found.xml');
 | 
						|
        $failedResponseXml = file_get_contents(__DIR__ . '/../_files/Track-res-XML-Parse-Err.xml');
 | 
						|
        //phpcs:enable Magento2.Functions.DiscouragedFunction
 | 
						|
        $expectedTrackingDataA = [
 | 
						|
            'carrier' => 'dhl',
 | 
						|
            'carrier_title' => 'DHL',
 | 
						|
            'tracking' => 4781584780,
 | 
						|
            'service' => 'DOCUMENT',
 | 
						|
            'progressdetail' => [
 | 
						|
                [
 | 
						|
                    'activity' => 'SD Shipment information received',
 | 
						|
                    'deliverydate' => '2017-12-25',
 | 
						|
                    'deliverytime' => '14:38:00',
 | 
						|
                    'deliverylocation' => 'BEIJING-CHN [PEK]'
 | 
						|
                ]
 | 
						|
            ],
 | 
						|
            'weight' => '0.5 K',
 | 
						|
        ];
 | 
						|
        $expectedTrackingDataB = [
 | 
						|
            'carrier' => 'dhl',
 | 
						|
            'carrier_title' => 'DHL',
 | 
						|
            'tracking' => 4781585060,
 | 
						|
            'service' => 'NOT RESTRICTED FOR TRANSPORT,',
 | 
						|
            'progressdetail' => [
 | 
						|
                [
 | 
						|
                    'activity' => 'SD Shipment information received',
 | 
						|
                    'deliverydate' => '2017-12-24',
 | 
						|
                    'deliverytime' => '13:35:00',
 | 
						|
                    'deliverylocation' => 'HONG KONG-HKG [HKG]'
 | 
						|
                ]
 | 
						|
            ],
 | 
						|
            'weight' => '2.0 K',
 | 
						|
        ];
 | 
						|
        $expectedTrackingDataC = [
 | 
						|
            'carrier' => 'dhl',
 | 
						|
            'carrier_title' => 'DHL',
 | 
						|
            'tracking' => 5702254250,
 | 
						|
            'service' => 'CD',
 | 
						|
            'progressdetail' => [
 | 
						|
                [
 | 
						|
                    'activity' => 'SD Shipment information received',
 | 
						|
                    'deliverydate' => '2017-12-24',
 | 
						|
                    'deliverytime' => '04:12:00',
 | 
						|
                    'deliverylocation' => 'BIRMINGHAM-GBR [BHX]'
 | 
						|
                ]
 | 
						|
            ],
 | 
						|
            'weight' => '0.12 K',
 | 
						|
        ];
 | 
						|
        $expectedTrackingDataD = [
 | 
						|
            'carrier' => 'dhl',
 | 
						|
            'carrier_title' => 'DHL',
 | 
						|
            'tracking' => 4781585060,
 | 
						|
            'error_message' => __('Unable to retrieve tracking')
 | 
						|
        ];
 | 
						|
        $expectedTrackingDataE = [
 | 
						|
            'carrier' => 'dhl',
 | 
						|
            'carrier_title' => 'DHL',
 | 
						|
            'tracking' => 111,
 | 
						|
            'error_message' => __(
 | 
						|
                'Error #%1 : %2',
 | 
						|
                '111',
 | 
						|
                ' Error Parsing incoming request XML
 | 
						|
                    Error: The content of element type
 | 
						|
                    "ShipperReference" must match
 | 
						|
                    "(ReferenceID,ReferenceType?)". at line
 | 
						|
                    16, column 22'
 | 
						|
            )
 | 
						|
        ];
 | 
						|
        return [
 | 
						|
            'multi-AWB' => [
 | 
						|
                ['4781584780', '4781585060', '5702254250'],
 | 
						|
                $multiAWBResponseXml,
 | 
						|
                [$expectedTrackingDataA, $expectedTrackingDataB, $expectedTrackingDataC],
 | 
						|
                $expectedMultiAWBRequestXml
 | 
						|
            ],
 | 
						|
            'single-AWB' => [
 | 
						|
                ['4781585060'],
 | 
						|
                $singleAWBResponseXml,
 | 
						|
                [$expectedTrackingDataB],
 | 
						|
                $expectedSingleAWBRequestXml
 | 
						|
            ],
 | 
						|
            'single-AWB-no-data' => [['4781585061'], $singleNoDataResponseXml, [$expectedTrackingDataD]],
 | 
						|
            'failed-response' => [['4781585060-failed'], $failedResponseXml, [$expectedTrackingDataE]]
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Assert request
 | 
						|
     *
 | 
						|
     * @param string $expectedRequestXml
 | 
						|
     * @param string $requestXml
 | 
						|
     */
 | 
						|
    private function assertRequest(string $expectedRequestXml, string $requestXml): void
 | 
						|
    {
 | 
						|
        $expectedRequestElement = new Element($expectedRequestXml);
 | 
						|
        $requestElement = new Element($requestXml);
 | 
						|
        $requestMessageTime = $requestElement->Request->ServiceHeader->MessageTime->__toString();
 | 
						|
        $this->assertEquals(
 | 
						|
            1,
 | 
						|
            preg_match("/\d{4}\-\d{2}\-\d{2}T\d{2}\:\d{2}\:\d{2}\+\d{2}\:\d{2}/", $requestMessageTime)
 | 
						|
        );
 | 
						|
        $expectedRequestElement->Request->ServiceHeader->MessageTime = $requestMessageTime;
 | 
						|
        $messageReference = $requestElement->Request->ServiceHeader->MessageReference->__toString();
 | 
						|
        $this->assertStringStartsWith('MAGE_TRCK_', $messageReference);
 | 
						|
        $this->assertGreaterThanOrEqual(28, strlen($messageReference));
 | 
						|
        $this->assertLessThanOrEqual(32, strlen($messageReference));
 | 
						|
        $requestElement->Request->ServiceHeader->MessageReference = 'MAGE_TRCK_28TO32_Char_CHECKED';
 | 
						|
        $this->assertXmlStringEqualsXmlString($expectedRequestElement->asXML(), $requestElement->asXML());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Assert tracking
 | 
						|
     *
 | 
						|
     * @param array|null $expectedTrackingData
 | 
						|
     * @param Status[]|null $trackingResults
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    private function assertTrackingResult($expectedTrackingData, $trackingResults): void
 | 
						|
    {
 | 
						|
        if (null === $expectedTrackingData) {
 | 
						|
            $this->assertNull($trackingResults);
 | 
						|
        } else {
 | 
						|
            $ctr = 0;
 | 
						|
            foreach ($trackingResults as $trackingResult) {
 | 
						|
                $this->assertEquals($expectedTrackingData[$ctr++], $trackingResult->getData());
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Test sending shipping requests.
 | 
						|
     *
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/id some ID
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/password some password
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/account 1234567890
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/gateway_url https://xmlpi-ea.dhl.com/XMLShippingServlet
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/content_type N
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/nondoc_methods 1,3,4,8,P,Q,E,F,H,J,M,V,Y
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/unit_of_measure C
 | 
						|
     * @param string $origCountryId
 | 
						|
     * @param string $expectedRegionCode
 | 
						|
     * @param string $destCountryId
 | 
						|
     * @param bool|null $isProductNameContainsSpecialChars
 | 
						|
     * @return void
 | 
						|
     * @dataProvider requestToShipmentDataProvider
 | 
						|
     */
 | 
						|
    public function testRequestToShip(
 | 
						|
        string $origCountryId,
 | 
						|
        string $expectedRegionCode,
 | 
						|
        string $destCountryId,
 | 
						|
        bool $isProductNameContainsSpecialChars = false
 | 
						|
    ): void {
 | 
						|
        $this->config->setValue(
 | 
						|
            'shipping/origin/country_id',
 | 
						|
            $origCountryId,
 | 
						|
            'store',
 | 
						|
            null
 | 
						|
        );
 | 
						|
        $convmap = [0x80, 0x10FFFF, 0, 0x1FFFFF];
 | 
						|
        $content = mb_encode_numericentity(
 | 
						|
            file_get_contents(__DIR__ . '/../_files/response_shipping_label.xml'),
 | 
						|
            $convmap,
 | 
						|
            'UTF-8'
 | 
						|
        );
 | 
						|
        //phpcs:disable Magento2.Functions.DiscouragedFunction
 | 
						|
        $this->httpClient->nextResponses(
 | 
						|
            [
 | 
						|
                new Response(
 | 
						|
                    200,
 | 
						|
                    [],
 | 
						|
                    $content
 | 
						|
                )
 | 
						|
            ]
 | 
						|
        );
 | 
						|
        $productName = $isProductNameContainsSpecialChars ? self::PRODUCT_NAME_SPECIAL_CHARS : 'item_name';
 | 
						|
 | 
						|
        //phpcs:enable Magento2.Functions.DiscouragedFunction
 | 
						|
        $request = new Request(
 | 
						|
            [
 | 
						|
                'packages' => [
 | 
						|
                    'package' => [
 | 
						|
                        'params' => [
 | 
						|
                            'width' => '3',
 | 
						|
                            'length' => '3',
 | 
						|
                            'height' => '3',
 | 
						|
                            'dimension_units' => 'CENTIMETER',
 | 
						|
                            'weight_units' => 'KILOGRAM',
 | 
						|
                            'weight' => '0.454000000001',
 | 
						|
                            'customs_value' => '10.00',
 | 
						|
                            'container' => Carrier::DHL_CONTENT_TYPE_NON_DOC,
 | 
						|
                        ],
 | 
						|
                        'items' => [
 | 
						|
                            'item1' => [
 | 
						|
                                'name' => $productName,
 | 
						|
                                'qty' => 1,
 | 
						|
                                'weight' => '0.454000000001',
 | 
						|
                                'price' => '10.00',
 | 
						|
                            ],
 | 
						|
                        ],
 | 
						|
                    ],
 | 
						|
                ],
 | 
						|
                'orig_country_id' => $origCountryId,
 | 
						|
                'dest_country_id' => $destCountryId,
 | 
						|
                'shipper_address_country_code' => $origCountryId,
 | 
						|
                'recipient_address_country_code' => $destCountryId,
 | 
						|
                'package_weight' => '0.454000000001',
 | 
						|
                'free_method_weight' => '0.454000000001',
 | 
						|
                'recipient_address_street_1' => '15099 Some Blvd',
 | 
						|
                'shipper_address_street_1' => '4956 Some Way',
 | 
						|
                'order_shipment' => new DataObject(
 | 
						|
                    [
 | 
						|
                        'order' => new DataObject(
 | 
						|
                            [
 | 
						|
                                'subtotal' => '10.00'
 | 
						|
                            ]
 | 
						|
                        )
 | 
						|
                    ]
 | 
						|
                )
 | 
						|
            ]
 | 
						|
        );
 | 
						|
 | 
						|
        //Generating labels
 | 
						|
        $labels = $this->dhlCarrier->requestToShipment($request);
 | 
						|
        $this->assertNotEmpty($labels);
 | 
						|
        $this->assertNotEmpty($labels->getInfo());
 | 
						|
        $request = $this->httpClient->getLastRequest()->getBody();
 | 
						|
        $requestElement = new Element($request);
 | 
						|
        $messageReference = $requestElement->Request->ServiceHeader->MessageReference->__toString();
 | 
						|
        $this->assertStringStartsWith('MAGE_SHIP_', $messageReference);
 | 
						|
        $this->assertGreaterThanOrEqual(28, strlen($messageReference));
 | 
						|
        $this->assertLessThanOrEqual(32, strlen($messageReference));
 | 
						|
        $requestElement->Request->ServiceHeader->MessageReference = 'MAGE_SHIP_28TO32_Char_CHECKED';
 | 
						|
        $requestElement->Request->ServiceHeader->MessageTime = 'currentTime';
 | 
						|
        $requestElement->ShipmentDetails->Date = 'currentTime';
 | 
						|
 | 
						|
        $expectedLabelRequest = $this->getExpectedLabelRequestXml(
 | 
						|
            $origCountryId,
 | 
						|
            $destCountryId,
 | 
						|
            $expectedRegionCode,
 | 
						|
            $isProductNameContainsSpecialChars
 | 
						|
        );
 | 
						|
 | 
						|
        $this->assertXmlStringEqualsXmlString($expectedLabelRequest, $requestElement->asXML());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Cases with different countries.
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public function requestToShipmentDataProvider(): array
 | 
						|
    {
 | 
						|
        return [
 | 
						|
            [
 | 
						|
                'GB', 'EU', 'US'
 | 
						|
            ],
 | 
						|
            [
 | 
						|
                'SG', 'AP', 'US'
 | 
						|
            ],
 | 
						|
            [
 | 
						|
                'DE', 'EU', 'DE'
 | 
						|
            ],
 | 
						|
            [
 | 
						|
                'GB', 'EU', 'US', true
 | 
						|
            ],
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Generate expected labels request XML.
 | 
						|
     *
 | 
						|
     * @param string $origCountryId
 | 
						|
     * @param string $destCountryId
 | 
						|
     * @param string $regionCode
 | 
						|
     * @param bool $isProductNameContainsSpecialChars
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    private function getExpectedLabelRequestXml(
 | 
						|
        string $origCountryId,
 | 
						|
        string $destCountryId,
 | 
						|
        string $regionCode,
 | 
						|
        bool $isProductNameContainsSpecialChars
 | 
						|
    ): string {
 | 
						|
        $countryNames = [
 | 
						|
            'US' => 'United States Of America',
 | 
						|
            'SG' => 'Singapore',
 | 
						|
            'GB' => 'United Kingdom',
 | 
						|
            'DE' => 'Germany',
 | 
						|
        ];
 | 
						|
        $requestXmlPath = $origCountryId == $destCountryId
 | 
						|
            ? '/../_files/domestic_shipment_request.xml'
 | 
						|
            : '/../_files/shipment_request.xml';
 | 
						|
 | 
						|
        // phpcs:ignore Magento2.Functions.DiscouragedFunction
 | 
						|
        $expectedRequestElement = new ShippingElement(file_get_contents(__DIR__ . $requestXmlPath));
 | 
						|
 | 
						|
        $expectedRequestElement->Request->MetaData->SoftwareVersion = $this->buildSoftwareVersion();
 | 
						|
        $expectedRequestElement->Consignee->CountryCode = $destCountryId;
 | 
						|
        $expectedRequestElement->Consignee->CountryName = $countryNames[$destCountryId];
 | 
						|
        $expectedRequestElement->Shipper->CountryCode = $origCountryId;
 | 
						|
        $expectedRequestElement->Shipper->CountryName = $countryNames[$origCountryId];
 | 
						|
        $expectedRequestElement->RegionCode = $regionCode;
 | 
						|
 | 
						|
        if ($origCountryId !== $destCountryId) {
 | 
						|
            $expectedRequestElement->ExportDeclaration->ExportLineItem->ManufactureCountryCode = $origCountryId;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($isProductNameContainsSpecialChars) {
 | 
						|
            $expectedRequestElement->ShipmentDetails->Pieces->Piece->PieceContents = self::PRODUCT_NAME_SPECIAL_CHARS;
 | 
						|
            $expectedRequestElement->ExportDeclaration->ExportLineItem->Description = self::PRODUCT_NAME_SPECIAL_CHARS;
 | 
						|
        }
 | 
						|
 | 
						|
        return $expectedRequestElement->asXML();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Builds a string to be used as the request SoftwareVersion.
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    private function buildSoftwareVersion(): string
 | 
						|
    {
 | 
						|
        return substr($this->productMetadata->getVersion(), 0, 10);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Tests that valid rates are returned when sending a quotes request.
 | 
						|
     *
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/active 1
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/id some ID
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/shipment_days Mon,Tue,Wed,Thu,Fri,Sat
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/intl_shipment_days Mon,Tue,Wed,Thu,Fri,Sat
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/allowed_methods IE
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/international_service IE
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/gateway_url https://xmlpi-ea.dhl.com/XMLShippingServlet
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/id some ID
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/password some password
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/content_type N
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/nondoc_methods 1,3,4,8,P,Q,E,F,H,J,M,V,Y
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/showmethod' => 1,
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/title DHL Title
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/specificerrmsg dhl error message
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/unit_of_measure K
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/size 1
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/height 1.6
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/width 1.6
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/depth 1.6
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/debug 1
 | 
						|
     * @magentoConfigFixture default_store shipping/origin/country_id GB
 | 
						|
     */
 | 
						|
    public function testCollectRates()
 | 
						|
    {
 | 
						|
        $this->setNextResponse(__DIR__ . '/../_files/dhl_quote_response.xml');
 | 
						|
        $request = $this->createRequest();
 | 
						|
        $expectedRates = [
 | 
						|
            ['carrier' => 'dhl', 'carrier_title' => 'DHL Title', 'cost' => 45.85, 'method' => 'E', 'price' => 45.85],
 | 
						|
            ['carrier' => 'dhl', 'carrier_title' => 'DHL Title', 'cost' => 35.26, 'method' => 'Q', 'price' => 35.26],
 | 
						|
            ['carrier' => 'dhl', 'carrier_title' => 'DHL Title', 'cost' => 37.38, 'method' => 'Y', 'price' => 37.38],
 | 
						|
            ['carrier' => 'dhl', 'carrier_title' => 'DHL Title', 'cost' => 35.26, 'method' => 'P', 'price' => 35.26]
 | 
						|
        ];
 | 
						|
 | 
						|
        $actualRates = $this->dhlCarrier->collectRates($request)->getAllRates();
 | 
						|
 | 
						|
        self::assertEquals(count($expectedRates), count($actualRates));
 | 
						|
        foreach ($actualRates as $i => $actualRate) {
 | 
						|
            $actualRate = $actualRate->getData();
 | 
						|
            unset($actualRate['method_title']);
 | 
						|
            self::assertEquals($expectedRates[$i], $actualRate);
 | 
						|
        }
 | 
						|
        $requestXml = $this->httpClient->getLastRequest()->getBody();
 | 
						|
        self::assertStringContainsString('<Weight>18.223</Weight>', $requestXml);
 | 
						|
        self::assertStringContainsString('<Height>0.63</Height>', $requestXml);
 | 
						|
        self::assertStringContainsString('<Width>0.63</Width>', $requestXml);
 | 
						|
        self::assertStringContainsString('<Depth>0.63</Depth>', $requestXml);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Tests that quotes request doesn't contain dimensions when it shouldn't.
 | 
						|
     *
 | 
						|
     * @param string|null $size
 | 
						|
     * @param string|null $height
 | 
						|
     * @param string|null $width
 | 
						|
     * @param string|null $depth
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/active 1
 | 
						|
     * @dataProvider collectRatesWithoutDimensionsDataProvider
 | 
						|
     */
 | 
						|
    public function testCollectRatesWithoutDimensions(?string $size, ?string $height, ?string $width, ?string $depth)
 | 
						|
    {
 | 
						|
        $this->setDhlConfig(['size' => $size, 'height' => $height, 'width' => $width, 'depth' => $depth]);
 | 
						|
 | 
						|
        $request = $this->createRequest();
 | 
						|
        $this->dhlCarrier = Bootstrap::getObjectManager()->create(Carrier::class);
 | 
						|
        $this->dhlCarrier->collectRates($request)->getAllRates();
 | 
						|
 | 
						|
        $requestXml = $this->httpClient->getLastRequest()->getBody();
 | 
						|
        $this->assertStringNotContainsString('<Width>', $requestXml);
 | 
						|
        $this->assertStringNotContainsString('<Height>', $requestXml);
 | 
						|
        $this->assertStringNotContainsString('<Depth>', $requestXml);
 | 
						|
 | 
						|
        $this->config->reinit();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Test get carriers rates if has HttpException.
 | 
						|
     *
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/active 1
 | 
						|
     */
 | 
						|
    public function testGetRatesWithHttpException(): void
 | 
						|
    {
 | 
						|
        $this->setDhlConfig(['showmethod' => 1]);
 | 
						|
        $deferredResponse = $this->getMockBuilder(HttpResponseDeferredInterface::class)
 | 
						|
            ->onlyMethods(['get'])
 | 
						|
            ->getMockForAbstractClass();
 | 
						|
        $exception = new HttpException('Exception message');
 | 
						|
        $deferredResponse->method('get')->willThrowException($exception);
 | 
						|
        $this->httpClient->setDeferredResponseMock($deferredResponse);
 | 
						|
        $request = $this->createRequest();
 | 
						|
        $this->dhlCarrier = Bootstrap::getObjectManager()->create(Carrier::class);
 | 
						|
        $resultRate = $this->dhlCarrier->collectRates($request)->getAllRates()[0];
 | 
						|
        $error = Bootstrap::getObjectManager()->get(Error::class);
 | 
						|
        $error->setCarrier('dhl');
 | 
						|
        $error->setCarrierTitle($this->dhlCarrier->getConfigData('title'));
 | 
						|
        $error->setErrorMessage($this->dhlCarrier->getConfigData('specificerrmsg'));
 | 
						|
 | 
						|
        $this->assertEquals($error, $resultRate);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public function collectRatesWithoutDimensionsDataProvider()
 | 
						|
    {
 | 
						|
        return [
 | 
						|
            ['size' => '0', 'height' => '1.1', 'width' => '0.6', 'depth' => '0.7'],
 | 
						|
            ['size' => '1', 'height' => '', 'width' => '', 'depth' => ''],
 | 
						|
            ['size' => null, 'height' => '1.1', 'width' => '0.6', 'depth' => '0.7'],
 | 
						|
            ['size' => '1', 'height' => '1', 'width' => '', 'depth' => ''],
 | 
						|
            ['size' => null, 'height' => null, 'width' => null, 'depth' => null],
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sets DHL config value.
 | 
						|
     *
 | 
						|
     * @param array $params
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    private function setDhlConfig(array $params)
 | 
						|
    {
 | 
						|
        foreach ($params as $name => $val) {
 | 
						|
            if ($val !== null) {
 | 
						|
                $this->config->setValue(
 | 
						|
                    'carriers/dhl/' . $name,
 | 
						|
                    $val,
 | 
						|
                    ScopeInterface::SCOPE_STORE
 | 
						|
                );
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Tests that the free rate is returned when sending a quotes request
 | 
						|
     *
 | 
						|
     * @param array $addRequestData
 | 
						|
     * @param bool $freeShippingExpects
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/active 1
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/id some ID
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/shipment_days Mon,Tue,Wed,Thu,Fri,Sat
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/intl_shipment_days Mon,Tue,Wed,Thu,Fri,Sat
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/allowed_methods IE
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/international_service IE
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/gateway_url https://xmlpi-ea.dhl.com/XMLShippingServlet
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/id some ID
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/password some password
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/content_type N
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/nondoc_methods 1,3,4,8,P,Q,E,F,H,J,M,V,Y
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/showmethod' => 1,
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/title DHL Title
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/specificerrmsg dhl error message
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/unit_of_measure K
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/size 1
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/height 1.6
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/width 1.6
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/depth 1.6
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/debug 1
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/free_method_nondoc P
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/free_shipping_enable 1
 | 
						|
     * @magentoConfigFixture default_store carriers/dhl/free_shipping_subtotal 25
 | 
						|
     * @magentoConfigFixture default_store shipping/origin/country_id GB
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     * @dataProvider collectRatesWithFreeShippingDataProvider
 | 
						|
     */
 | 
						|
    public function testCollectRatesWithFreeShipping(array $addRequestData, bool $freeShippingExpects): void
 | 
						|
    {
 | 
						|
        $this->setNextResponse(__DIR__ . '/../_files/dhl_quote_response.xml');
 | 
						|
        $request = $this->createRequest($addRequestData);
 | 
						|
 | 
						|
        $actualRates = $this->dhlCarrier->collectRates($request)->getAllRates();
 | 
						|
        $freeRateExists = false;
 | 
						|
        foreach ($actualRates as $actualRate) {
 | 
						|
            $actualRate = $actualRate->getData();
 | 
						|
            if ($actualRate['method'] === 'P' && (float)$actualRate['price'] === 0.0) {
 | 
						|
                $freeRateExists = true;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        self::assertEquals($freeShippingExpects, $freeRateExists);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public function collectRatesWithFreeShippingDataProvider(): array
 | 
						|
    {
 | 
						|
        return [
 | 
						|
            [
 | 
						|
                ['package_value' => 25, 'package_value_with_discount' => 22],
 | 
						|
                false
 | 
						|
            ],
 | 
						|
            [
 | 
						|
                ['package_value' => 25, 'package_value_with_discount' => 25],
 | 
						|
                true
 | 
						|
            ],
 | 
						|
            [
 | 
						|
                ['package_value' => 28, 'package_value_with_discount' => 25],
 | 
						|
                true
 | 
						|
            ],
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns request data.
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    private function getRequestData(): array
 | 
						|
    {
 | 
						|
        return [
 | 
						|
            'dest_country_id' => 'DE',
 | 
						|
            'dest_region_id' => '82',
 | 
						|
            'dest_region_code' => 'BER',
 | 
						|
            'dest_street' => 'Turmstraße 17',
 | 
						|
            'dest_city' => 'Berlin',
 | 
						|
            'dest_postcode' => '10559',
 | 
						|
            'dest_postal' => '10559',
 | 
						|
            'package_value' => '5',
 | 
						|
            'package_value_with_discount' => '5',
 | 
						|
            'package_weight' => '8.2657',
 | 
						|
            'package_qty' => '1',
 | 
						|
            'package_physical_value' => '5',
 | 
						|
            'free_method_weight' => '5',
 | 
						|
            'store_id' => '1',
 | 
						|
            'website_id' => '1',
 | 
						|
            'free_shipping' => '0',
 | 
						|
            'limit_carrier' => null,
 | 
						|
            'base_subtotal_incl_tax' => '5',
 | 
						|
            'orig_country_id' => 'US',
 | 
						|
            'orig_region_id' => '12',
 | 
						|
            'orig_city' => 'Fremont',
 | 
						|
            'orig_postcode' => '94538',
 | 
						|
            'dhl_id' => 'MAGEN_8501',
 | 
						|
            'dhl_password' => 'QR2GO1U74X',
 | 
						|
            'dhl_account' => '799909537',
 | 
						|
            'dhl_shipping_intl_key' => '54233F2B2C4E5C4B4C5E5A59565530554B405641475D5659',
 | 
						|
            'girth' => null,
 | 
						|
            'height' => null,
 | 
						|
            'length' => null,
 | 
						|
            'width' => null,
 | 
						|
            'weight' => 1,
 | 
						|
            'dhl_shipment_type' => 'P',
 | 
						|
            'dhl_duitable' => 0,
 | 
						|
            'dhl_duty_payment_type' => 'R',
 | 
						|
            'dhl_content_desc' => 'Big Box',
 | 
						|
            'limit_method' => 'IE',
 | 
						|
            'ship_date' => '2014-01-09',
 | 
						|
            'action' => 'RateEstimate',
 | 
						|
            'all_items' => [],
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set next response content from file
 | 
						|
     *
 | 
						|
     * @param string $file
 | 
						|
     */
 | 
						|
    private function setNextResponse(string $file): void
 | 
						|
    {
 | 
						|
        //phpcs:disable Magento2.Functions.DiscouragedFunction
 | 
						|
        $response = new Response(
 | 
						|
            200,
 | 
						|
            [],
 | 
						|
            file_get_contents($file)
 | 
						|
        );
 | 
						|
        //phpcs:enable Magento2.Functions.DiscouragedFunction
 | 
						|
        $this->httpClient->nextResponses(
 | 
						|
            array_fill(0, Carrier::UNAVAILABLE_DATE_LOOK_FORWARD + 1, $response)
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Create Rate Request
 | 
						|
     *
 | 
						|
     * @param array $addRequestData
 | 
						|
     * @return RateRequest
 | 
						|
     */
 | 
						|
    private function createRequest(array $addRequestData = []): RateRequest
 | 
						|
    {
 | 
						|
        $requestData = $this->getRequestData();
 | 
						|
        if (!empty($addRequestData)) {
 | 
						|
            $requestData = array_merge($requestData, $addRequestData);
 | 
						|
        }
 | 
						|
 | 
						|
        return Bootstrap::getObjectManager()->create(RateRequest::class, ['data' => $requestData]);
 | 
						|
    }
 | 
						|
}
 |