Magento2 提交Shipping Address 代码执行逻辑分析

前台JS执行

文件: vendor/magento/module-checkout/view/frontend/web/template/shipping.html

<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<li id="shipping" class="checkout-shipping-address" data-bind="fadeVisible: visible()">
    <div class="step-title" translate="'Shipping Address'" data-role="title"></div>
    <div id="checkout-step-shipping"
         class="step-content"
         data-role="content">

        <each if="!quoteIsVirtual" args="getRegion('customer-email')" render="" ></each>
        <each args="getRegion('address-list')" render="" ></each>
        <each args="getRegion('address-list-additional-addresses')" render="" ></each>

        <!-- Address form pop up -->
        <if args="!isFormInline">
            <div class="new-address-popup">
                <button type="button"
                        class="action action-show-popup"
                        click="showFormPopUp"
                        visible="!isNewAddressAdded()">
                    <span translate="'New Address'"></span>
                </button>
            </div>
            <div id="opc-new-shipping-address"
                 visible="isFormPopUpVisible()"
                 render="shippingFormTemplate"></div>
        </if>

        <each args="getRegion('before-form')" render="" ></each>

        <!-- Inline address form -->
        <render if="isFormInline" args="shippingFormTemplate"></render>
    </div>
</li>

<!--Shipping method template-->
<li id="opc-shipping_method"
    class="checkout-shipping-method"
    data-bind="fadeVisible: visible(), blockLoader: isLoading"
    role="presentation">
    <div class="checkout-shipping-method">
        <div class="step-title"
             translate="'Shipping Methods'"
             data-role="title"></div>

        <each args="getRegion('before-shipping-method-form')" render="" ></each>

        <div id="checkout-step-shipping_method"
             class="step-content"
             data-role="content"
             role="tabpanel"
             aria-hidden="false">
            <form id="co-shipping-method-form"
                  class="form methods-shipping"
                  if="rates().length"
                  submit="setShippingInformation"
                  novalidate="novalidate">

                <render args="shippingMethodListTemplate"></render>

                <div id="onepage-checkout-shipping-method-additional-load">
                    <each args="getRegion('shippingAdditional')" render="" ></each>
                </div>
                <div role="alert"
                     if="errorValidationMessage().length"
                     class="message notice">
                    <span text="errorValidationMessage()"></span>
                </div>
                <div class="actions-toolbar" id="shipping-method-buttons-container">
                    <div class="primary">
                        <button data-role="opc-continue" type="submit" class="button action continue primary">
                            <span translate="'Next'"></span>
                        </button>
                    </div>
                </div>
            </form>
            <div class="no-quotes-block"
                 ifnot="rates().length > 0"
                 translate="'Sorry, no quotes are available for this order at this time'"></div>
        </div>
    </div>
</li>

JS提交数据 :view/frontend/web/js/model/shipping-save-processor/default.js

/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

define([
    'ko',
    'Magento_Checkout/js/model/quote',
    'Magento_Checkout/js/model/resource-url-manager',
    'mage/storage',
    'Magento_Checkout/js/model/payment-service',
    'Magento_Checkout/js/model/payment/method-converter',
    'Magento_Checkout/js/model/error-processor',
    'Magento_Checkout/js/model/full-screen-loader',
    'Magento_Checkout/js/action/select-billing-address',
    'Magento_Checkout/js/model/shipping-save-processor/payload-extender'
], function (
    ko,
    quote,
    resourceUrlManager,
    storage,
    paymentService,
    methodConverter,
    errorProcessor,
    fullScreenLoader,
    selectBillingAddressAction,
    payloadExtender
) {
    'use strict';

    return {
        /**
         * @return {jQuery.Deferred}
         */
        saveShippingInformation: function () {
            var payload;

            if (!quote.billingAddress() && quote.shippingAddress().canUseForBilling()) {
                selectBillingAddressAction(quote.shippingAddress());
            }

            payload = {
                addressInformation: {
                    'shipping_address': quote.shippingAddress(),
                    'billing_address': quote.billingAddress(),
                    'shipping_method_code': quote.shippingMethod()['method_code'],
                    'shipping_carrier_code': quote.shippingMethod()['carrier_code']
                }
            };

            payloadExtender(payload);

            fullScreenLoader.startLoader();

            return storage.post(
                resourceUrlManager.getUrlForSetShippingInformation(quote),
                JSON.stringify(payload)
            ).done(
                function (response) {
                    quote.setTotals(response.totals);
                    paymentService.setPaymentMethods(methodConverter(response['payment_methods']));
                    fullScreenLoader.stopLoader();
                }
            ).fail(
                function (response) {
                    errorProcessor.process(response);
                    fullScreenLoader.stopLoader();
                }
            );
        }
    };
});

