Frage

As i need custom fields for billing address under shipping address in shipping page and text entered should display as billing address all over website where billing address will display

enter image description here

War es hilfreich?

Lösung

Create a plugin that will override the Checkout Layoutpreprocessor -

Magento\Checkout\Block\Checkout\LayoutProcessor

public function aroundProcess(
        \Magento\Checkout\Block\Checkout\LayoutProcessor $subject,
        \Closure $proceed,
        array $jsLayout
    ) {
        $jsLayoutResult = $proceed($jsLayout);
        if($this->getQuote()->isVirtual()) {
            return $jsLayoutResult;
        }
        if(isset($jsLayoutResult['components']['checkout']['children']['steps']['children']['shipping-step']['children']
            ['shippingAddress']['children']['shipping-address-fieldset'])) {
            $jsLayoutResult['components']['checkout']['children']['steps']['children']['shipping-step']
            ['children']['shippingAddress']['children']['shipping-address-fieldset']['children']['street']['children'][0]['placeholder'] = __('Street Address');
            $jsLayoutResult['components']['checkout']['children']['steps']['children']['shipping-step']
            ['children']['shippingAddress']['children']['shipping-address-fieldset']['children']['street']['children'][1]['placeholder'] = __('Street line 2');
            $elements = $this->getAddressAttributes();
            $jsLayoutResult['components']['checkout']['children']['steps']['children']['shipping-step']
            ['children']['shippingAddress']['children']['billing-address'] = $this->getCustomBillingAddressComponent($elements);
            $jsLayoutResult['components']['checkout']['children']['steps']['children']['shipping-step']
            ['children']['shippingAddress']['children']['billing-address']['children']['form-fields']['children']['street']['children'][0]['placeholder'] = __('Street Address');
            $jsLayoutResult['components']['checkout']['children']['steps']['children']['shipping-step']
            ['children']['shippingAddress']['children']['billing-address']['children']['form-fields']['children']['street']['children'][1]['placeholder'] = __('Street line 2');
        }
        return $jsLayoutResult;
    }
    /**
     * Get all visible address attribute
     *
     * @return array
     */
    private function getAddressAttributes()
    {
        /** @var \Magento\Eav\Api\Data\AttributeInterface[] $attributes */
        $attributes = $this->attributeMetadataDataProvider->loadAttributesCollection(
            'customer_address',
            'customer_register_address'
        );
        $elements = [];
        foreach ($attributes as $attribute) {
            $code = $attribute->getAttributeCode();
            if ($attribute->getIsUserDefined()) {
                continue;
            }
            $elements[$code] = $this->attributeMapper->map($attribute);
            if (isset($elements[$code]['label'])) {
                $label = $elements[$code]['label'];
                $elements[$code]['label'] = __($label);
            }
        }
        return $elements;
    }
    /**
     * Prepare billing address field for shipping step for physical product
     *
     * @param $elements
     * @return array
     */
    public function getCustomBillingAddressComponent($elements)
    {
        return [
            'component' => 'SR_ModifiedCheckout/js/view/billing-address',
            'displayArea' => 'billing-address',
            'provider' => 'checkoutProvider',
            'deps' => ['checkoutProvider'],
            'dataScopePrefix' => 'billingAddress',
            'children' => [
                'form-fields' => [
                    'component' => 'uiComponent',
                    'displayArea' => 'additional-fieldsets',
                    'children' => $this->merger->merge(
                        $elements,
                        'checkoutProvider',
                        'billingAddress',
                        [
                            'country_id' => [
                                'sortOrder' => 115,
                            ],
                            'region' => [
                                'visible' => false,
                            ],
                            'region_id' => [
                                'component' => 'Magento_Ui/js/form/element/region',
                                'config' => [
                                    'template' => 'ui/form/field',
                                    'elementTmpl' => 'ui/form/element/select',
                                    'customEntry' => 'billingAddress.region',
                                ],
                                'validation' => [
                                    'required-entry' => true,
                                ],
                                'filterBy' => [
                                    'target' => '${ $.provider }:${ $.parentScope }.country_id',
                                    'field' => 'country_id',
                                ],
                            ],
                            'postcode' => [
                                'component' => 'Magento_Ui/js/form/element/post-code',
                                'validation' => [
                                    'required-entry' => true,
                                ],
                            ],
                            'company' => [
                                'validation' => [
                                    'min_text_length' => 0,
                                ],
                            ],
                            'fax' => [
                                'validation' => [
                                    'min_text_length' => 0,
                                ],
                            ],
                            'telephone' => [
                                'config' => [
                                    'tooltip' => [
                                        'description' => __('For delivery questions.'),
                                    ],
                                ],
                            ],
                        ]
                    ),
                ],
            ],
        ];
    }

