magento2 checkout增长address field

我要在checkout加一个留言输入栏,能够在后台order detail查获得的,magento官方wiki有如下教程正好知足个人需求
http://devdocs.magento.com/gu...
然而我仍是花了不少时间没搞定,官方教程也许是错的,也许是不完整。教程的实现方法没法在后台读到数据,完整应该包括建立attribute,但教程里没有。后来不得不用本身的方法实现,个人实现原理是在checkout模板上加个input,用mixins把保存触发事件加到shipping进入下一步的按钮,触发事件再调用本身开发的WEBAPI,把message保存到quote表的message字段,再用event把quote message搬到order message。javascript

step1 先给quote和sales_order表添加message字段

quote和sales_order不少字段对应,当你把产品加入到cart,会建立一个quote,cart的数据就会存到quote中,checkout到了正式支付后,order才会被真正产生出来,其实数据库里的操做是数据从quote搬到了sales_order。因此添加字段,应该在quote与sales_order同时添加,数据才会传到最终的order。php

Setup/InstallSchema.php (忽略类的细节,只有关键代码)html

$setup->startSetup();

$setup->getConnection()->addColumn(
    $setup->getTable('quote'),
    'message',
    [
        'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
        'length' => 2048,
        'nullable' => false,
        'default' => '',
        'comment' => 'checkout message'
    ]
);
$setup->getConnection()->addColumn(
    $setup->getTable('sales_order'),
    'message',
    [
        'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
        'length' => 2048,
        'nullable' => false,
        'default' => '',
        'comment' => 'checkout message'
    ]
);

$setup->endSetup();

step2 建立webapi,把message保存到quote表

建立WEBAPI教程
https://segmentfault.com/a/11...
值得注意的是interface中的注释是必须的,并且参数声明必须有类型,不然系统会把参数当成是类。这对于老手特别容易出错。java

<route url="/V1/<module>/checkout" method="POST">
    <service class="<vendor>\<module>\Api\ManagementInterface" method="saveMessage"/>
    <resources>
        <resource ref="self" />
    </resources>
    <data>
        <parameter name="cartId" force="true">%cart_id%</parameter>
    </data>
</route>
protected $quoteRepository;

public function __construct(
    \Magento\Quote\Api\CartRepositoryInterface $quoteRepository
) {
    $this->quoteRepository = $quoteRepository;
}

public function saveMessage($cartId, $message) {
    $quote = $this->quoteRepository->get($cartId);
    $quote->setMessage($message);
    $this->quoteRepository->save($quote);
    return true;
}

step3 把input加到checkout

我选择加到shipping这一步
app/design/frontend/<vendor>/<theme>/Magento_Checkout/web/template/shipping.htmljquery

<textarea id="checkout_comment"></textarea>

step4 mixins注入到shpping的下一步按钮

requirejs-config.jsweb

var config = {
    config: {
        mixins: {
            'Magento_Checkout/js/action/set-shipping-information': {
                '<Vendor_Module>/js/mixin/set-shipping-information': true
            }
        }
    }
};

js/mixin/set-shipping-information.js数据库

/*jshint browser:true jquery:true*/
/*global alert*/
define([
    'jquery',
    'mage/utils/wrapper',
    'Magento_Checkout/js/model/quote',
    'mage/storage',
    'Magento_Checkout/js/model/url-builder'
], function ($, wrapper, quote, storage, urlBuilder) {
    'use strict';

    return function (setShippingInformationAction) {

        return wrapper.wrap(setShippingInformationAction, function (originalAction) {

            if($('#checkout_comment').length > 0 && $('#checkout_comment').val() != '') {
                storage.post(
                    urlBuilder.createUrl('/<module>/checkout', {}),
                    JSON.stringify({
                        comment: $('#checkout_comment').val()
                    })
                ).fail(
                    function (response) {
                        console.log(response);
                    }
                );
            }

            return originalAction();
        });
    };
});

js mixins是magento实现的js注入功能,让js能实现像DI同样的注入效率,不得不说是一个亮点。具体内容能够参考:http://devdocs.magento.com/gu...segmentfault

step5 生成订单时把quote数据般到sales_order

etc/events.xmlapi

<event name="sales_model_service_quote_submit_before">
    <observer name="checkout_message_sales_model_service_quote_submit_before" instance="<vendor>\<module>\Observer\SaveOrderBeforeSalesModelQuoteObserver" />
</event>

SaveOrderBeforeSalesModelQuoteObserver.phpapp

private $attributes = [
    'message'
];

public function execute(\Magento\Framework\Event\Observer $observer)
{
    /* @var \Magento\Sales\Model\Order $order */
    $order = $observer->getEvent()->getData('order');
    /* @var \Magento\Quote\Model\Quote $quote */
    $quote = $observer->getEvent()->getData('quote');

    foreach ($this->attributes as $attribute) {
        if ($quote->hasData($attribute)) {
            $order->setData($attribute, $quote->getData($attribute));
        }
    }

    return $this;
}

step6 让message在后台显示

为了修改后台的模板,我直接修改了magento的默认模板了,这是不建议的作法,但复写后台默认模板是件比较麻烦的事,后台并无设置给后台换新模板
vendor/magento/module-sales/view/adminhtml/templates/order/view/info.phtml

<?php /* @escapeNotVerified */ echo $_order->getData('message'); ?>

另外一种更好的方法

以上方法须要建立新的webapi,能够利用原有的webapi固然更省事,但须要深刻理解webapi的拓展机制,主要须要用到extension attributes
http://devdocs.magento.com/gu...
以在shipping addess追加属性为例,如下是完整过程。

