ShippingConfiguration.php 4.33 KB
Newer Older
Ketan's avatar
Ketan committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Magento\InstantPurchase\Model\QuoteManagement;

use Magento\Framework\Exception\LocalizedException;
use Magento\InstantPurchase\Model\ShippingMethodChoose\DeferredShippingMethodChooserInterface;
use Magento\InstantPurchase\Model\ShippingMethodChoose\DeferredShippingMethodChooserPool;
use Magento\Quote\Api\Data\ShippingMethodInterface;
use Magento\Quote\Model\Quote;
use Magento\Quote\Model\Quote\Address;

/**
 * Configure shipping method for instant purchase
 *
 * @api May be used for pluginization.
 * @since 100.2.0
 */
class ShippingConfiguration
{
    /**
     * @var DeferredShippingMethodChooserPool
     */
    private $deferredShippingMethodChooserPool;

    /**
     * ShippingConfiguration constructor.
     * @param DeferredShippingMethodChooserPool $deferredShippingMethodChooserPool
     */
    public function __construct(
        DeferredShippingMethodChooserPool $deferredShippingMethodChooserPool
    ) {
        $this->deferredShippingMethodChooserPool = $deferredShippingMethodChooserPool;
    }

    /**
     * Sets shipping information to quote.
     *
     * @param Quote $quote
     * @param ShippingMethodInterface $shippingMethod
     * @return Quote
     * @throws LocalizedException if shipping can not be configured for a quote.
     * @since 100.2.0
     */
    public function configureShippingMethod(
        Quote $quote,
        ShippingMethodInterface $shippingMethod
    ): Quote {
        if ($quote->isVirtual()) {
            return $quote;
        }

        $shippingAddress = $quote->getShippingAddress();
        $shippingMethodCode = $this->getShippingMethodCodeToUse($shippingAddress, $shippingMethod);
        $shippingAddress->setShippingMethod($shippingMethodCode);

        return $quote;
    }

    /**
     * Build quote specific shipping method code based on shipping method.
     *
     * @param Address $address
     * @param ShippingMethodInterface $shippingMethod
     * @return string
     * @throws LocalizedException if shipping code can not be detected.
     */
    private function getShippingMethodCodeToUse(
        Address $address,
        ShippingMethodInterface $shippingMethod
    ): string {
        if ($shippingMethod->getCarrierCode() === DeferredShippingMethodChooserInterface::CARRIER) {
            return $this->resolveDeferredShippingMethodChoose($address, $shippingMethod);
        } else {
            return $this->getCorrespondingShippingRateCode($address, $shippingMethod);
        }
    }

    /**
     * Detects real shipping method code.
     *
     * @param Address $address
     * @param ShippingMethodInterface $shippingMethod
     * @return string
     * @throws LocalizedException if shipping method not applicable to quote.
     */
    private function getCorrespondingShippingRateCode(
        Address $address,
        ShippingMethodInterface $shippingMethod
    ): string {
        $address->setCollectShippingRates(true);
        $address->collectShippingRates();
        $shippingRates = $address->getAllShippingRates();
        foreach ($shippingRates as $shippingRate) {
            if ($shippingRate->getCarrier() === $shippingMethod->getCarrierCode()
                &&
                $shippingRate->getMethod() === $shippingMethod->getMethodCode()
            ) {
                return $shippingRate->getCode();
            }
        }
        throw new LocalizedException(__('Specified shipping method is not available.'));
    }

    /**
     * Detect real shipping method based on provided strategy and shipping address with quote data.
     *
     * @param Address $address
     * @param ShippingMethodInterface $shippingMethod
     * @return string
     * @throws LocalizedException if appropriate shipping method is not available
     */
    private function resolveDeferredShippingMethodChoose(
        Address $address,
        ShippingMethodInterface $shippingMethod
    ): string {
        $deferredShippingMethodChooser = $this->deferredShippingMethodChooserPool->get(
            $shippingMethod->getMethodCode()
        );

        $shippingMethodCode = $deferredShippingMethodChooser->choose($address);
        if (empty($shippingMethodCode)) {
            throw new LocalizedException(__('Appropriate shipping method is not available.'));
        }

        return $shippingMethodCode;
    }
}