I want to add a custom shipping and billing address field in the checkout and of course save it, in the database. I've managed to render it in the shipping and billing address forms, however I'm facing some issues saving it.
Please see my code below, data patch:
namespace Vendor\Checkout\Setup\Patch\Data;
use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Eav\Model\Config;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Customer\Setup\CustomerSetupFactory;
class RegComAddressAttribute implements DataPatchInterface{
const REGISTRU_COMERTULUI_ATTRIBUTE = 'regcom';
public function __construct(
public CustomerSetupFactory $customerSetupFactory,
public EavSetupFactory $eavSetupFactory,
public Config $eavConfig
) { }
public function apply()
{
$customerSetup = $this->customerSetupFactory->create();
// Add custom address attribute
$customerSetup->addAttribute('customer_address',
self::REGISTRU_COMERTULUI_ATTRIBUTE,
[
'label' => 'Registrul Comertului',
'input' => 'text',
'type' => 'varchar',
'source' => '',
'required' => false,
'position' => 333,
'visible' => true,
'system' => false,
'is_used_in_grid' => false,
'is_visible_in_grid' => false,
'is_filterable_in_grid' => false,
'is_searchable_in_grid' => false,
'backend' => ''
]);
// Add the attribute to forms
$attribute = $this->eavConfig->getAttribute('customer_address', self::REGISTRU_COMERTULUI_ATTRIBUTE);
$attribute->setData(
'used_in_forms',
[
'customer_address_edit',
'customer_register_address',
'adminhtml_customer_address'
]
);
$attribute->save();
}
public static function getDependencies()
{
return [];
}
public function getAliases()
{
return [];
}
}
From the db_schema.xml, i have added 2 columns, where i want to store the regcom
value"
<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
<table name="quote_address" resource="default" engine="innodb" comment="Quote Address">
<column xsi:type="varchar" name="regcom" nullable="true" length="255" comment="RegCom Shipping Field"/>
</table>
<table name="sales_order_address" resource="default" engine="innodb" comment="Sales Order Address">
<column xsi:type="varchar" name="regcom" nullable="true" length="255" comment="RegCom Billing Field"/>
</table>
</schema>
Until now, I have my custom field in the shipping and billing address forms, but it is not saved in the quote_address
table (regcom
column) Also from the backoffice, if I edit an order shipping or billing address and add manually a value for my regcom field. It is saved correctly.
For the next steps, I've made my extension_attributes.xml
file and it's content is:
<?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="regcom" type="string"/>
</extension_attributes>
</config>
Next, I've made my plugins: In the di.xml , i have:
<?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\Quote\Model\BillingAddressManagement">
<plugin disabled="false"
name="Vendor_Checkout_Plugin_Magento_Quote_Model_BillingAddressManagement" sortOrder="10"
type="Vendor\Checkout\Plugin\Magento\Quote\Model\BillingAddressManagement"/>
</type>
<type name="Magento\Quote\Model\ShippingAddressManagement">
<plugin disabled="false"
name="Vendor_Checkout_Plugin_Magento_Quote_Model_ShippingAddressManagement" sortOrder="10"
type="Vendor\Checkout\Plugin\Magento\Quote\Model\ShippingAddressManagement"/>
</type>
</config>
From the BillingAddressManagement , i have this content:
namespace Vendor\Checkout\Plugin\Magento\Quote\Model;
use Psr\Log\LoggerInterface;
use Magento\Quote\Model\BillingAddressManagement as Subject;
use Magento\Quote\Api\Data\AddressInterface;
use Exception;
class BillingAddressManagement
{
public function __construct(
protected LoggerInterface $logger
) {}
public function beforeAssign(
Subject $subject,
$cartId,
AddressInterface $address,
$useForShipping = false
) {
$extAttributes = $address->getExtensionAttributes();
if (!empty($extAttributes)) {
try {
$address->setRegcom($extAttributes->getRegcom());
} catch (Exception $error) {
$this->logger->critical($error->getMessage());
}
}
}
}
And from the ShippingAddressManagement class i have:
namespace Vendor\Checkout\Plugin\Magento\Quote\Model;
use Magento\Quote\Api\Data\AddressInterface;
use Magento\Quote\Model\ShippingAddressManagement as Subject;
use Psr\Log\LoggerInterface;
use Exception;
class ShippingAddressManagement
{
public function __construct(
protected LoggerInterface $logger
) {}
public function beforeAssign(
Subject $subject,
$cartId,
AddressInterface $address,
$useForShipping = false
) {
$extAttributes = $address->getExtensionAttributes();
if (!empty($extAttributes)) {
try {
$address->setRegcom($extAttributes->getRegcom());
} catch (Exception $error) {
$this->logger->critical($error->getMessage());
}
}
}
}
From my events.xml:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="sales_quote_address_save_before">
<observer name="vendor_checkout_save_quote_address_regcom" instance="Vendor\Checkout\Observer\SaveQuoteAddressRegcom"/>
</event>
</config>
and my observer class -> SaveQuoteAddressRegcom:
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Psr\Log\LoggerInterface;
use Magento\Quote\Model\Quote\Address;
use Vendor\Checkout\Setup\Patch\Data\RegComAddressAttribute;
class SaveQuoteAddressRegcom implements ObserverInterface
{
public function __construct(
public LoggerInterface $logger
){}
public function execute(Observer $observer)
{
/** @var Address $quoteAddress */
$quoteAddress = $observer->getEvent()->getQuoteAddress();
$extensionAttributes = $quoteAddress->getExtensionAttributes();
if ($extensionAttributes && $extensionAttributes->getRegcom()) {
try {
$quoteAddress->setData(RegComAddressAttribute::REGISTRU_COMERTULUI_ATTRIBUTE, $extensionAttributes->getRegcom());
} catch (\Exception $e) {
$this->logger->critical('Error saving regcom in quote address: ' . $e->getMessage());
}
}
}
}
The last part, the JS part: In the requirejs-config.js i have:
var config = {
config: {
mixins: {
'Magento_Checkout/js/action/set-billing-address': {
'Vendor_Checkout/js/action/set-billing-address-mixin': true
},
'Magento_Checkout/js/action/set-shipping-information': {
'Vendor_Checkout/js/action/set-shipping-information-mixin': true
},
'Magento_Checkout/js/action/create-shipping-address': {
'Vendor_Checkout/js/action/create-shipping-address-mixin': true
},
'Magento_Checkout/js/action/place-order': {
'Vendor_Checkout/js/action/set-billing-address-mixin': true
},
'Magento_Checkout/js/action/create-billing-address': {
'Vendor_Checkout/js/action/set-billing-address-mixin': true
}
}
}
};
And in the 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) {
console.log('set-shipping');
var shippingAddress = quote.shippingAddress();
if (shippingAddress['extension_attributes'] === undefined) {
shippingAddress['extension_attributes'] = {};
}
if (shippingAddress.customAttributes != undefined) {
console.log('set-shipping2');
$.each(shippingAddress.customAttributes , function( key, value ) {
console.log('set-shipping3');
if($.isPlainObject(value)){
value = value['value'];
}
shippingAddress['customAttributes'][key] = value;
shippingAddress['extension_attributes'][key] = value;
});
}
return originalAction(messageContainer);
});
};
});
Here I don't see the console.log('set-shipping2');
!!!!!!!!, maybe here is the issue!.
from the set-billing-address-mixin.js
file , i have:
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) {
console.log('set-billing');
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);
});
};
});
and the last js file: 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) {
console.log('set-shipping');
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);
});
};
});
Not sure what I am missing, why I don't see the regcom
value saved in the table.
I followed these examples:
- https://codeblog.experius.nl/magento-2-add-extra-billing-or-shipping-field-to-the-checkout/
- https://github.com/DominicWatts/Postbox/blob/master/Setup/InstallData.php
Trying this on Magento 2.4.7-p2
Please let me know your thoughts, hints etc .
Thank you in advance!