diff --git a/app/code/Magento/Quote/Observer/Backend/Quote/Address/CollectTotalsObserver.php b/app/code/Magento/Quote/Observer/Backend/Quote/Address/CollectTotalsObserver.php
new file mode 100755
index 0000000000000..3f413d6069bd6
--- /dev/null
+++ b/app/code/Magento/Quote/Observer/Backend/Quote/Address/CollectTotalsObserver.php
@@ -0,0 +1,81 @@
+state = $state;
+ }
+
+ /**
+ * Conditions to change customer group
+ *
+ * @param int|null $groupId
+ * @return bool
+ */
+ protected function assignCustomerGroupConditions($groupId)
+ {
+ if ($groupId !== null
+ && !(
+ $this->state->getAreaCode() == Area::AREA_ADMINHTML
+ && $groupId == $this->groupManagement->getNotLoggedInGroup()->getId()
+ )) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/app/code/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserver.php b/app/code/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserver.php
old mode 100644
new mode 100755
index a1228903e2323..2e9d8e4910181
--- a/app/code/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserver.php
+++ b/app/code/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserver.php
@@ -131,7 +131,7 @@ public function execute(\Magento\Framework\Event\Observer $observer)
);
}
- if ($groupId !== null) {
+ if ($this->assignCustomerGroupConditions($groupId)) {
$address->setPrevQuoteCustomerGroupId($quote->getCustomerGroupId());
$quote->setCustomerGroupId($groupId);
$this->customerSession->setCustomerGroupId($groupId);
@@ -139,4 +139,15 @@ public function execute(\Magento\Framework\Event\Observer $observer)
$quote->setCustomer($customer);
}
}
+
+ /**
+ * Conditions to change customer group
+ *
+ * @param int|null $groupId
+ * @return bool
+ */
+ protected function assignCustomerGroupConditions($groupId)
+ {
+ return $groupId !== null ? true : false;
+ }
}
diff --git a/app/code/Magento/Quote/Test/Unit/Observer/Backend/Quote/Address/CollectTotalsObserverTest.php b/app/code/Magento/Quote/Test/Unit/Observer/Backend/Quote/Address/CollectTotalsObserverTest.php
new file mode 100755
index 0000000000000..b7a2d9a2f586e
--- /dev/null
+++ b/app/code/Magento/Quote/Test/Unit/Observer/Backend/Quote/Address/CollectTotalsObserverTest.php
@@ -0,0 +1,488 @@
+objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+ $this->storeId = 1;
+ $this->customerMock = $this->getMockForAbstractClass(
+ \Magento\Customer\Api\Data\CustomerInterface::class,
+ [],
+ '',
+ false,
+ true,
+ true,
+ ['getStoreId', 'getCustomAttribute', 'getId', '__wakeup']
+ );
+ $this->customerAddressMock = $this->createMock(\Magento\Customer\Helper\Address::class);
+ $this->customerVatMock = $this->createMock(\Magento\Customer\Model\Vat::class);
+ $this->customerDataFactoryMock = $this->createPartialMock(
+ \Magento\Customer\Api\Data\CustomerInterfaceFactory::class,
+ ['mergeDataObjectWithArray', 'create']
+ );
+ $this->vatValidatorMock = $this->createMock(\Magento\Quote\Observer\Frontend\Quote\Address\VatValidator::class);
+ $this->observerMock = $this->createPartialMock(
+ \Magento\Framework\Event\Observer::class,
+ ['getShippingAssignment', 'getQuote']
+ );
+
+ $this->quoteAddressMock = $this->createPartialMock(
+ \Magento\Quote\Model\Quote\Address::class,
+ ['getCountryId', 'getVatId', 'getQuote', 'setPrevQuoteCustomerGroupId', '__wakeup']
+ );
+
+ $this->quoteMock = $this->createPartialMock(
+ \Magento\Quote\Model\Quote::class,
+ ['setCustomerGroupId', 'getCustomerGroupId', 'getCustomer', '__wakeup', 'setCustomer']
+ );
+
+ $this->groupManagementMock = $this->getMockForAbstractClass(
+ \Magento\Customer\Api\GroupManagementInterface::class,
+ [],
+ '',
+ false,
+ true,
+ true,
+ [
+ 'getDefaultGroup',
+ 'getNotLoggedInGroup'
+ ]
+ );
+
+ $this->groupInterfaceMock = $this->getMockForAbstractClass(
+ \Magento\Customer\Api\Data\GroupInterface::class,
+ [],
+ '',
+ false,
+ true,
+ true,
+ ['getId']
+ );
+
+ $this->stateMock = $this->createPartialMock(
+ State::class,
+ ['getAreaCode']
+ );
+
+ $shippingAssignmentMock = $this->createMock(\Magento\Quote\Api\Data\ShippingAssignmentInterface::class);
+ $shippingMock = $this->createMock(\Magento\Quote\Api\Data\ShippingInterface::class);
+ $shippingAssignmentMock->expects($this->once())->method('getShipping')->willReturn($shippingMock);
+ $shippingMock->expects($this->once())->method('getAddress')->willReturn($this->quoteAddressMock);
+
+ $this->observerMock->expects($this->once())
+ ->method('getShippingAssignment')
+ ->willReturn($shippingAssignmentMock);
+
+ $this->observerMock->expects($this->once())->method('getQuote')->willReturn($this->quoteMock);
+ $this->quoteMock->expects($this->any())
+ ->method('getCustomer')
+ ->will($this->returnValue($this->customerMock));
+
+ $this->addressRepository = $this->createMock(\Magento\Customer\Api\AddressRepositoryInterface::class);
+ $this->customerSession = $this->getMockBuilder(\Magento\Customer\Model\Session::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->customerMock->expects($this->any())->method('getStoreId')->will($this->returnValue($this->storeId));
+
+ $this->model = new \Magento\Quote\Observer\Backend\Quote\Address\CollectTotalsObserver(
+ $this->customerAddressMock,
+ $this->customerVatMock,
+ $this->vatValidatorMock,
+ $this->customerDataFactoryMock,
+ $this->groupManagementMock,
+ $this->addressRepository,
+ $this->customerSession,
+ $this->stateMock
+ );
+ }
+
+ public function testDispatchWithDisableVatValidator()
+ {
+ $this->vatValidatorMock->expects($this->once())
+ ->method('isEnabled')
+ ->with($this->quoteAddressMock, $this->storeId)
+ ->will($this->returnValue(false));
+ $this->model->execute($this->observerMock);
+ }
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+ */
+ public function testDispatchWithCustomerCountryNotInEUAndNotLoggedCustomerInGroup()
+ {
+ $this->groupManagementMock->expects($this->once())
+ ->method('getNotLoggedInGroup')
+ ->will($this->returnValue($this->groupInterfaceMock));
+ $this->groupInterfaceMock->expects($this->once())
+ ->method('getId')->will($this->returnValue(null));
+ $this->vatValidatorMock->expects($this->once())
+ ->method('isEnabled')
+ ->with($this->quoteAddressMock, $this->storeId)
+ ->will($this->returnValue(true));
+
+ $this->quoteAddressMock->expects($this->once())
+ ->method('getCountryId')
+ ->will($this->returnValue('customerCountryCode'));
+ $this->quoteAddressMock->expects($this->once())->method('getVatId')->will($this->returnValue('vatId'));
+
+ $this->customerVatMock->expects(
+ $this->once()
+ )->method(
+ 'isCountryInEU'
+ )->with(
+ 'customerCountryCode'
+ )->will(
+ $this->returnValue(false)
+ );
+
+ $this->customerMock->expects($this->once())->method('getId')->will($this->returnValue(null));
+
+ /** Assertions */
+ $this->quoteAddressMock->expects($this->never())->method('setPrevQuoteCustomerGroupId');
+ $this->customerDataFactoryMock->expects($this->never())->method('mergeDataObjectWithArray');
+ $this->quoteMock->expects($this->never())->method('setCustomerGroupId');
+
+ /** SUT execution */
+ $this->model->execute($this->observerMock);
+ }
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+ */
+ public function testDispatchWithNotLoggedCustomerInGroupAndInAdminArea()
+ {
+ $this->stateMock->expects($this->once())
+ ->method('getAreaCode')->will($this->returnValue(Area::AREA_ADMINHTML));
+ $this->groupManagementMock->expects($this->exactly(2))
+ ->method('getNotLoggedInGroup')
+ ->will($this->returnValue($this->groupInterfaceMock));
+ $this->groupInterfaceMock->expects($this->exactly(2))
+ ->method('getId')->will($this->returnValue(0));
+ $this->vatValidatorMock->expects($this->once())
+ ->method('isEnabled')
+ ->with($this->quoteAddressMock, $this->storeId)
+ ->will($this->returnValue(true));
+
+ $this->quoteAddressMock->expects($this->once())
+ ->method('getCountryId')
+ ->will($this->returnValue('customerCountryCode'));
+ $this->quoteAddressMock->expects($this->once())->method('getVatId')->will($this->returnValue('vatId'));
+
+ $this->customerVatMock->expects(
+ $this->once()
+ )->method(
+ 'isCountryInEU'
+ )->with(
+ 'customerCountryCode'
+ )->will(
+ $this->returnValue(false)
+ );
+
+ $this->customerMock->expects($this->once())->method('getId')->will($this->returnValue(null));
+
+ /** Assertions */
+ $this->quoteAddressMock->expects($this->never())->method('setPrevQuoteCustomerGroupId');
+ $this->customerDataFactoryMock->expects($this->never())->method('mergeDataObjectWithArray');
+ $this->quoteMock->expects($this->never())->method('setCustomerGroupId');
+
+ /** SUT execution */
+ $this->model->execute($this->observerMock);
+ }
+
+ public function testDispatchWithDefaultCustomerGroupId()
+ {
+ $this->stateMock->expects($this->once())
+ ->method('getAreaCode')->will($this->returnValue(Area::AREA_FRONTEND));
+ $this->vatValidatorMock->expects($this->once())
+ ->method('isEnabled')
+ ->with($this->quoteAddressMock, $this->storeId)
+ ->will($this->returnValue(true));
+
+ $this->quoteAddressMock->expects($this->once())
+ ->method('getCountryId')
+ ->will($this->returnValue('customerCountryCode'));
+ $this->quoteAddressMock->expects($this->once())->method('getVatId')->will($this->returnValue(null));
+
+ $this->quoteMock->expects($this->once())
+ ->method('getCustomerGroupId')
+ ->will($this->returnValue('customerGroupId'));
+ $this->customerMock->expects($this->once())->method('getId')->will($this->returnValue('1'));
+ $this->groupManagementMock->expects($this->once())
+ ->method('getDefaultGroup')
+ ->will($this->returnValue($this->groupInterfaceMock));
+ $this->groupInterfaceMock->expects($this->once())
+ ->method('getId')->will($this->returnValue('defaultCustomerGroupId'));
+ /** Assertions */
+ $this->quoteAddressMock->expects($this->once())
+ ->method('setPrevQuoteCustomerGroupId')
+ ->with('customerGroupId');
+ $this->quoteMock->expects($this->once())->method('setCustomerGroupId')->with('defaultCustomerGroupId');
+ $this->customerDataFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($this->customerMock);
+
+ $this->quoteMock->expects($this->once())->method('setCustomer')->with($this->customerMock);
+
+ /** SUT execution */
+ $this->model->execute($this->observerMock);
+ }
+
+ public function testDispatchWithCustomerCountryInEU()
+ {
+ $this->stateMock->expects($this->once())
+ ->method('getAreaCode')->will($this->returnValue(Area::AREA_FRONTEND));
+ $this->vatValidatorMock->expects($this->once())
+ ->method('isEnabled')
+ ->with($this->quoteAddressMock, $this->storeId)
+ ->will($this->returnValue(true));
+
+ $this->quoteAddressMock->expects($this->once())
+ ->method('getCountryId')
+ ->will($this->returnValue('customerCountryCode'));
+ $this->quoteAddressMock->expects($this->once())
+ ->method('getVatId')
+ ->will($this->returnValue('vatID'));
+
+ $this->customerVatMock->expects($this->once())
+ ->method('isCountryInEU')
+ ->with('customerCountryCode')
+ ->willReturn(true);
+
+ $this->quoteMock->expects($this->once())
+ ->method('getCustomerGroupId')
+ ->will($this->returnValue('customerGroupId'));
+
+ $validationResult = ['some' => 'result'];
+ $this->vatValidatorMock->expects($this->once())
+ ->method('validate')
+ ->with($this->quoteAddressMock, $this->storeId)
+ ->will($this->returnValue($validationResult));
+
+ $this->customerVatMock->expects($this->once())
+ ->method('getCustomerGroupIdBasedOnVatNumber')
+ ->with('customerCountryCode', $validationResult, $this->storeId)
+ ->will($this->returnValue('customerGroupId'));
+
+ /** Assertions */
+ $this->quoteAddressMock->expects($this->once())
+ ->method('setPrevQuoteCustomerGroupId')
+ ->with('customerGroupId');
+
+ $this->quoteMock->expects($this->once())->method('setCustomerGroupId')->with('customerGroupId');
+ $this->quoteMock->expects($this->once())->method('setCustomer')->with($this->customerMock);
+ $this->customerDataFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($this->customerMock);
+ $this->model->execute($this->observerMock);
+ }
+
+ public function testDispatchWithAddressCustomerVatIdAndCountryId()
+ {
+ $customerCountryCode = "BE";
+ $customerVat = "123123123";
+ $defaultShipping = 1;
+
+ $customerAddress = $this->createMock(\Magento\Quote\Model\Quote\Address::class);
+ $customerAddress->expects($this->any())
+ ->method("getVatId")
+ ->willReturn($customerVat);
+
+ $customerAddress->expects($this->any())
+ ->method("getCountryId")
+ ->willReturn($customerCountryCode);
+
+ $this->addressRepository->expects($this->once())
+ ->method("getById")
+ ->with($defaultShipping)
+ ->willReturn($customerAddress);
+
+ $this->customerMock->expects($this->atLeastOnce())
+ ->method("getDefaultShipping")
+ ->willReturn($defaultShipping);
+
+ $this->vatValidatorMock->expects($this->once())
+ ->method('isEnabled')
+ ->with($this->quoteAddressMock, $this->storeId)
+ ->will($this->returnValue(true));
+
+ $this->customerVatMock->expects($this->once())
+ ->method('isCountryInEU')
+ ->with($customerCountryCode)
+ ->willReturn(true);
+
+ $this->model->execute($this->observerMock);
+ }
+
+ public function testDispatchWithEmptyShippingAddress()
+ {
+ $this->stateMock->expects($this->once())
+ ->method('getAreaCode')->will($this->returnValue(Area::AREA_FRONTEND));
+ $customerCountryCode = "DE";
+ $customerVat = "123123123";
+ $defaultShipping = 1;
+
+ $customerAddress = $this->createMock(\Magento\Customer\Api\Data\AddressInterface::class);
+ $customerAddress->expects($this->once())
+ ->method("getCountryId")
+ ->willReturn($customerCountryCode);
+
+ $customerAddress->expects($this->once())
+ ->method("getVatId")
+ ->willReturn($customerVat);
+ $this->addressRepository->expects($this->once())
+ ->method("getById")
+ ->with($defaultShipping)
+ ->willReturn($customerAddress);
+
+ $this->customerMock->expects($this->atLeastOnce())
+ ->method("getDefaultShipping")
+ ->willReturn($defaultShipping);
+
+ $this->vatValidatorMock->expects($this->once())
+ ->method('isEnabled')
+ ->with($this->quoteAddressMock, $this->storeId)
+ ->will($this->returnValue(true));
+
+ $this->quoteAddressMock->expects($this->once())
+ ->method('getCountryId')
+ ->will($this->returnValue(null));
+ $this->quoteAddressMock->expects($this->once())
+ ->method('getVatId')
+ ->will($this->returnValue(null));
+
+ $this->customerVatMock->expects($this->once())
+ ->method('isCountryInEU')
+ ->with($customerCountryCode)
+ ->willReturn(true);
+
+ $this->quoteMock->expects($this->once())
+ ->method('getCustomerGroupId')
+ ->will($this->returnValue('customerGroupId'));
+ $validationResult = ['some' => 'result'];
+ $this->customerVatMock->expects($this->once())
+ ->method('getCustomerGroupIdBasedOnVatNumber')
+ ->with($customerCountryCode, $validationResult, $this->storeId)
+ ->will($this->returnValue('customerGroupId'));
+ $this->customerSession->expects($this->once())
+ ->method("setCustomerGroupId")
+ ->with('customerGroupId');
+
+ $this->vatValidatorMock->expects($this->once())
+ ->method('validate')
+ ->with($this->quoteAddressMock, $this->storeId)
+ ->will($this->returnValue($validationResult));
+
+ /** Assertions */
+ $this->quoteAddressMock->expects($this->once())
+ ->method('setPrevQuoteCustomerGroupId')
+ ->with('customerGroupId');
+
+ $this->quoteMock->expects($this->once())->method('setCustomerGroupId')->with('customerGroupId');
+ $this->quoteMock->expects($this->once())->method('setCustomer')->with($this->customerMock);
+ $this->customerDataFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($this->customerMock);
+ $this->model->execute($this->observerMock);
+ }
+}
diff --git a/app/code/Magento/Quote/etc/adminhtml/events.xml b/app/code/Magento/Quote/etc/adminhtml/events.xml
old mode 100644
new mode 100755
index 54943fe4cd34f..f0dd18c34af32
--- a/app/code/Magento/Quote/etc/adminhtml/events.xml
+++ b/app/code/Magento/Quote/etc/adminhtml/events.xml
@@ -9,4 +9,7 @@
+
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminChangeCustomerGroupWithAutomaticAssignmentToCustomerGroupInNewOrderTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminChangeCustomerGroupWithAutomaticAssignmentToCustomerGroupInNewOrderTest.xml
new file mode 100644
index 0000000000000..326658f4415b8
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminChangeCustomerGroupWithAutomaticAssignmentToCustomerGroupInNewOrderTest.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+