0

I have an issue with a custom attribute in the shipping address failing to save for Logged In customers when he clicks on "Add new address" in checkout. If he uses an already saved address with a custom attribute then everything works. If a guest user is trying to finish checkout with a custom attribute field then it also works as expected. The issue is only for the logged-in user when he clicks on the "Add new address" button and tries to enter his address from checkout.

In developers console in network tab, the following call is failing - /rest/es_es/V1/carts/mine/shipping-information with the following error message -

"Error occurred during "shipping_address" processing. Error occurred during "extension_attributes" processing. Error occurred during "door_number" processing. The "array" value's type is invalid. The "string" type was expected. Verify and try again."

This is my 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="door_number" type="string"/>
    </extension_attributes>
</config>

This is my set-shipping-information-mixin.js -

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

    return function (setShippingInformationAction) {
        return wrapper.wrap(setShippingInformationAction, function (originalAction, messageContainer) {
            var shippingAddress = quote.shippingAddress();

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

            if (shippingAddress.customAttributes !== undefined) {
                $.each(shippingAddress.customAttributes, function(key, value) {
                    if ($.isPlainObject(value)) {
                        value = value['value'];
                        key = this.attribute_code;
                    }

                    shippingAddress['customAttributes'][key] = value;
                    shippingAddress['extension_attributes'][key] = value;
                });
            }

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

What could be the reason why custom attributes are failing only for logged-in users when adding new address through checkout but working for logged-in customer saved addresses and also for guest users going through the checkout no issues appear. What I am missing?

Thank you!

3
  • You need to store extension attribute using plugin. Check this blog dckap.com/blog/extension-attributes-in-magento2 Jun 21, 2021 at 7:36
  • Hello @RahulBarot, tried your link, using the plugin example in your given link it throws an error, that "Allowed memory size of 792723456 bytes exhausted (tried to allocate 20480 bytes) in /var/www/magento/vendor/magento/framework/Interception/Interceptor.php on line 102"
    – help
    Jun 21, 2021 at 8:33
  • Please check added answer.
    – ZealousWeb
    Jun 21, 2021 at 12:36

1 Answer 1

1

You need to follow below steps to save custom field value.

Below code will be work for both the login and guest user. Also please create field in "quote_address" and "sales_order_address" table first. Here i have shown you code according to the field "customtype". Please change field according to yours.

Step 1:- Create file extension_attributes.xml under path Zmage/Customfield/etc

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\Checkout\Api\Data\ShippingInformationInterface">
        <attribute code="customtype" type="string"/>
    </extension_attributes>
</config>

Step 2:- Create requirejs-config.js file under path Zmage/Customfield/view/frontend/

var config = {
    "map": {
        "*": {
            "Magento_Checkout/js/model/shipping-save-processor/default" : "Zmage_Customfield/js/shipping-save-processor-default-override"
        }
    }
};

Step 3:- Create file shipping-save-processor-default-override.js under path Zmage/Customfield/view/frontend/web/js/

define(
    [
        'ko',
        'jquery',
        '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'
    ],
    function (ko, $, quote, resourceUrlManager, storage, paymentService, methodConverter, errorProcessor) {
        'use strict';
        return {
            saveShippingInformation: function() {
                var payload = {

                addressInformation: {
                        shipping_address: quote.shippingAddress(),
                        shipping_method_code: quote.shippingMethod().method_code,
                        shipping_carrier_code: quote.shippingMethod().carrier_code,
                        extension_attributes: {
                            customtype: $('[name="custom_attributes[customtype]"]').val()
                        }
                    }
                };

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

Step 4:- Create di.xml file under path Zmage/Customfield/etc

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Checkout\Block\Checkout\LayoutProcessor">
        <plugin name="add_custom_field_checkout_form" type="Zmage\Customfield\Plugin\Checkout\LayoutProcessor" sortOrder="100"/>
    </type>
    <type name="Magento\Checkout\Model\ShippingInformationManagement">
        <plugin name="save-in-quote" type="Zmage\Customfield\Plugin\Checkout\ShippingInformationManagementPlugin" sortOrder="12349"/>
    </type>
    <type name="Magento\Quote\Model\Quote\Address\ToOrderAddress">
        <plugin name="item_quote_to_order_address" type="Zmage\Customfield\Plugin\ItemQuoteToOrderAddress"/>
    </type>
</config>

Step 5:- Please create file LayoutProcessor.php under path Zmage/Customfield/Plugin/Checkout

Below code is for creating custom field in shipping address form.

<?php
namespace Zmage\Customfield\Plugin\Checkout;

class LayoutProcessor
{
    /**
     * @param \Magento\Checkout\Block\Checkout\LayoutProcessor $subject
     * @param array $jsLayout
     * @return array
     */
    public function afterProcess(
        \Magento\Checkout\Block\Checkout\LayoutProcessor $subject,
        array  $jsLayout
    ) {
        $customAttributeCode = 'customtype';

        $customField = [
            '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' => 'shippingAddress.custom_attributes',
                'customEntry' => null,
                'template' => 'ui/form/field',
                'elementTmpl' => 'ui/form/element/input',
                'tooltip' => [
                    'description' => 'this is what the field is for',
                ],
            ],
            'dataScope' => 'shippingAddress.custom_attributes' . '.' . $customAttributeCode,
            'label' => 'Custom type',
            'provider' => 'checkoutProvider',
            'sortOrder' => 10,
            'validation' => [
               'required-entry' => true
            ],
            'options' => [],
            'filterBy' => null,
            'customEntry' => null,
            'visible' => true,
        ];

        $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']['shippingAddress']['children']['shipping-address-fieldset']['children'][$customAttributeCode] = $customField;
 
        return $jsLayout;
    }
}

Step 6:- Create ShippingInformationManagementPlugin.php file under path Zmage/Customfield/Plugin/Checkout

Below code is for saving custom field value in quote address table.

<?php

namespace Zmage\Customfield\Plugin\Checkout;

/**
 * Class ShippingInformationManagementPlugin
 * @package Oye\Deliverydate\Model\Checkout
 */
class ShippingInformationManagementPlugin
{
    public function beforeSaveAddressInformation(
        \Magento\Checkout\Model\ShippingInformationManagement $subject,
        $cartId,
        \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation
    ) {
        $extAttributes = $addressInformation->getExtensionAttributes();
        $customType = $extAttributes->getCustomtype();
        $shippingAddress = $addressInformation->getShippingAddress();
        $shippingAddress->setCustomtype($customType);
    }
}

Step 7:- Create ItemQuoteToOrderAddress.php file under path Zmage/Customfield/Plugin

Below code is for saving custom field value from quote address to order address table.

<?php
namespace Zmage\Customfield\Plugin;
 
class ItemQuoteToOrderAddress
{
    public function aroundConvert(
        \Magento\Quote\Model\Quote\Address\ToOrderAddress $subject,
        \Closure $proceed,
        \Magento\Quote\Model\Quote\Address $object,
        $data = []
    ) {
        $orderAddress = $proceed($object, $data);
        if($object->getCustomtype()){
            $orderAddress->setCustomtype($object->getCustomtype());
        }
        
        return $orderAddress;
    }
}

Above code is practically tested and it is working fine. Please check and let me know.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.