Magento – Deny change billing address customer

billing-addressmagento2

This title is somehow misleading. I will explain the what I want to achieve.

I know it is possible by default to change the billing address on checkout. Since we are only selling to business clients I kinda want to disable that overall.

The billing address that they provide during the registration should not be editable without us knowing. OR they should not be able to order without a valid VAT id filled in. But even so when they have filled in a valid VAT id we still need to check those (otherwise we have problems with the law).

How it works now :

On viewing our website they can not see prices , after a quick registration we are able to manually see if they have filled in a valid VAT id and therefor putting them in a group manually (since we manually check before allowing them to see prices). When they we have putted them in a group and checked the VAT they can see prices and order. But now everything what happens before has no effect. They can still decide to order without VAT at the checkout and change the address.

Any solutions ?

Would really help me out!

Best Answer

I think you are asking two questions. I'll try to answer the first one. This is how I tried to always use the default billing address:

As far as I know a billing address is tied to the chosen payment method. In order to disallow the customer to change the billing address, I made two changes:

  1. Configure the payment method not to use a billing address
  2. Add an interceptor plugin to the setBillingAddress function of the \Magento\Quote\Model\Quote class which always inserts the default billing address The interceptor is needed, because the standard shipping address is still used instead of the standard billing address.

1.

This can be accomplished by overriding the isBillingAddressRequired property of the checkout layout. For example when using the Magento_OfflinePayments module as a payment option: Copy the xml code of magento2ce/vendor/magento/module-offline-payments/view/frontend/layout/checkout_index_index.xml to /app/design/frontend/{YOUR_VENDOR}/{YOUR_THEME}/Magento_OfflinePayments/layout/checkout_index_index.xml and set the true booleans to false. This

2.

I used http://alanstorm.com/magento_2_object_manager_plugin_system as a guide for setting up the Interceptor:

<?php
namespace {YOUR_VENDOR}\{YOUR_MODULE}\Model\Quote;

use Magento\Customer\Api\AddressRepositoryInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Customer\Model\Address;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Exception\LocalizedException;
use Magento\Quote\Api\Data\AddressInterface;
use Magento\Quote\Model\Quote\Interceptor;

class Plugin
{

    /** @var  CustomerRepositoryInterface */
    private $_customerRepository;

    /** @var  AddressRepositoryInterface */
    private $_addressRepository;


    /**
     * Plugin constructor.
     * @param CustomerRepositoryInterface $customerRepository
     * @param AddressRepositoryInterface  $addressRepository
     */
    public function __construct(
        CustomerRepositoryInterface $customerRepository,
        AddressRepositoryInterface $addressRepository
    ) {
        $this->_customerRepository = $customerRepository;
        $this->_addressRepository = $addressRepository;
    }


    /**
     * Interceptor which always sets the default billing address of a customer as the quote/order billing address
     * @param Interceptor      $subject
     * @param AddressInterface $address
     * @return $this
     */
    public function beforeSetBillingAddress(Interceptor $subject, AddressInterface $address = null)
    {
        $customerId = $address->getCustomerId();

        /** @var CustomerInterface $customer */
        $customer = $this->_customerRepository->getById($customerId);

        /** @var Address $defaultAddress */
        $defaultAddressId = $customer->getDefaultBilling();

        /** @var \Magento\Customer\Api\AddressRepositoryInterface $addressRepository */
        try {
            //This is our Customer Address
            $defaultBillingAddress = $this->_addressRepository->getById($defaultAddressId);

            //Convert the Customer Address to a Quote Address
            //Using the ObjectManager is bad practice, use DI instead, but how?
            $objectManager = ObjectManager::getInstance();
            /** @var \Magento\Quote\Model\Quote\Address $quoteBillingAddress */
            $quoteBillingAddress = $objectManager->create('Magento\Quote\Model\Quote\Address');
            $quoteBillingAddress->importCustomerAddressData($defaultBillingAddress);

            $address = $quoteBillingAddress;
        } catch (LocalizedException $e) {
            //Address not found?
        }


        return [$address];
    }

}

I feel this solution is still sub optimal. I hope an interceptor won't be necessary, but maybe this is of use to anyone.

Related Topic