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:
- Configure the payment method not to use a billing address
- 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.