If you see the file has components used for JS - So in order to do that you will have to create JS files for billing-address.js -

/*jshint browser:true*/
/*global define*/
define(
    [
        'ko',
        'underscore',
        'jquery',
        'Magento_Ui/js/form/form',
        'Magento_Customer/js/model/customer',
        'Magento_Customer/js/model/address-list',
        'Magento_Checkout/js/model/quote',
        'Magento_Checkout/js/action/create-billing-address',
        'Magento_Checkout/js/action/select-billing-address',
        'Magento_Checkout/js/checkout-data',
        'Magento_Checkout/js/model/checkout-data-resolver',
        'Magento_Customer/js/customer-data',
        'Magento_Checkout/js/action/set-billing-address',
        'Magento_Ui/js/model/messageList',
        'mage/translate'
    ],
    function (
        ko,
        _,
        $,
        Component,
        customer,
        addressList,
        quote,
        createBillingAddress,
        selectBillingAddress,
        checkoutData,
        checkoutDataResolver,
        customerData,
        setBillingAddressAction,
        globalMessageList,
        $t

    ) {
        'use strict';

        var newAddressOption = {
                /**
                 * Get new address label
                 * @returns {String}
                 */
                getAddressInline: function () {
                    return $t('New Address');
                },
                customerAddressId: null
            },
            countryData = customerData.get('directory-data'),
            addressOptions = addressList().filter(function (address) {
                return address.getType() == 'customer-address';
            });

        addressOptions.push(newAddressOption);

        return Component.extend({
            defaults: {
                template: 'SR_ModifiedCheckout/billing-address'
            },
            currentBillingAddress: quote.billingAddress,
            addressOptions: addressOptions,
            customerHasAddresses: addressOptions.length > 1,

            /**
             * Init component
             */
            initialize: function () {
                this._super();
            },

            /**
             * @return {exports.initObservable}
             */
            initObservable: function () {
                this._super()
                    .observe({
                        selectedAddress: null,
                        isAddressFormVisible: false,
                        isAddressSameAsShipping: true,
                        saveInAddressBook: 1,
                        isAddressFormListVisible:false
                    });

                return this;
            },

            canUseShippingAddress: ko.computed(function () {
                return !quote.isVirtual() && quote.shippingAddress() && quote.shippingAddress().canUseForBilling();
            }),

            /**
             * @param {Object} address
             * @return {*}
             */
            addressOptionsText: function (address) {
                return address.getAddressInline();
            },

            /**
             * @return {Boolean}
             */
            useShippingAddress: function () {
                if (this.isAddressSameAsShipping()) {
                    this.isAddressFormVisible(false);
                    this.isAddressFormListVisible(false);
                } else {
                    if(addressOptions.length == 1) {
                        this.isAddressFormVisible(true);
                    } else {
                        this.isAddressFormListVisible(true);
                    }
                }
                return true;
            },
            /**
             * @param {Object} address
             */
            onAddressChange: function (address) {
                if(address) {
                    this.isAddressFormVisible(false);
                } else {
                    this.isAddressFormVisible(true);
                }
            },

            /**
             * @param {int} countryId
             * @return {*}
             */
            getCountryName: function (countryId) {
                return countryData()[countryId] != undefined ? countryData()[countryId].name : '';
            },

            /**
             * Get code
             * @param {Object} parent
             * @returns {String}
             */
            getCode: function (parent) {
                return _.isFunction(parent.getCode) ? parent.getCode() : 'shared';
            }
        });
    }
);

