From 1743a36a424ded64043fbc6592956099ebb0eec2 Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Wed, 11 Oct 2017 21:47:27 +0300 Subject: [PATCH 1/4] Sync billing with shipping address on Admin Order Page - Set customer address ID only if the address was selected in dropdown - Removed "old" billing address from quote if customer address doesn't specified --- .../Magento/Sales/Model/AdminOrder/Create.php | 52 ++++++++-------- .../adminhtml/web/order/create/scripts.js | 46 +++++++++------ .../Controller/Adminhtml/Order/CreateTest.php | 59 ++++++++++++++++++- 3 files changed, 114 insertions(+), 43 deletions(-) diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index ccc5c134514f6..3d80713c51c08 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -10,6 +10,7 @@ use Magento\Customer\Api\AddressMetadataInterface; use Magento\Customer\Model\Metadata\Form as CustomerForm; +use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\Quote\Item; /** @@ -1449,32 +1450,35 @@ public function getBillingAddress() */ public function setBillingAddress($address) { - if (is_array($address)) { - $billingAddress = $this->_objectManager->create( - \Magento\Quote\Model\Quote\Address::class - )->setData( - $address - )->setAddressType( - \Magento\Quote\Model\Quote\Address::TYPE_BILLING - ); - $this->_setQuoteAddress($billingAddress, $address); - /** - * save_in_address_book is not a valid attribute and is filtered out by _setQuoteAddress, - * that is why it should be added after _setQuoteAddress call - */ - $saveInAddressBook = (int)(!empty($address['save_in_address_book'])); - $billingAddress->setData('save_in_address_book', $saveInAddressBook); - - if (!$this->getQuote()->isVirtual() && $this->getShippingAddress()->getSameAsBilling()) { - $shippingAddress = clone $billingAddress; - $shippingAddress->setSameAsBilling(true); - $shippingAddress->setSaveInAddressBook(false); - $address['save_in_address_book'] = 0; - $this->setShippingAddress($address); - } + if (!is_array($address)) { + return $this; + } + + $billingAddress = $this->_objectManager->create(Address::class) + ->setData($address) + ->setAddressType(Address::TYPE_BILLING); + + $this->_setQuoteAddress($billingAddress, $address); + + /** + * save_in_address_book is not a valid attribute and is filtered out by _setQuoteAddress, + * that is why it should be added after _setQuoteAddress call + */ + $saveInAddressBook = (int)(!empty($address['save_in_address_book'])); + $billingAddress->setData('save_in_address_book', $saveInAddressBook); + + $quote = $this->getQuote(); + if (!$quote->isVirtual() && $this->getShippingAddress()->getSameAsBilling()) { + $address['save_in_address_book'] = 0; + $this->setShippingAddress($address); + } - $this->getQuote()->setBillingAddress($billingAddress); + // not assigned billing address should be saved as new + // but if quote already has the billing address it won't be overridden + if (empty($billingAddress->getCustomerAddressId())) { + $quote->removeAddress($quote->getBillingAddress()->getId()); } + $quote->setBillingAddress($billingAddress); return $this; } diff --git a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js index 1c755b4e08a0d..302c615e68855 100644 --- a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js +++ b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js @@ -157,6 +157,7 @@ define([ } if(this.addresses[id]){ this.fillAddressFields(container, this.addresses[id]); + } else{ this.fillAddressFields(container, {}); @@ -190,43 +191,52 @@ define([ } }, - changeAddressField : function(event){ - var field = Event.element(event); - var re = /[^\[]*\[([^\]]*)_address\]\[([^\]]*)\](\[(\d)\])?/; - var matchRes = field.name.match(re); + /** + * Triggers on each form's element changes. + * + * @param {Object} event + */ + changeAddressField: function (event) { + var field = Event.element(event), + re = /[^\[]*\[([^\]]*)_address\]\[([^\]]*)\](\[(\d)\])?/, + matchRes = field.name.match(re), + type, + name, + data; if (!matchRes) { return; } - var type = matchRes[1]; - var name = matchRes[2]; - var data; + type = matchRes[1]; + name = matchRes[2]; - if(this.isBillingField(field.id)){ - data = this.serializeData(this.billingAddressContainer) - } - else{ - data = this.serializeData(this.shippingAddressContainer) + if (this.isBillingField(field.id)) { + data = this.serializeData(this.billingAddressContainer); + } else { + data = this.serializeData(this.shippingAddressContainer); } data = data.toObject(); - if( (type == 'billing' && this.shippingAsBilling) - || (type == 'shipping' && !this.shippingAsBilling) ) { + if (type === 'billing' && this.shippingAsBilling || type === 'shipping' && !this.shippingAsBilling) { data['reset_shipping'] = true; } - data['order['+type+'_address][customer_address_id]'] = $('order-'+type+'_address_customer_address_id').value; + data['order[' + type + '_address][customer_address_id]'] = null; + + if (name === 'customer_address_id') { + data['order[' + type + '_address][customer_address_id]'] = + $('order-' + type + '_address_customer_address_id').value; + } if (data['reset_shipping']) { this.resetShippingMethod(data); } else { this.saveData(data); - if (name == 'country_id' || name == 'customer_address_id') { + + if (name === 'country_id' || name === 'customer_address_id') { this.loadArea(['shipping_method', 'billing_method', 'totals', 'items'], true, data); } - // added for reloading of default sender and default recipient for giftmessages - //this.loadArea(['giftmessage'], true, data); } }, diff --git a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/CreateTest.php b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/CreateTest.php index 5f3dbdabc640a..e071dde26a263 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/CreateTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/CreateTest.php @@ -5,6 +5,10 @@ */ namespace Magento\Sales\Controller\Adminhtml\Order; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Backend\Model\Session\Quote; +use Magento\Quote\Api\CartRepositoryInterface; + /** * @magentoAppArea adminhtml * @magentoDbIsolation enabled @@ -158,7 +162,7 @@ public function testIndexAction() */ public function testGetAclResource($actionName, $reordered, $expectedResult) { - $this->_objectManager->get(\Magento\Backend\Model\Session\Quote::class)->setReordered($reordered); + $this->_objectManager->get(Quote::class)->setReordered($reordered); $orderController = $this->_objectManager->get( \Magento\Sales\Controller\Adminhtml\Order\Stub\OrderCreateStub::class ); @@ -229,4 +233,57 @@ public function testDeniedSaveAction() $this->dispatch('backend/sales/order_create/save'); $this->assertEquals('403', $this->getResponse()->getHttpResponseCode()); } + + /** + * Checks a case when shipping is the same as billing and billing address details was changed by request. + * Both billing and shipping addresses should be updated. + * + * @magentoAppArea adminhtml + * @magentoDataFixture Magento/Sales/_files/quote_with_customer.php + */ + public function testSyncBetweenQuoteAddresses() + { + /** @var CustomerRepositoryInterface $customerRepository */ + $customerRepository = $this->_objectManager->get(CustomerRepositoryInterface::class); + $customer = $customerRepository->get('customer@example.com'); + + /** @var CartRepositoryInterface $quoteRepository */ + $quoteRepository = $this->_objectManager->get(CartRepositoryInterface::class); + $quote = $quoteRepository->getActiveForCustomer($customer->getId()); + + $session = $this->_objectManager->get(Quote::class); + $session->setQuoteId($quote->getId()); + + $data = [ + 'firstname' => 'John', + 'lastname' => 'Doe', + 'street' => ['Soborna 23'], + 'city' => 'Kyiv', + 'country_id' => 'UA', + 'region' => 'Kyivska', + 'region_id' => 1 + ]; + $this->getRequest()->setPostValue( + [ + 'order' => ['billing_address' => $data], + 'reset_shipping' => 1, + 'customer_id' => $customer->getId(), + 'store_id' => 1, + 'json' => true + ] + ); + + $this->dispatch('backend/sales/order_create/loadBlock/block/shipping_address'); + self::assertEquals(200, $this->getResponse()->getHttpResponseCode()); + + $updatedQuote = $quoteRepository->get($quote->getId()); + + $billingAddress = $updatedQuote->getBillingAddress(); + self::assertEquals($data['region_id'], $billingAddress->getRegionId()); + self::assertEquals($data['country_id'], $billingAddress->getCountryId()); + + $shippingAddress = $updatedQuote->getShippingAddress(); + self::assertEquals($data['city'], $shippingAddress->getCity()); + self::assertEquals($data['street'], $shippingAddress->getStreet()); + } } From d1e6f822ce8d28ef1a941e3e33262782386344a6 Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Thu, 12 Oct 2017 21:04:50 +0300 Subject: [PATCH 2/4] Sync billing with shipping address on Admin Order Page - Fixed failed FAT --- app/code/Magento/Sales/Model/AdminOrder/Create.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index 3d80713c51c08..8619165cde606 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -1477,6 +1477,7 @@ public function setBillingAddress($address) // but if quote already has the billing address it won't be overridden if (empty($billingAddress->getCustomerAddressId())) { $quote->removeAddress($quote->getBillingAddress()->getId()); + $billingAddress->setCustomerAddressId(null); } $quote->setBillingAddress($billingAddress); @@ -1779,6 +1780,7 @@ public function _prepareCustomer() $address = $this->getShippingAddress()->setCustomerId($this->getQuote()->getCustomer()->getId()); $this->setShippingAddress($address); } + $this->getBillingAddress()->setCustomerId($customer->getId()); $this->getQuote()->updateCustomerData($this->getQuote()->getCustomer()); $customer = $this->getQuote()->getCustomer(); From 63b549b5bb052bb4a0b0b57cf81c7591f53b56e2 Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Fri, 13 Oct 2017 15:42:04 +0300 Subject: [PATCH 3/4] Sync billing with shipping address on Admin Order Page - Added validation for empty applied taxes to avoid exceptions during json decoding --- .../Magento/Quote/Model/Quote/Address.php | 3 +- .../Test/Unit/Model/Quote/AddressTest.php | 28 +++++++++---------- .../Magento/Sales/Model/AdminOrder/Create.php | 5 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php index 109ca91cb2ae8..87c5feaba8f2e 100644 --- a/app/code/Magento/Quote/Model/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Quote/Address.php @@ -1170,7 +1170,8 @@ public function validateMinimumAmount() */ public function getAppliedTaxes() { - return $this->serializer->unserialize($this->getData('applied_taxes')); + $taxes = $this->getData('applied_taxes'); + return $taxes ? $this->serializer->unserialize($taxes) : []; } /** diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/AddressTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/AddressTest.php index 1557fe420be02..d01ae7304bdc6 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/Quote/AddressTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/AddressTest.php @@ -9,7 +9,7 @@ namespace Magento\Quote\Test\Unit\Model\Quote; use Magento\Directory\Model\Currency; -use \Magento\Quote\Model\Quote\Address; +use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\Quote\Address\Rate; use Magento\Quote\Model\ResourceModel\Quote\Address\Rate\CollectionFactory as RateCollectionFactory; use Magento\Quote\Model\ResourceModel\Quote\Address\Rate\Collection as RatesCollection; @@ -28,6 +28,7 @@ use Magento\Store\Api\Data\StoreInterface; use Magento\Store\Api\Data\WebsiteInterface; use Magento\Quote\Model\Quote\Address\RateResult\AbstractResult; +use Magento\Framework\Serialize\Serializer\Json; /** * Test class for sales quote address model @@ -117,7 +118,7 @@ protected function setUp() $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->scopeConfig = $this->createMock(\Magento\Framework\App\Config::class); - $this->serializer = $this->createMock(\Magento\Framework\Serialize\Serializer\Json::class); + $this->serializer = new Json(); $this->requestFactory = $this->getMockBuilder(RateRequestFactory::class) ->disableOriginalConstructor() @@ -273,20 +274,17 @@ public function testValidateMiniumumAmountNegative() public function testSetAndGetAppliedTaxes() { $data = ['data']; - $result = json_encode($data); - - $this->serializer->expects($this->once()) - ->method('serialize') - ->with($data) - ->willReturn($result); - - $this->serializer->expects($this->once()) - ->method('unserialize') - ->with($result) - ->willReturn($data); + self::assertInstanceOf(Address::class, $this->address->setAppliedTaxes($data)); + self::assertEquals($data, $this->address->getAppliedTaxes()); + } - $this->assertInstanceOf(\Magento\Quote\Model\Quote\Address::class, $this->address->setAppliedTaxes($data)); - $this->assertEquals($data, $this->address->getAppliedTaxes()); + /** + * Checks a case, when applied taxes are not provided. + */ + public function testGetAppliedTaxesWithEmptyValue() + { + $this->address->setData('applied_taxes', null); + self::assertEquals([], $this->address->getAppliedTaxes()); } /** diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index 8619165cde606..c8afc6d8a292b 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -10,6 +10,7 @@ use Magento\Customer\Api\AddressMetadataInterface; use Magento\Customer\Model\Metadata\Form as CustomerForm; +use Magento\Framework\App\ObjectManager; use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\Quote\Item; @@ -324,7 +325,7 @@ public function __construct( $this->dataObjectHelper = $dataObjectHelper; $this->orderManagement = $orderManagement; $this->quoteFactory = $quoteFactory; - $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + $this->serializer = $serializer ?: ObjectManager::getInstance() ->get(\Magento\Framework\Serialize\Serializer\Json::class); parent::__construct($data); } @@ -1476,8 +1477,8 @@ public function setBillingAddress($address) // not assigned billing address should be saved as new // but if quote already has the billing address it won't be overridden if (empty($billingAddress->getCustomerAddressId())) { - $quote->removeAddress($quote->getBillingAddress()->getId()); $billingAddress->setCustomerAddressId(null); + $quote->getBillingAddress()->setCustomerAddressId(null); } $quote->setBillingAddress($billingAddress); From b1a0181d4148c6f994ad85c7e2f4f8b762fc6a3f Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Wed, 18 Oct 2017 19:42:43 +0300 Subject: [PATCH 4/4] Sync billing with shipping address on Admin Order Page - Fixed skipped 'Same as billing' checkbox --- .../Magento/Sales/view/adminhtml/web/order/create/scripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js index 302c615e68855..8e25584627d3b 100644 --- a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js +++ b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js @@ -223,6 +223,7 @@ define([ } data['order[' + type + '_address][customer_address_id]'] = null; + data['shipping_as_billing'] = jQuery('[name="shipping_same_as_billing"]').is(':checked') ? 1 : 0; if (name === 'customer_address_id') { data['order[' + type + '_address][customer_address_id]'] =