Magento – Checkout billing address update custom attributes

billing-addresscheckoutcustom-attributesmagento2

I am trying to add an additional field to the checkout billing address. Below is the LayoutProcessor plugin that i use to do that.

// Loop all payment methods (because billing address is appended to the payments)
    $configuration = $jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children']['payment']['children']['payments-list']['children'];
    foreach ($configuration as $paymentGroup => $groupConfig) {
        if (isset($groupConfig['component']) AND $groupConfig['component'] === 'Magento_Checkout/js/view/billing-address') {

            $jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children']
            ['payment']['children']['payments-list']['children'][$paymentGroup]['children']['form-fields']['children'][$mobilePhoneAttributeCode] = [
                'component' => 'Magento_Ui/js/form/element/abstract',
                'config' => [
                    // customScope is used to group elements within a single form (e.g. they can be validated separately)
                    'customScope' => 'billingAddress.custom_attributes',
                    'customEntry' => null,
                    'template' => 'ui/form/field',
                    'id' => 'mobile-phone',
                    'elementTmpl' => 'ui/form/element/input',
                    'tooltip' => [
                        'description' => 'For delivery questions.',
                    ],
                ],
                'dataScope' => 'billingAddress.custom_attributes.' . $mobilePhoneAttributeCode,
                'label' => 'Mobile Phone',
                'provider' => 'checkoutProvider',
                'sortOrder' => 125,
                'validation' => [
                    'required-entry' => false
                ],
                'options' => [],
                'filterBy' => null,
                'customEntry' => null,
                'visible' => true,
                'id' => 'mobile-phone'
            ];
        }
    }

But when the updateAddress function runs in vendor\magento\module-checkout\view\frontend\web\js\view\billing-address.js the custom attributes are not passed in the dataScope so i can't parse the value to save it to the database.

PS I also added this field to the checkout shipping address and it works fine even with the billing address. The problem above exists only when i use diffent billing address.

Best Answer

I found the problem it with the data scope i set. Below is the correct code tested.

// Loop all payment methods (because billing address is appended to the payments)
    $configuration = $jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children']['payment']['children']['payments-list']['children'];
    foreach ($configuration as $paymentGroup => $groupConfig) {
        if (isset($groupConfig['component']) AND $groupConfig['component'] === 'Magento_Checkout/js/view/billing-address') {

            $jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children']
            ['payment']['children']['payments-list']['children'][$paymentGroup]['children']['form-fields']['children'][$mobilePhoneAttributeCode] = [
                'component' => 'Magento_Ui/js/form/element/abstract',
                'config' => [
                    // customScope is used to group elements within a single form (e.g. they can be validated separately)
                    'customScope' => 'billingAddress.custom_attributes',
                    'customEntry' => null,
                    'template' => 'ui/form/field',
                    'id' => 'mobile-phone',
                    'elementTmpl' => 'ui/form/element/input',
                    'tooltip' => [
                        'description' => 'For delivery questions.',
                    ],
                ],
                'dataScope' => $groupConfig['dataScopePrefix'] . '.custom_attributes.' . $mobilePhoneAttributeCode,
                'label' => 'Mobile Phone',
                'provider' => 'checkoutProvider',
                'sortOrder' => 125,
                'validation' => [
                    'required-entry' => false
                ],
                'options' => [],
                'filterBy' => null,
                'customEntry' => null,
                'visible' => true,
                'id' => 'mobile-phone'
            ];
        }
    }

Hope this helps someone else thanks!!

EDIT

@krybbio look at this

You first have to get the value from the billing address custom attributes and then add to the extension attributes.

I created a mixin for Magento_Checkout/js/action/set-billing-address.js

define([
    'jquery',
    'mage/utils/wrapper',
    'Magento_Checkout/js/model/quote'
], function ($, wrapper,quote) {
    'use strict';

    return function (setBillingAddressAction) {
        return wrapper.wrap(setBillingAddressAction, function (originalAction, messageContainer) {

            var billingAddress = quote.billingAddress();

            if(billingAddress != undefined) {

                if (billingAddress['extension_attributes'] === undefined) {
                    billingAddress['extension_attributes'] = {};
                }

                if (billingAddress.customAttributes != undefined) {
                    $.each(billingAddress.customAttributes, function (key, value) {

                        if($.isPlainObject(value)){
                            value = value['value'];
                        }

                        billingAddress['extension_attributes'][key] = value;
                    });
                }

            }

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