Similarly shipping-mixin.js within mixin folder -

define([
    'jquery',
    'underscore',
    'Magento_Ui/js/form/form',
    'ko',
    'Magento_Customer/js/model/customer',
    'Magento_Customer/js/model/address-list',
    'Magento_Checkout/js/model/address-converter',
    'Magento_Checkout/js/model/quote',
    'Magento_Checkout/js/action/create-shipping-address',
    'Magento_Checkout/js/action/select-shipping-address',
    'Magento_Checkout/js/action/create-billing-address',
    'Magento_Checkout/js/action/select-billing-address',
    'Magento_Checkout/js/action/set-shipping-information',
    'Magento_Checkout/js/model/step-navigator',
    'Magento_Checkout/js/checkout-data'
], function(
    $,
    _,
    Component,
    ko,
    customer,
    addressList,
    addressConverter,
    quote,
    createShippingAddress,
    selectShippingAddress,
    createBillingAddress,
    selectBillingAddress,
    setShippingInformationAction,
    stepNavigator,
    checkoutData
) {
    'use strict';

    return function (target) {
        return target.extend({
            defaults: {
                template: 'SR_ModifiedCheckout/address'
            },
            setShippingInformation: function () {
                if (this.validateShippingInformation() && this.validateBillingInformation()) {
                    setShippingInformationAction().done(
                        function () {
                            stepNavigator.next();
                        }
                    );
                }
            },
            validateBillingInformation: function() {

                if($('[name="billing-address-same-as-shipping"]').is(":checked")) {
                    if (this.isFormInline) {
                        var shippingAddress = quote.shippingAddress();
                        var addressData = addressConverter.formAddressDataToQuoteAddress(
                            this.source.get('shippingAddress')
                        );
                        //Copy form data to quote shipping address object
                        for (var field in addressData) {

                            if (addressData.hasOwnProperty(field) &&
                                shippingAddress.hasOwnProperty(field) &&
                                typeof addressData[field] != 'function' &&
                                _.isEqual(shippingAddress[field], addressData[field])
                            ) {
                                shippingAddress[field] = addressData[field];
                            } else if (typeof addressData[field] != 'function' &&
                                !_.isEqual(shippingAddress[field], addressData[field])) {
                                shippingAddress = addressData;
                                break;
                            }
                        }

                        if (customer.isLoggedIn()) {
                            shippingAddress.save_in_address_book = 1;
                        }
                        var newBillingAddress = createBillingAddress(shippingAddress);
                        selectBillingAddress(newBillingAddress);
                    } else {
                        selectBillingAddress(quote.shippingAddress());
                    }

                    return true;
                }

                var selectedAddress = $('[name="billing_address_id"]').val();
                if(selectedAddress) {
                    var res = addressList.some(function (addressFromList) {
                        if (selectedAddress == addressFromList.customerAddressId) {
                            selectBillingAddress(addressFromList);
                            return true;
                        }
                        return false;
                    });

                    return res;
                }

                this.source.set('params.invalid', false);
                this.source.trigger('billingAddress.data.validate');

                if (this.source.get('params.invalid')) {
                    return false;
                }

                var addressData = this.source.get('billingAddress'),
                    newBillingAddress;

                if ($('#billing-save-in-address-book').is(":checked")) {
                    addressData.save_in_address_book = 1;
                }

                newBillingAddress = createBillingAddress(addressData);
                selectBillingAddress(newBillingAddress);

                return true;
            }
        });
    }
});

You will be required to add the requirejs-config.js for mapping -

var config = {
    config: {
        mixins: {
            'Magento_Checkout/js/view/shipping': {
                'SR_ModifiedCheckout/js/mixin/shipping-mixin': true
            }
        }
    }
};

The within web/template/billing-address.html