Setup

$this->_quoteSetup = $this->_quoteSetupFactory->create( [ 'setup' => $setup ] );
$this->_salesSetup = $this->_salesSetupFactory->create( [ 'setup' => $setup ] );

$this->_quoteSetup->addAttribute( 'quote_address', 'delivery_date_1', [ 'type' => 'varchar' ] );
$this->_salesSetup->addAttribute( 'order_address', 'delivery_date_1', [ 'type' => 'varchar' ] );

$this->_quoteSetup->addAttribute( 'quote_address', 'delivery_date_2', [ 'type' => 'varchar' ] );
$this->_salesSetup->addAttribute( 'order_address', 'delivery_date_2', [ 'type' => 'varchar' ] );

声明Extension类

etc/extension_attributes.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\Quote\Api\Data\AddressInterface">
        <attribute code="delivery_date_1" type="string">
            <resources>
                <resource ref="Magento_Customer::customer" />
            </resources>
        </attribute>
        <attribute code="delivery_date_2" type="string">
            <resources>
                <resource ref="Magento_Customer::customer" />
            </resources>
        </attribute>
    </extension_attributes>
</config>

上边这步的做用仅仅是为系统自动生成的 extension 类(本例为 MagentoQuoteApiDataAddressExtension,可在 var/generation/Magento/Quote/Api/Data 目录找到)添加 getter 和 setter。

数据保存到quote_address

完成了extension attributes的声明,与数据表字段建立,系统并不会把WEBAPI提交过来的extension attributes自动保存到表中,这须要写代码完成这个操做。方法是让Model在save时就把extension attributes写入属性,Model的属性会自动更新至数据表。不该该直接修改原代码,建议使用event机制。
etc/di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Quote\Model\Quote\Address">
        <plugin name="xxxx_checkout_extension_attributes_processor" type="<Vendor>\<Module>\Plugin\Magento\Quote\Model\Quote\Address" />
    </type>
</config>

Address.php

namespace Infinity\Checkout\Plugin\Magento\Quote\Model\Quote;

class Address
{
    public function afterBeforeSave(\Magento\Quote\Model\Quote\Address $subject, \Magento\Quote\Model\Quote\Address $return) {

        $extensionAttributes = $return->getExtensionAttributes();
        if($extensionAttributes != null) {
            $return->addData( $extensionAttributes->__toArray() );
        }
        return $return;
    }
}

数据从quote表到order表

etc/events.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="sales_model_service_quote_submit_before">
        <observer name="xxxxx_checkout_sales_model_service_quote_submit_before" instance="<Vendor>\<Model>\Observer\SaveOrderBeforeSalesModelQuoteObserver" />
    </event>
</config>

SaveOrderBeforeSalesModelQuoteObserver.php

namespace Infinity\Checkout\Observer;

use Magento\Framework\Event\ObserverInterface;

class SaveOrderBeforeSalesModelQuoteObserver implements ObserverInterface
{
    public function execute(\Magento\Framework\Event\Observer $observer) {
        /* @var \Magento\Sales\Model\Order $order */
        $order = $observer->getEvent()->getData('order');
        /* @var \Magento\Quote\Model\Quote $quote */
        $quote = $observer->getEvent()->getData('quote');

        $attributes = ['delivery_date_1', 'delivery_date_2', 'installation_date_1', 'installation_date_2'];

        foreach($attributes as $attribute) {
            if($quote->getShippingAddress()->hasData($attribute)) {
                $order->getShippingAddress()->setData($attribute, $quote->getShippingAddress()->getData($attribute));
            }
        }

        return $this;
    }
}

checkout过程当中提交extension attributes

vendor/magento/module-checkout/view/frontend/web/js/model/shipping-save-processor/default.js

var shippingAddress = quote.shippingAddress();
shippingAddress['extension_attributes'] = {
    delivery_date_1: 'xxxxx',
    delivery_date_2: 'yyyyy'
};
quote.shippingAddress(shippingAddress);

后台order detail 里显示这个数据

Address在后台、PDF或者是单行状况下,都是能够指定模板的,可在Customer Configuration > Address Templates设置对应模板。可是在2.1版本中新增的Address字段没法被模板引用,官方也认可这个BUG,而且可能在2.4才获得解决。我目前能找到的办法是利用customer_address_format事件。

etc/events.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="customer_address_format">
        <observer name="infinity_checkout_customer_address_format" instance="Infinity\Checkout\Observer\CustomerAddressFormat" />
    </event>
</config>

app/code/Infinity/Checkout/Observer/CustomerAddressFormat.php

namespace Infinity\Checkout\Observer;

use Magento\Framework\Event\ObserverInterface;

class CustomerAddressFormat implements ObserverInterface
{
    public function execute(\Magento\Framework\Event\Observer $observer) {
        $formatType = $observer->getEvent()->getData('type');
        $address = $observer->getEvent()->getData('address');

        $format = $formatType->getDefaultFormat();
        if($formatType->getCode() == 'html') {
            $html ='';
            if($address->getData('delivery_date_1')) {
                $html .= __('Delivery Date').':'.$address->getData('delivery_date_1');
                if($address->getData('delivery_date_2'))
                    $html .= ':'.__('or').' '.$address->getData('delivery_date_2');
                $html .= '<br/>';
            }
            $formatType->setData('default_format', $format.'<br/>'.$html);
        }
    }
}

Quote Item to Order Item

https://stackoverflow.com/que...

相关文章
相关标签/搜索