diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/OnePageCheckoutAsCustomerUsingNonExistentCustomerGroupTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/OnePageCheckoutAsCustomerUsingNonExistentCustomerGroupTest.xml new file mode 100644 index 0000000000000..92dad56e81135 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/OnePageCheckoutAsCustomerUsingNonExistentCustomerGroupTest.xml @@ -0,0 +1,116 @@ + + + + + + + + + + <description value="Checkout as a customer with non-existent customer group assigned to the quote"/> + <severity value="AVERAGE"/> + <testCaseId value="MC-36385"/> + <group value="checkout"/> + </annotations> + <before> + <!-- Create Simple Product --> + <createData entity="SimpleProduct2" stepKey="createSimpleProduct"> + <field key="price">560</field> + </createData> + + <!-- Create customer group --> + <createData entity="CustomCustomerGroup" stepKey="createCustomerGroup"/> + + <!-- Create customer and assign it to the customer group created on the previous step --> + <createData entity="Simple_US_Customer_Multiple_Addresses" stepKey="createCustomer"> + <field key="group_id">$$createCustomerGroup.id$$</field> + </createData> + </before> + <after> + <!-- Admin log out --> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + + <!-- Customer log out --> + <actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="customerLogout"/> + + <!-- Delete created product --> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + + <!-- Delete customer --> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + </after> + + <!-- Login as customer --> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="customerLogin"> + <argument name="Customer" value="$$createCustomer$$"/> + </actionGroup> + + <!-- Add Simple Product to cart --> + <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.custom_attributes[url_key]$$)}}" stepKey="navigateToSimpleProductPage"/> + <waitForPageLoad stepKey="waitForSimpleProductPageLoad"/> + <actionGroup ref="AddToCartFromStorefrontProductPageActionGroup" stepKey="addToCartFromStorefrontProductPage"> + <argument name="productName" value="$$createSimpleProduct.name$$"/> + </actionGroup> + + <!-- Delete customer group --> + <deleteData createDataKey="createCustomerGroup" stepKey="deleteCustomerGroup"/> + + <!-- Go to shopping cart --> + <actionGroup ref="ClickViewAndEditCartFromMiniCartActionGroup" stepKey="goToShoppingCartFromMinicart"/> + <actionGroup ref="FillShippingZipForm" stepKey="fillShippingZipForm"> + <argument name="address" value="US_Address_CA"/> + </actionGroup> + <click selector="{{CheckoutCartSummarySection.proceedToCheckout}}" stepKey="clickProceedToCheckout"/> + <waitForPageLoad stepKey="waitForProceedToCheckout"/> + + <!-- Check that error does not appear and shipping methods are available to select --> + <dontSee selector="{{CheckoutCartMessageSection.errorMessage}}" userInput="No such entity with id = $$createCustomerGroup.id$$" stepKey="assertErrorMessage"/> + <dontSee selector="{{CheckoutShippingMethodsSection.noQuotesMsg}}" userInput="Sorry, no quotes are available for this order at this time" stepKey="assertNoQuotesMessage"/> + + <!-- Fill customer address data --> + <waitForElementVisible selector="{{CheckoutShippingSection.shipHereButton(UK_Not_Default_Address.street[0])}}" stepKey="waitForShipHereVisible"/> + <!-- Change address --> + <click selector="{{CheckoutShippingSection.shipHereButton(UK_Not_Default_Address.street[0])}}" stepKey="clickShipHere"/> + + <!-- Click next button to open payment section --> + <click selector="{{CheckoutShippingGuestInfoSection.next}}" stepKey="clickNext"/> + <waitForPageLoad stepKey="waitForShipmentPageLoad"/> + + <!-- Select payment solution --> + <checkOption selector="{{CheckoutPaymentSection.billingAddressNotSameCheckbox}}" stepKey="selectPaymentSolution" /> + + <!-- Check order summary in checkout --> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" stepKey="waitForPaymentSectionLoaded"/> + <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrderButton"/> + <seeElement selector="{{CheckoutSuccessMainSection.success}}" stepKey="orderIsSuccessfullyPlaced"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber22}}" stepKey="grabOrderNumber"/> + + <!-- Login as admin --> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + + <!-- Open created order in backend --> + <amOnPage url="{{AdminOrdersPage.url}}" stepKey="goToOrders"/> + <waitForPageLoad stepKey="waitForOrdersPageLoad"/> + <actionGroup ref="OpenOrderByIdActionGroup" stepKey="filterOrderGridById"> + <argument name="orderId" value="$grabOrderNumber"/> + </actionGroup> + + <!-- Assert order total --> + <scrollTo selector="{{AdminOrderTotalSection.grandTotal}}" stepKey="scrollToOrderTotalSection"/> + <see selector="{{AdminOrderTotalSection.grandTotal}}" userInput="$565.00" stepKey="checkOrderTotalInBackend"/> + + <!-- Assert order addresses --> + <see selector="{{AdminShipmentAddressInformationSection.billingAddress}}" userInput="{{UK_Not_Default_Address.street[0]}}" stepKey="seeBillingAddressStreet"/> + <see selector="{{AdminShipmentAddressInformationSection.billingAddress}}" userInput="{{UK_Not_Default_Address.city}}" stepKey="seeBillingAddressCity"/> + <see selector="{{AdminShipmentAddressInformationSection.billingAddress}}" userInput="{{UK_Not_Default_Address.postcode}}" stepKey="seeBillingAddressPostcode"/> + <see selector="{{AdminShipmentAddressInformationSection.shippingAddress}}" userInput="{{UK_Not_Default_Address.street[0]}}" stepKey="seeShippingAddressStreet"/> + <see selector="{{AdminShipmentAddressInformationSection.shippingAddress}}" userInput="{{UK_Not_Default_Address.city}}" stepKey="seeShippingAddressCity"/> + <see selector="{{AdminShipmentAddressInformationSection.shippingAddress}}" userInput="{{UK_Not_Default_Address.postcode}}" stepKey="seeShippingAddressPostcode"/> + </test> +</tests> diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php index 8b51c9e1bd774..d2e900138cd06 100644 --- a/app/code/Magento/Quote/Model/Quote.php +++ b/app/code/Magento/Quote/Model/Quote.php @@ -10,6 +10,7 @@ use Magento\Directory\Model\AllowedCountries; use Magento\Framework\Api\AttributeValueFactory; use Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Model\AbstractExtensibleModel; use Magento\Quote\Api\Data\PaymentInterface; use Magento\Quote\Model\Quote\Address; @@ -1104,7 +1105,22 @@ public function getCustomerTaxClassId() //if (!$this->getData('customer_group_id') && !$this->getData('customer_tax_class_id')) { $groupId = $this->getCustomerGroupId(); if ($groupId !== null) { - $taxClassId = $this->groupRepository->getById($this->getCustomerGroupId())->getTaxClassId(); + $taxClassId = null; + try { + $taxClassId = $this->groupRepository->getById($this->getCustomerGroupId())->getTaxClassId(); + } catch (NoSuchEntityException $e) { + /** + * A customer MAY create a quote and AFTER that customer group MAY be deleted. + * That breaks a quote because it still refers no a non-existent customer group. + * In such a case we should load a new customer group id from the current customer + * object and use it to retrieve tax class and update quote. + */ + $groupId = $this->getCustomer()->getGroupId(); + $this->setCustomerGroupId($groupId); + if ($groupId !== null) { + $taxClassId = $this->groupRepository->getById($groupId)->getTaxClassId(); + } + } $this->setCustomerTaxClassId($taxClassId); } diff --git a/app/code/Magento/Quote/Test/Unit/Model/QuoteTest.php b/app/code/Magento/Quote/Test/Unit/Model/QuoteTest.php index d9b797c454d4e..422a6cbcb7bbe 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/QuoteTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/QuoteTest.php @@ -30,7 +30,9 @@ use Magento\Framework\DataObject\Copy; use Magento\Framework\DataObject\Factory; use Magento\Framework\Event\Manager; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Model\Context; +use Magento\Framework\Phrase; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Quote\Api\Data\CartInterface; use Magento\Quote\Model\Quote; @@ -640,6 +642,48 @@ public function testGetCustomerTaxClassId() $this->assertEquals($taxClassId, $result); } + /** + * Test case when non-existent customer group is stored into the quote. + * In such a case we should get a NoSuchEntityException exception and try + * to get a valid customer group from the current customer object. + */ + public function testGetCustomerTaxClassIdForNonExistentCustomerGroup() + { + $customerId = 1; + $nonExistentGroupId = 100; + $groupId = 1; + $taxClassId = 1; + $groupMock = $this->getMockForAbstractClass(GroupInterface::class, [], '', false); + $this->groupRepositoryMock->expects($this->at(0)) + ->method('getById') + ->with($nonExistentGroupId) + ->willThrowException(new NoSuchEntityException(new Phrase('Entity Id does not exist'))); + $customerMock = $this->getMockForAbstractClass( + CustomerInterface::class, + [], + '', + false + ); + $customerMock->expects($this->once()) + ->method('getGroupId') + ->willReturn($groupId); + $this->customerRepositoryMock->expects($this->once()) + ->method('getById') + ->with($customerId) + ->willReturn($customerMock); + $this->groupRepositoryMock->expects($this->at(1)) + ->method('getById') + ->with($groupId) + ->willReturn($groupMock); + $groupMock->expects($this->once()) + ->method('getTaxClassId') + ->willReturn($taxClassId); + $this->quote->setData('customer_id', $customerId); + $this->quote->setData('customer_group_id', $nonExistentGroupId); + $result = $this->quote->getCustomerTaxClassId(); + $this->assertEquals($taxClassId, $result); + } + public function testGetAllAddresses() { $id = 1;