<div class="checkout-billing-address">

    <div class="billing-address-same-as-shipping-block field choice" data-bind="visible: canUseShippingAddress()">
        <input type="checkbox" name="billing-address-same-as-shipping"
               data-bind="checked: isAddressSameAsShipping, click: useShippingAddress, attr: {id: 'billing-address-same-as-shipping'}"/>
        <label data-bind="attr: {for: 'billing-address-same-as-shipping'}">
            <span data-bind="i18n: 'This address is also my billing address'"></span>
        </label>
    </div>
    <fieldset class="fieldset">
        <!-- ko template: 'SR_ModifiedCheckout/billing-address/list' --><!-- /ko -->
        <!-- ko template: 'SR_ModifiedCheckout/billing-address/form' --><!-- /ko -->
    </fieldset>

</div>

Similarly - web/template/address.html

<li id="shipping" class="checkout-shipping-address" data-bind="fadeVisible: visible()">
    <div class="step-title" data-bind="i18n: 'Shipping Address'" data-role="title"></div>
    <div id="checkout-step-shipping"
         class="step-content"
         data-role="content">

        <!-- ko if: (!quoteIsVirtual) -->
            <!-- ko foreach: getRegion('customer-email') -->
                <!-- ko template: getTemplate() --><!-- /ko -->
            <!--/ko-->
        <!--/ko-->

        <!-- ko foreach: getRegion('address-list') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->

        <!-- ko foreach: getRegion('address-list-additional-addresses') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->

        <!-- Address form pop up -->
        <!-- ko if: (!isFormInline) -->
        <button type="button"
                data-bind="click: showFormPopUp, visible: !isNewAddressAdded()"
                class="action action-show-popup">
            <span data-bind="i18n: 'New Address'"></span></button>
        <div id="opc-new-shipping-address" data-bind="visible: isFormPopUpVisible()">
            <!-- ko template: 'Magento_Checkout/shipping-address/form' --><!-- /ko -->
        </div>
        <!-- /ko -->

        <!-- ko foreach: getRegion('before-form') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->

        <!-- Inline address form -->
        <!-- ko if: (isFormInline) -->
        <!-- ko template: 'Magento_Checkout/shipping-address/form' --><!-- /ko -->
        <!-- /ko -->

        <!-- ko if: (isFormInline) -->
        <span class="mandatory" data-bind="i18n: 'Mandatory fields'"></span>
        <!-- /ko -->
        <!-- Inline Billing address form -->
        <!-- ko foreach: getRegion('billing-address') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!-- /ko -->
    </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" data-bind="i18n: 'Shipping Methods'" data-role="title"></div>
        <!-- ko foreach: getRegion('before-shipping-method-form') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!-- /ko -->
        <div id="checkout-step-shipping_method"
             class="step-content"
             data-role="content"
             role="tabpanel"
             aria-hidden="false">
            <!-- ko if: rates().length  -->
            <form class="form methods-shipping" id="co-shipping-method-form" data-bind="submit: setShippingInformation" novalidate="novalidate">
                <div id="checkout-shipping-method-load">
                    <table class="table-checkout-shipping-method">
                        <thead>
                            <tr class="row">
                                <th class="col col-method" data-bind="i18n: 'Select Method'"></th>
                                <th class="col col-price" data-bind="i18n: 'Price'"></th>
                                <th class="col col-method" data-bind="i18n: 'Method Title'"></th>
                                <th class="col col-carrier" data-bind="i18n: 'Carrier Title'"></th>
                            </tr>
                        </thead>
                        <tbody>

                        <!--ko foreach: { data: rates(), as: 'method'}-->
                        <tr class="row" data-bind="click: $parent.selectShippingMethod">
                            <td class="col col-method">
                                <!-- ko ifnot: method.error_message -->
                                <!-- ko if: $parent.rates().length == 1 -->
                                <input class="radio"
                                       type="radio"
                                       data-bind="attr: {
                                                    checked: $parent.rates().length == 1,
                                                    'value' : method.carrier_code + '_' + method.method_code,
                                                    'id': 's_method_' + method.method_code,
                                                    'aria-labelledby': 'label_method_' + method.method_code + '_' + method.carrier_code + ' ' + 'label_carrier_' + method.method_code + '_' + method.carrier_code
                                                 }" />
                                <!-- /ko -->
                                <!--ko ifnot: ($parent.rates().length == 1)-->
                                <input type="radio"
                                       data-bind="
                                                value: method.carrier_code + '_' + method.method_code,
                                                checked: $parent.isSelected,
                                                attr: {
                                                    'id': 's_method_' + method.carrier_code + '_' + method.method_code,
                                                    'aria-labelledby': 'label_method_' + method.method_code + '_' + method.carrier_code + ' ' + 'label_carrier_' + method.method_code + '_' + method.carrier_code
                                                },
                                                click: $parent.selectShippingMethod"
                                       class="radio"/>
                                <!--/ko-->
                                <!-- /ko -->
                            </td>
                            <td class="col col-price">
                                <!-- ko foreach: $parent.getRegion('price') -->
                                <!-- ko template: getTemplate() --><!-- /ko -->
                                <!-- /ko -->
                            </td>

                            <td class="col col-method"
                                    data-bind="text: method.method_title, attr: {'id': 'label_method_' + method.method_code + '_' + method.carrier_code}"></td>

                            <td class="col col-carrier"
                                    data-bind="text: method.carrier_title, attr: {'id': 'label_carrier_' + method.method_code + '_' + method.carrier_code}"></td>
                        </tr>

                        <!-- ko if:  method.error_message -->
                        <tr class="row row-error">
                            <td class="col col-error" colspan="4">
                                <div class="message error">
                                    <div data-bind="text: method.error_message"></div>
                                </div>
                                <span class="no-display">
                                    <input type="radio" data-bind="attr: {'value' : method.method_code, 'id': 's_method_' + method.method_code}"/>
                                </span>
                            </td>
                        </tr>
                        <!-- /ko -->

                        <!-- /ko -->
                        </tbody>
                    </table>
                </div>

                <div id="onepage-checkout-shipping-method-additional-load">
                    <!-- ko foreach: getRegion('shippingAdditional') -->
                    <!-- ko template: getTemplate() --><!-- /ko -->
                    <!-- /ko -->
                </div>
                <!-- ko if: errorValidationMessage().length > 0 -->
                <div class="message notice">
                    <span><!-- ko text: errorValidationMessage()--><!-- /ko --></span>
                </div>
                <!-- /ko -->
                <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><!-- ko i18n: 'Next'--><!-- /ko --></span>
                        </button>
                    </div>
                </div>
            </form>
            <!-- /ko -->
            <!-- ko ifnot: rates().length > 0 --><div class="no-quotes-block"><!-- ko i18n: 'Sorry, no quotes are available for this order at this time'--><!-- /ko --></div><!-- /ko -->
        </div>
    </div>