后台php执行

这里分注册登录用户和未登录的访客用户

1. 注册登录用户执行下面逻辑

http://m248.demo.com/rest/default/V1/carts/mine/shipping-information

请求方法 POST

文件: vendor/magento/module-checkout/etc/webapi.xml

 <!-- Managing My shipping information -->
    <route url="/V1/carts/mine/shipping-information" method="POST">
        <service class="Magento\Checkout\Api\ShippingInformationManagementInterface" method="saveAddressInformation"/>
        <resources>
            <resource ref="self" />
        </resources>
        <data>
            <parameter name="cartId" force="true">%cart_id%</parameter>
        </data>
    </route>

这个接口文件由: vendor/magento/module-checkout/etc/di.xml 的

Magento\Checkout\Model\ShippingInformationManagement 来实现

文件:vendor/magento/module-checkout/Model/ShippingInformationManagement.php的saveAddressInformation方法

保存收货地址然后返回付款方式

public function saveAddressInformation(
$cartId,
ShippingInformationInterface $addressInformation
): PaymentDetailsInterface {
/** @var Quote $quote */
$quote = $this->quoteRepository->getActive($cartId);
$this->validateQuote($quote);

// 直接打印到页面(仅适用于非 API 环境)
// echo '<pre>';
// print_r($addressInformation->getShippingAddress()->getData());
// die();

$address = $addressInformation->getShippingAddress();
$this->validateAddress($address);
//print_r($quote);
// print_r($address);
$this->updateCustomerShippingAddressId($quote, $address);

//die();
if (!$address->getCustomerAddressId()) {
$address->setCustomerAddressId(null);
}

try {
$billingAddress = $addressInformation->getBillingAddress();
if ($billingAddress) {
$this->updateCustomerBillingAddressId($quote, $billingAddress);
if (!$billingAddress->getCustomerAddressId()) {
$billingAddress->setCustomerAddressId(null);
}
$this->addressValidator->validateForCart($quote, $billingAddress);
$quote->setBillingAddress($billingAddress);
}

$this->addressValidator->validateForCart($quote, $address);
$carrierCode = $addressInformation->getShippingCarrierCode();
$address->setLimitCarrier($carrierCode);
$methodCode = $addressInformation->getShippingMethodCode();
$quote = $this->prepareShippingAssignment($quote, $address, $carrierCode . '_' . $methodCode);

$quote->setIsMultiShipping(false);

$this->quoteRepository->save($quote);
} catch (LocalizedException $e) {
$this->logger->critical($e);
throw new InputException(
__(
'The shipping information was unable to be saved. Error: "%message"',
['message' => $e->getMessage()]
)
);
} catch (\Exception $e) {
$this->logger->critical($e);
throw new InputException(
__('The shipping information was unable to be saved. Verify the input data and try again.')
);
}

$shippingAddress = $quote->getShippingAddress();

if (!$quote->getIsVirtual()
&& !$shippingAddress->getShippingRateByCode($shippingAddress->getShippingMethod())
) {
$errorMessage = $methodCode ?
__('Carrier with such method not found: %1, %2', $carrierCode, $methodCode)
: __('The shipping method is missing. Select the shipping method and try again.');
throw new NoSuchEntityException(
$errorMessage
);
}

/** @var PaymentDetailsInterface $paymentDetails */
$paymentDetails = $this->paymentDetailsFactory->create();
$paymentDetails->setPaymentMethods($this->paymentMethodManagement->getList($cartId));
$paymentDetails->setTotals($this->cartTotalsRepository->get($cartId));
return $paymentDetails;
}

2.未登录的访客用户执行下面逻辑

http://m248.demo.com/rest/default/V1/guest-carts/aosn0t36KW23VvMrJFNN6IjWhYYiekVy/shipping-information

请求方法

POST

发表评论