I have created a customer attribute which created dynamically from backend its fine works in customer_account_create and customer_account_edit and I stuck at saving customer attribute field data in after saving address information in the checkout form. After filling shipping address, shipping and press next button method I m getting the following error
message: "Internal Error. Details are available in Magento log file. Report ID: webapi-5d3aa1ebbf82a"
Exception log: 'Report ID: webapi-5d3aa1ebbf82a; Message: Property "TestAge" does not have corresponding setter in class "Magento\Quote\Api\Data\AddressExtensionInterface".' in D:\wamp64\www\m2\magento\vendor\magento\framework\Webapi\ErrorProcessor
and I followed this link
app/code/Cm/CustomerAttribute/etc/frontend/di.xml
<?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\Onepage">
<arguments>
<argument name="layoutProcessors" xsi:type="array">
<item name="cm__fields_layoutprocessor" xsi:type="object">Cm\CustomerAttribute\Block\Checkout\LayoutProcessor</item>
</argument>
</arguments>
</type>
</config>
app/code/ Cm/CustomerAttribute/Block/Checkout/LayoutProcessor.php
<?php
namespace Cm\CustomerAttribute\Block\Checkout;
class LayoutProcessor
{
protected $customerSession;
protected $resultPageFactory;
public function __construct(\Cm\CustomerAttribute\Helper\Customerattribute $helper,
\Magento\Customer\Api\CustomerRepositoryInterface $customerRepositoryInterface,
\Magento\Customer\Model\Session $customerSession)
{
$this->helper = $helper;
$this->customerRepositoryInterface = $customerRepositoryInterface;
$this->customerSession = $customerSession;
}
public function afterProcess(
\Magento\Checkout\Block\Checkout\LayoutProcessor $subject,
$jsLayout
) {
$attributeCollection = $this->helper->getUserDefinedAttribures();
if ($attributeCollection->getSize() > 0)
{
foreach ($attributeCollection as $attribute)
{
if ($this->helper->isAttribureForCheckoutRegister($attribute->getAttributeCode()))
{
$frontEndLabel = $attribute->getStoreLabel($this->helper->getStoreId());
$customAttributeCode = $attribute->getAttributeCode();
if($this->customerSession->isLoggedIn()) {
$customerId =$this->customerSession->getCustomer()->getId();
$customer =$this->customerRepositoryInterface->getById($customerId);
$customerAttr = $customer->getCustomAttribute($customAttributeCode)->getValue();
}
else
{
$customerAttr = NULL;
}
$fieldRequiredClass = ($attribute->getIsRequired()) ? 'true' : '' ;
if($fieldRequiredClass == '')
{
$fieldRequiredClass = false;
}
$fieldFrontendClass = ($attribute->getFrontendClass()) ? $attribute->getFrontendClass() : '';
$fieldInput =$attribute->getFrontendInput();
$attributeId = $attribute->getAttributeId();
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$attributeOptionAll = $objectManager->create(\Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection::class)
->setPositionOrder('asc')
->setAttributeFilter($attributeId)
->setStoreFilter()
->load();
$opt_val = array();
$allOptions=array();
foreach ($attributeOptionAll->getData() as $key => $v)
{
// $allid = $v['attribute_id'];
$opt_val['value'] = $v['option_id'];
$opt_val['label'] = $v['value'];
$allOptions[] = $opt_val;
}
$jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']
['shippingAddress']['children']['shipping-address-fieldset']['children'][$customAttributeCode] = $this->addNewField($customAttributeCode,$frontEndLabel, $fieldRequiredClass, $fieldFrontendClass,$fieldInput, $allOptions, $customerAttr );
}
}
}
return $jsLayout;
}
private function addNewField($customAttributeCode, $frontEndLabel, $fieldRequiredClass, $fieldFrontendClass, $fieldInput, $allOptions, $customerAttr )
{
if($fieldInput == 'text')
{
$fieldInputType = 'input';
$fieldAbstract = 'abstract';
}
elseif ($fieldInput == 'date') {
$fieldInputType = 'date';
$fieldAbstract = 'date';
}
elseif ($fieldInput == 'select') {
$fieldInputType = 'select';
$fieldAbstract = 'select';
}
elseif ($fieldInput == 'boolean') {
$fieldInputType = 'select';
$fieldAbstract = 'select';
$allOptions = [
['value' => '0', 'label' => 'No'],
['value' => '1', 'label' => 'Yes']
];
}
elseif ($fieldInput == 'textarea') {
$fieldInputType = 'textarea';
$fieldAbstract = 'textarea';
}
$customField = [
'component' => 'Magento_Ui/js/form/element/'.$fieldAbstract.'',
'config' => [
'customScope' => 'shippingAddress.custom_attributes',
'customEntry' => null,
'template' => 'ui/form/field',
'elementTmpl' => 'ui/form/element/'.$fieldInputType.'',
'rows' => 5
// 'tooltip' => [
// 'description' => 'this is what the field is for',
// ],
],
'dataScope' => 'shippingAddress.custom_attributes' . '.' . $customAttributeCode,
'label' => $frontEndLabel,
'provider' => 'checkoutProvider',
'sortOrder' => 1000,
'validation' => [$fieldFrontendClass => true ,
'required-entry' => $fieldRequiredClass],
'options' => $allOptions,
'filterBy' => null,
'customEntry' => null,
'visible' => true,
'value' => $customerAttr
];
return $customField;
}
}
app/code/Cm/CustomerAttribute/view/frontend/requirejs-config.js
var config = {
config: {
mixins: {
'Magento_Checkout/js/action/set-billing-address': {
'Cm_CustomerAttribute/js/action/set-billing-address-mixin': true
},
'Magento_Checkout/js/action/set-shipping-information': {
'Cm_CustomerAttribute/js/action/set-shipping-information-mixin': true
},
'Magento_Checkout/js/action/create-shipping-address': {
'Cm_CustomerAttribute/js/action/create-shipping-address-mixin': true
},
'Magento_Checkout/js/action/place-order': {
'Cm_CustomerAttribute/js/action/set-billing-address-mixin': true
},
'Magento_Checkout/js/action/create-billing-address': {
'Cm_CustomerAttribute/js/action/set-billing-address-mixin': true
}
}
}
};
app/code/Cm/CustomerAttribute/view/frontend/web/js/action/create-shipping-address-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) {
if (messageContainer.custom_attributes != undefined) {
$.each(messageContainer.custom_attributes , function( key, value ) {
messageContainer['custom_attributes'][key] = {'attribute_code':key,'value':value};
});
}
return originalAction(messageContainer);
});
};
});
app/code/Cm/CustomerAttribute/view/frontend/web/js/action/set-billing-address-mixin.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);
});
};
});
app/code/Cm/CustomerAttribute/view/frontend/web/js/action/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'];
}
shippingAddress['customAttributes'][key] = value;
shippingAddress['extension_attributes'][key] = value;
});
}
return originalAction(messageContainer);
});
};
});
app/code/Cm/CustomerAttribute/etc/di.xml
<?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\Model\ShippingInformationManagement">
<plugin name="Cm_CustomerAttribute::ShippingInformationManagement"
type="Cm\CustomerAttribute\Plugin\Checkout\Model\ShippingInformationManagement" sortOrder="1"/>
</type>
</config>
app/code/Cm/CustomerAttribute/Plugin/Checkout/Model/ShippingInformationManagement.php
<?php
namespace Cm\CustomerAttribute\Plugin\Checkout\Model;
class ShippingInformationManagement
{
/**
* @param \Magento\Checkout\Model\ShippingInformationManagement $subject
* @param $cartId
* @param \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation
*/
protected $helper;
protected $quoteRepository;
public function __construct(
\Bootsgrid\CustomerAttribute\Helper\Customerattribute $helper,
\Magento\Quote\Model\QuoteRepository $quoteRepository
) {
$this->helper = $helper;
$this->quoteRepository = $quoteRepository;
}
public function beforeSaveAddressInformation(
\Magento\Checkout\Model\ShippingInformationManagement $subject,
$cartId,
\Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation
) {
$extensionAttributes = $addressInformation->getShippingAddress();
$custAttributes = $extensionAttributes->getExtensionAttributes();
if($custAttributes )
{
$quote = $this->quoteRepository->getActive($cartId);
$customField = $custAttributes->getTestTextarea();
$cus = $custAttributes->getTestAge();
$quote->setTestAge($cus);
$quote->setTestTextarea($customField);
}
// error_log(print_r($custAttributes,1));
}
}
How to save the customer_field dynamically in sales_order and quote order in magento 2
image:
When using extension_attributes.xml file its saved into db but i want to pass a attribute_code dynamically in the xml file
etc/extension_attributes.xml
<?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\Quote\Api\Data\AddressInterface">
<attribute code="test_age" type="string" /> \* how to pass "test_age" dynamically *\
<attribute code="test_textarea" type="string" />
</extension_attributes>
</config>