</li>

For adding the billing address form add - web/template/billing-address/form.html

<div class="billing-address-form" data-bind="fadeVisible: isAddressFormVisible">
    <div class="step-title" data-bind="i18n: 'Billing Address'" data-role="title"></div>
    <!-- ko foreach: getRegion('before-fields') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
    <!--/ko-->
    <fieldset id="billing-new-address-form" class="fieldset address">
        <!-- ko foreach: getRegion('additional-fieldsets') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->
        <!-- ko if: (isCustomerLoggedIn) -->
        <div class="field save-address">
            <input type="checkbox" class="checkbox" id="billing-save-in-address-book" data-bind="checked: saveInAddressBook" />
            <label class="label" for="billing-save-in-address-book">
                <span data-bind="i18n: 'Save in address book'"></span>
            </label>
        </div>
        <!-- /ko -->
        <span class="mandatory" data-bind="i18n: 'Mandatory fields'"></span>
    </fieldset>
</div>

And for billing addresses list - web/template/billing-address/list.html

<!-- ko if: (customerHasAddresses && isAddressFormListVisible)-->
<div class="field field-select-billing">
    <div class="control" data-bind="if: (addressOptions.length > 1)">
        <select class="select" id="billing_address_id" name="billing_address_id" data-bind="
        options: addressOptions,
        optionsText: addressOptionsText,
        optionsValue: 'customerAddressId',
        value: selectedAddress,
        event: {change: onAddressChange(selectedAddress())};
    "></select>
    </div>
</div>
<!-- /ko -->

The above code has been written by Sohel Rana, and the link to the module is this You can also directly install the plugin

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit magento.stackexchange
scroll top