From d0ab2a328666825dc1f87f333638255268a24026 Mon Sep 17 00:00:00 2001 From: dzung kiu Date: Wed, 25 Mar 2020 18:00:27 +0700 Subject: [PATCH 1/9] #23440 fix Refund for bundle product without receiving product back error --- app/code/Magento/Sales/Model/Order/CreditmemoFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php index 73afd0a06f710..cc2a645413fdf 100644 --- a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php +++ b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php @@ -147,7 +147,7 @@ protected function canRefundItem($item, $qtys = [], $invoiceQtysRefundLimits = [ if ($item->isDummy()) { if ($item->getHasChildren()) { foreach ($item->getChildrenItems() as $child) { - if (empty($qtys)) { + if (empty($qtys) || (count(array_unique($qtys)) === 1 && end($qtys) == 0)) { if ($this->canRefundNoDummyItem($child, $invoiceQtysRefundLimits)) { return true; } From d03d1338b7b05da2faccc5b4dd2ec775bc0c8161 Mon Sep 17 00:00:00 2001 From: dzung kiu Date: Tue, 7 Apr 2020 15:24:05 +0700 Subject: [PATCH 2/9] #23440 fix static test error --- app/code/Magento/Sales/Model/Order/CreditmemoFactory.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php index cc2a645413fdf..103ed3e2fa3c5 100644 --- a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php +++ b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php @@ -166,6 +166,7 @@ protected function canRefundItem($item, $qtys = [], $invoiceQtysRefundLimits = [ return isset($qtys[$parent->getId()]) && $qtys[$parent->getId()] > 0; } } + return false; } else { return $this->canRefundNoDummyItem($item, $invoiceQtysRefundLimits); } From 4807ebb53158ebdd9207ad994ab38d4084c9d1d2 Mon Sep 17 00:00:00 2001 From: dzung kiu Date: Wed, 15 Apr 2020 15:47:56 +0700 Subject: [PATCH 3/9] #23440 add unit test for changed function --- .../Model/Order/CreditmemoFactoryTest.php | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php new file mode 100644 index 0000000000000..1778a7e3057c6 --- /dev/null +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php @@ -0,0 +1,74 @@ +subject = $objectManager->getObject(\Magento\Sales\Model\Order\CreditmemoFactory::class, []); + } + + /** + * Check if order item can be refunded + */ + public function testCanRefundItem() + { + $orderItem = $this->createPartialMock( + \Magento\Sales\Model\Order\Item::class, + ['getChildrenItems', 'isDummy', 'getHasChildren', 'getId', 'getParentItemId'] + ); + $orderItem->expects($this->any()) + ->method('getId') + ->willReturn(1); + $orderItem->expects($this->any())->method('getParentItemId')->willReturn(false); + $orderItem->expects($this->any())->method('isDummy')->willReturn(true); + $orderItem->expects($this->any())->method('getHasChildren')->willReturn(true); + $orderChildItemOne = $this->createPartialMock( + \Magento\Sales\Model\Order\Item::class, + ['getQtyToRefund', 'getId'] + ); + $orderChildItemOne->expects($this->any())->method('getQtyToRefund')->willReturn(1); + $orderChildItemOne->expects($this->any())->method('getId')->willReturn(2); + $orderChildItemTwo = $this->createPartialMock( + \Magento\Sales\Model\Order\Item::class, + ['getQtyToRefund', 'getId'] + ); + $orderChildItemTwo->expects($this->any())->method('getQtyToRefund')->willReturn(1); + $orderChildItemTwo->expects($this->any())->method('getId')->willReturn(3); + $orderItem->expects($this->any())->method('getChildrenItems')->willReturn([$orderChildItemOne, $orderChildItemTwo]); + $testMethod = new \ReflectionMethod( + \Magento\Sales\Model\Order\CreditmemoFactory::class, + 'canRefundItem' + ); + $orderItemQtys = [ + 2 => 0, + 3 => 0 + ]; + $invoiceQtysRefundLimits = []; + $testMethod->setAccessible(true); + $result = $testMethod->invoke($this->subject, $orderItem, $orderItemQtys, $invoiceQtysRefundLimits); + $expectedResult = true; + $this->assertEquals($expectedResult, $result); + } +} From b88d88e40ffffd141bed4dd32483148af1ad29fe Mon Sep 17 00:00:00 2001 From: dzung kiu Date: Wed, 15 Apr 2020 19:58:09 +0700 Subject: [PATCH 4/9] #23440 add unit test - fix test code style warning --- .../Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php index 1778a7e3057c6..13245e3ce2700 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php @@ -56,7 +56,9 @@ public function testCanRefundItem() ); $orderChildItemTwo->expects($this->any())->method('getQtyToRefund')->willReturn(1); $orderChildItemTwo->expects($this->any())->method('getId')->willReturn(3); - $orderItem->expects($this->any())->method('getChildrenItems')->willReturn([$orderChildItemOne, $orderChildItemTwo]); + $orderItem->expects($this->any()) + ->method('getChildrenItems') + ->willReturn([$orderChildItemOne, $orderChildItemTwo]); $testMethod = new \ReflectionMethod( \Magento\Sales\Model\Order\CreditmemoFactory::class, 'canRefundItem' From 10d5f735c83c4588c449c85126882e4fb7bfd337 Mon Sep 17 00:00:00 2001 From: dzung kiu Date: Fri, 17 Apr 2020 12:45:35 +0700 Subject: [PATCH 5/9] #23440 add MFTF test --- ...editMemoRefundBundleWithQtyActionGroup.xml | 45 +++++ .../Section/AdminCreditMemoItemsSection.xml | 1 + ...nCreateCreditmemoWithBundleProductTest.xml | 155 ++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOpenAndFillCreditMemoRefundBundleWithQtyActionGroup.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOpenAndFillCreditMemoRefundBundleWithQtyActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOpenAndFillCreditMemoRefundBundleWithQtyActionGroup.xml new file mode 100644 index 0000000000000..65a64bdf9eb90 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOpenAndFillCreditMemoRefundBundleWithQtyActionGroup.xml @@ -0,0 +1,45 @@ + + + + + + + Clicks on the 'Credit Memos' section on the Admin Orders edit page. Fills in the provided Refund details (child item qty, Shipping Refund, Adjustment Refund, Adjustment Fee and Row number). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoItemsSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoItemsSection.xml index 74b773b0830d9..fa98843b0199a 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoItemsSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoItemsSection.xml @@ -24,5 +24,6 @@ + \ No newline at end of file diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml new file mode 100644 index 0000000000000..89c7a3176390a --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml @@ -0,0 +1,155 @@ + + + + + + + + <stories value="Github issue: #23440 fix Refund for bundle product without receiving product back"/> + <description value="Create Creditmemo for bundle product with without receiving product back(all child item qty = 0)"/> + <features value="Sales"/> + <severity value="AVERAGE"/> + <group value="Sales"/> + </annotations> + + <before> + <!--Set default flat rate shipping method settings--> + <createData entity="FlatRateShippingMethodDefault" stepKey="setDefaultFlatRateShippingMethod"/> + + <!--Create simple customer--> + <createData entity="Simple_US_Customer_CA" stepKey="simpleCustomer"/> + + <!--Create simple product 1--> + <createData entity="ApiProductWithDescription" stepKey="simple1" before="simple2"/> + + <!--Create simple product 2--> + <createData entity="ApiProductWithDescription" stepKey="simple2" before="product"/> + + <!--Create bundle product with checkbox bundle option--> + <createData entity="ApiBundleProduct" stepKey="product"/> + <createData entity="CheckboxOption" stepKey="checkboxBundleOption"> + <requiredEntity createDataKey="product"/> + </createData> + + <!--Link simple product 1 to bundle option with default quantity 2--> + <createData entity="ApiBundleLink" stepKey="createBundleLink1"> + <requiredEntity createDataKey="product"/> + <requiredEntity createDataKey="checkboxBundleOption"/> + <requiredEntity createDataKey="simple1"/> + <field key="qty">2</field> + <field key="is_default">1</field> + </createData> + + <!--Link simple product 2 to bundle option with default quantity 2--> + <createData entity="ApiBundleLink" stepKey="createBundleLink2"> + <requiredEntity createDataKey="product"/> + <requiredEntity createDataKey="checkboxBundleOption"/> + <requiredEntity createDataKey="simple2"/> + <field key="qty">2</field> + <field key="is_default">1</field> + </createData> + + <!--Add drop-down bundle option--> + <createData entity="DropDownBundleOption" stepKey="dropDownBundleOption"> + <requiredEntity createDataKey="product"/> + </createData> + + <!--Link simple product 1 to drop-down bundle option with default quantity 2--> + <createData entity="ApiBundleLink" stepKey="createBundleLink3"> + <requiredEntity createDataKey="product"/> + <requiredEntity createDataKey="dropDownBundleOption"/> + <requiredEntity createDataKey="simple1"/> + <field key="qty">2</field> + <field key="is_default">1</field> + </createData> + + <!--Link simple product 2 to drop-down bundle option with default quantity 2--> + <createData entity="ApiBundleLink" stepKey="createBundleLink4"> + <requiredEntity createDataKey="product"/> + <requiredEntity createDataKey="dropDownBundleOption"/> + <requiredEntity createDataKey="simple2"/> + <field key="qty">2</field> + </createData> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + + <!--Create new customer order--> + <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="navigateToNewOrderWithExistingCustomer"> + <argument name="customer" value="$$simpleCustomer$$"/> + </actionGroup> + + <!--Add bundle product to order and check product price in grid--> + <actionGroup ref="addBundleProductToOrderAndCheckPriceInGrid" stepKey="addBundleProductToOrder"> + <argument name="product" value="$$product$$"/> + <argument name="quantity" value="1"/> + <argument name="price" value="$738.00"/> + </actionGroup> + + <!--Select FlatRate shipping method--> + <actionGroup ref="orderSelectFlatRateShipping" stepKey="orderSelectFlatRateShippingMethod"/> + + <!--Submit order--> + <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="submitOrder"/> + + <!--Verify order information--> + <actionGroup ref="verifyCreatedOrderInformation" stepKey="verifyCreatedOrderInformation"/> + + + <!-- Create Invoice --> + <actionGroup ref="StartCreateInvoiceFromOrderPage" stepKey="startInvoice"/> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> + <waitForElementVisible selector="{{AdminMessagesSection.success}}" stepKey="waitForMessageAppears"/> + <see selector="{{AdminMessagesSection.success}}" userInput="The invoice has been created." stepKey="seeInvoiceCreateSuccess"/> + + <!-- Go to Sales > Orders > find out placed order and open --> + <grabTextFrom selector="|Order # (\d+)|" stepKey="grabOrderId" /> + <assertNotEmpty actual="$grabOrderId" stepKey="assertOrderIdIsNotEmpty" after="grabOrderId"/> + <actionGroup ref="OpenOrderById" stepKey="openOrder"> + <argument name="orderId" value="{$grabOrderId}"/> + </actionGroup> + + <!-- Click 'Credit Memo' button and fill data from dataset: partial refund --> + <actionGroup ref="AdminOpenAndFillCreditMemoRefundBundleWithQtyActionGroup" stepKey="fillCreditMemoRefund"> + <argument name="itemQtyToRefund" value="0"/> + <argument name="rowNumberItemOne" value="3"/> + <argument name="rowNumberItemTwo" value="5"/> + <argument name="rowNumberItemThree" value="6"/> + <argument name="adjustmentRefund" value="10"/> + </actionGroup> + + <!-- On order's page click 'Refund offline' button --> + <click selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="clickRefundOffline"/> + <waitForPageLoad stepKey="waitForResultPage"/> + + <!-- Perform all assertions: assert refund success create message --> + <see selector="{{AdminIndexManagementSection.successMessage}}" userInput="You created the credit memo." stepKey="assertRefundSuccessCreateMessage"/> + + <!--Assert refund in Credit Memo Tab --> + <click selector="{{AdminOrderDetailsOrderViewSection.creditMemos}}" stepKey="clickCreditMemoTab"/> + <waitForPageLoad stepKey="waitForTabLoad"/> + <grabTextFrom selector="{{AdminCreditMemosGridSection.memoId}}" stepKey="grabMemoId"/> + <assertNotEmpty actual="$grabMemoId" stepKey="assertMemoIdIsNotEmpty" after="grabMemoId"/> + <click selector="{{AdminCreditMemosGridSection.memoId}}" stepKey="clickView"/> + <waitForPageLoad stepKey="waitForCreditMemo"/> + <scrollTo selector="{{AdminCreditMemoViewTotalSection.subtotal}}" stepKey="scrollToTotal"/> + <see selector="{{AdminCreditMemoViewTotalSection.subtotal}}" userInput="$0.00" stepKey="seeSubtotal"/> + <see selector="{{AdminCreditMemoViewTotalSection.adjustmentRefund}}" userInput="$10.00" stepKey="seeAdjustmentRefund"/> + <see selector="{{AdminCreditMemoViewTotalSection.adjustmentFee}}" userInput="$0.00" stepKey="seeAdjustmentFee"/> + <see selector="{{AdminCreditMemoViewTotalSection.grandTotal}}" userInput="$10.00" stepKey="assertRefundOnCreditMemoTab"/> + + <after> + <actionGroup ref="logout" stepKey="logout"/> + + <deleteData createDataKey="product" stepKey="delete"/> + <deleteData createDataKey="simpleCustomer" stepKey="deleteSimpleCustomer"/> + <deleteData createDataKey="simple1" stepKey="deleteSimple1" before="deleteSimple2"/> + <deleteData createDataKey="simple2" stepKey="deleteSimple2" before="delete"/> + </after> + </test> +</tests> From b13b0ec728c1a06410602e5f018fab5b2d19b847 Mon Sep 17 00:00:00 2001 From: dzung kiu <dzung.kiu@balanceinternet.com.au> Date: Fri, 17 Apr 2020 13:48:32 +0700 Subject: [PATCH 6/9] #23440 update identical condition --- app/code/Magento/Sales/Model/Order/CreditmemoFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php index 103ed3e2fa3c5..8a278ae6591b7 100644 --- a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php +++ b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php @@ -147,7 +147,7 @@ protected function canRefundItem($item, $qtys = [], $invoiceQtysRefundLimits = [ if ($item->isDummy()) { if ($item->getHasChildren()) { foreach ($item->getChildrenItems() as $child) { - if (empty($qtys) || (count(array_unique($qtys)) === 1 && end($qtys) == 0)) { + if (empty($qtys) || (count(array_unique($qtys)) === 1 && (int)end($qtys) === 0)) { if ($this->canRefundNoDummyItem($child, $invoiceQtysRefundLimits)) { return true; } From 9de9cf0df827d7f1741854ffa1f3f15ff82c711b Mon Sep 17 00:00:00 2001 From: dzung kiu <dzung.kiu@balanceinternet.com.au> Date: Fri, 17 Apr 2020 18:34:53 +0700 Subject: [PATCH 7/9] #23440 add MFTF test --- .../AdminCreateCreditmemoWithBundleProductTest.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml index 89c7a3176390a..1feda9f723edc 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml @@ -76,7 +76,7 @@ <requiredEntity createDataKey="simple2"/> <field key="qty">2</field> </createData> - <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> </before> <!--Create new customer order--> @@ -109,7 +109,9 @@ <!-- Go to Sales > Orders > find out placed order and open --> <grabTextFrom selector="|Order # (\d+)|" stepKey="grabOrderId" /> - <assertNotEmpty actual="$grabOrderId" stepKey="assertOrderIdIsNotEmpty" after="grabOrderId"/> + <assertNotEmpty stepKey="assertOrderIdIsNotEmpty" after="grabOrderId"> + <actualResult type="const">$grabOrderId</actualResult> + </assertNotEmpty> <actionGroup ref="OpenOrderById" stepKey="openOrder"> <argument name="orderId" value="{$grabOrderId}"/> </actionGroup> @@ -134,7 +136,9 @@ <click selector="{{AdminOrderDetailsOrderViewSection.creditMemos}}" stepKey="clickCreditMemoTab"/> <waitForPageLoad stepKey="waitForTabLoad"/> <grabTextFrom selector="{{AdminCreditMemosGridSection.memoId}}" stepKey="grabMemoId"/> - <assertNotEmpty actual="$grabMemoId" stepKey="assertMemoIdIsNotEmpty" after="grabMemoId"/> + <assertNotEmpty stepKey="assertMemoIdIsNotEmpty" after="grabMemoId"> + <actualResult type="const">$grabMemoId</actualResult> + </assertNotEmpty> <click selector="{{AdminCreditMemosGridSection.memoId}}" stepKey="clickView"/> <waitForPageLoad stepKey="waitForCreditMemo"/> <scrollTo selector="{{AdminCreditMemoViewTotalSection.subtotal}}" stepKey="scrollToTotal"/> @@ -144,7 +148,7 @@ <see selector="{{AdminCreditMemoViewTotalSection.grandTotal}}" userInput="$10.00" stepKey="assertRefundOnCreditMemoTab"/> <after> - <actionGroup ref="logout" stepKey="logout"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> <deleteData createDataKey="product" stepKey="delete"/> <deleteData createDataKey="simpleCustomer" stepKey="deleteSimpleCustomer"/> From a7ea256e1741716a5ab49345a7aa3d65d493a20d Mon Sep 17 00:00:00 2001 From: dzung kiu <dzung.kiu@balanceinternet.com.au> Date: Fri, 17 Apr 2020 19:39:08 +0700 Subject: [PATCH 8/9] #23440 add MFTF - update action ref --- .../AdminCreateCreditmemoWithBundleProductTest.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml index 1feda9f723edc..0967bb5106e5c 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml @@ -80,29 +80,29 @@ </before> <!--Create new customer order--> - <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="navigateToNewOrderWithExistingCustomer"> + <actionGroup ref="NavigateToNewOrderPageExistingCustomerActionGroup" stepKey="navigateToNewOrderWithExistingCustomer"> <argument name="customer" value="$$simpleCustomer$$"/> </actionGroup> <!--Add bundle product to order and check product price in grid--> - <actionGroup ref="addBundleProductToOrderAndCheckPriceInGrid" stepKey="addBundleProductToOrder"> + <actionGroup ref="AddBundleProductToOrderAndCheckPriceInGridActionGroup" stepKey="addBundleProductToOrder"> <argument name="product" value="$$product$$"/> <argument name="quantity" value="1"/> <argument name="price" value="$738.00"/> </actionGroup> <!--Select FlatRate shipping method--> - <actionGroup ref="orderSelectFlatRateShipping" stepKey="orderSelectFlatRateShippingMethod"/> + <actionGroup ref="OrderSelectFlatRateShippingActionGroup" stepKey="orderSelectFlatRateShippingMethod"/> <!--Submit order--> <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="submitOrder"/> <!--Verify order information--> - <actionGroup ref="verifyCreatedOrderInformation" stepKey="verifyCreatedOrderInformation"/> + <actionGroup ref="VerifyCreatedOrderInformationActionGroup" stepKey="verifyCreatedOrderInformation"/> <!-- Create Invoice --> - <actionGroup ref="StartCreateInvoiceFromOrderPage" stepKey="startInvoice"/> + <actionGroup ref="StartCreateInvoiceFromOrderPageActionGroup" stepKey="startInvoice"/> <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> <waitForElementVisible selector="{{AdminMessagesSection.success}}" stepKey="waitForMessageAppears"/> <see selector="{{AdminMessagesSection.success}}" userInput="The invoice has been created." stepKey="seeInvoiceCreateSuccess"/> @@ -112,7 +112,7 @@ <assertNotEmpty stepKey="assertOrderIdIsNotEmpty" after="grabOrderId"> <actualResult type="const">$grabOrderId</actualResult> </assertNotEmpty> - <actionGroup ref="OpenOrderById" stepKey="openOrder"> + <actionGroup ref="OpenOrderByIdActionGroup" stepKey="openOrder"> <argument name="orderId" value="{$grabOrderId}"/> </actionGroup> From 84ff07645320eadedee48b9f3ffdab683c59bc9e Mon Sep 17 00:00:00 2001 From: engcom-Echo <engcom-vendorworker-echo@adobe.com> Date: Tue, 28 Apr 2020 13:22:04 +0300 Subject: [PATCH 9/9] refactoring - unit, mftf tests --- ...nCreateCreditmemoWithBundleProductTest.xml | 93 +++---------- .../Model/Order/CreditmemoFactoryTest.php | 129 ++++++++++++------ 2 files changed, 107 insertions(+), 115 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml index 0967bb5106e5c..3a9b252a95a3d 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateCreditmemoWithBundleProductTest.xml @@ -19,25 +19,14 @@ </annotations> <before> - <!--Set default flat rate shipping method settings--> <createData entity="FlatRateShippingMethodDefault" stepKey="setDefaultFlatRateShippingMethod"/> - - <!--Create simple customer--> <createData entity="Simple_US_Customer_CA" stepKey="simpleCustomer"/> - - <!--Create simple product 1--> <createData entity="ApiProductWithDescription" stepKey="simple1" before="simple2"/> - - <!--Create simple product 2--> <createData entity="ApiProductWithDescription" stepKey="simple2" before="product"/> - - <!--Create bundle product with checkbox bundle option--> <createData entity="ApiBundleProduct" stepKey="product"/> <createData entity="CheckboxOption" stepKey="checkboxBundleOption"> <requiredEntity createDataKey="product"/> </createData> - - <!--Link simple product 1 to bundle option with default quantity 2--> <createData entity="ApiBundleLink" stepKey="createBundleLink1"> <requiredEntity createDataKey="product"/> <requiredEntity createDataKey="checkboxBundleOption"/> @@ -45,8 +34,6 @@ <field key="qty">2</field> <field key="is_default">1</field> </createData> - - <!--Link simple product 2 to bundle option with default quantity 2--> <createData entity="ApiBundleLink" stepKey="createBundleLink2"> <requiredEntity createDataKey="product"/> <requiredEntity createDataKey="checkboxBundleOption"/> @@ -54,13 +41,9 @@ <field key="qty">2</field> <field key="is_default">1</field> </createData> - - <!--Add drop-down bundle option--> <createData entity="DropDownBundleOption" stepKey="dropDownBundleOption"> <requiredEntity createDataKey="product"/> </createData> - - <!--Link simple product 1 to drop-down bundle option with default quantity 2--> <createData entity="ApiBundleLink" stepKey="createBundleLink3"> <requiredEntity createDataKey="product"/> <requiredEntity createDataKey="dropDownBundleOption"/> @@ -68,8 +51,6 @@ <field key="qty">2</field> <field key="is_default">1</field> </createData> - - <!--Link simple product 2 to drop-down bundle option with default quantity 2--> <createData entity="ApiBundleLink" stepKey="createBundleLink4"> <requiredEntity createDataKey="product"/> <requiredEntity createDataKey="dropDownBundleOption"/> @@ -78,45 +59,30 @@ </createData> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> </before> + <after> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + <deleteData createDataKey="product" stepKey="delete"/> + <deleteData createDataKey="simpleCustomer" stepKey="deleteSimpleCustomer"/> + <deleteData createDataKey="simple1" stepKey="deleteSimple1" before="deleteSimple2"/> + <deleteData createDataKey="simple2" stepKey="deleteSimple2" before="delete"/> + </after> - <!--Create new customer order--> <actionGroup ref="NavigateToNewOrderPageExistingCustomerActionGroup" stepKey="navigateToNewOrderWithExistingCustomer"> <argument name="customer" value="$$simpleCustomer$$"/> </actionGroup> - - <!--Add bundle product to order and check product price in grid--> <actionGroup ref="AddBundleProductToOrderAndCheckPriceInGridActionGroup" stepKey="addBundleProductToOrder"> <argument name="product" value="$$product$$"/> <argument name="quantity" value="1"/> <argument name="price" value="$738.00"/> </actionGroup> - - <!--Select FlatRate shipping method--> <actionGroup ref="OrderSelectFlatRateShippingActionGroup" stepKey="orderSelectFlatRateShippingMethod"/> - - <!--Submit order--> - <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="submitOrder"/> - - <!--Verify order information--> - <actionGroup ref="VerifyCreatedOrderInformationActionGroup" stepKey="verifyCreatedOrderInformation"/> - - - <!-- Create Invoice --> + <actionGroup ref="AdminSubmitOrderActionGroup" stepKey="submitOrder"/> <actionGroup ref="StartCreateInvoiceFromOrderPageActionGroup" stepKey="startInvoice"/> - <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> - <waitForElementVisible selector="{{AdminMessagesSection.success}}" stepKey="waitForMessageAppears"/> - <see selector="{{AdminMessagesSection.success}}" userInput="The invoice has been created." stepKey="seeInvoiceCreateSuccess"/> - - <!-- Go to Sales > Orders > find out placed order and open --> - <grabTextFrom selector="|Order # (\d+)|" stepKey="grabOrderId" /> - <assertNotEmpty stepKey="assertOrderIdIsNotEmpty" after="grabOrderId"> - <actualResult type="const">$grabOrderId</actualResult> - </assertNotEmpty> + <actionGroup ref="SubmitInvoiceActionGroup" stepKey="submitInvoice"/> + <grabFromCurrentUrl regex="~/order_id/(\d+)/~" stepKey="grabOrderId"/> <actionGroup ref="OpenOrderByIdActionGroup" stepKey="openOrder"> - <argument name="orderId" value="{$grabOrderId}"/> + <argument name="orderId" value="$grabOrderId"/> </actionGroup> - - <!-- Click 'Credit Memo' button and fill data from dataset: partial refund --> <actionGroup ref="AdminOpenAndFillCreditMemoRefundBundleWithQtyActionGroup" stepKey="fillCreditMemoRefund"> <argument name="itemQtyToRefund" value="0"/> <argument name="rowNumberItemOne" value="3"/> @@ -124,36 +90,15 @@ <argument name="rowNumberItemThree" value="6"/> <argument name="adjustmentRefund" value="10"/> </actionGroup> + <actionGroup ref="SubmitCreditMemoActionGroup" stepKey="submitCreditMemo" /> - <!-- On order's page click 'Refund offline' button --> - <click selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="clickRefundOffline"/> - <waitForPageLoad stepKey="waitForResultPage"/> - - <!-- Perform all assertions: assert refund success create message --> - <see selector="{{AdminIndexManagementSection.successMessage}}" userInput="You created the credit memo." stepKey="assertRefundSuccessCreateMessage"/> - - <!--Assert refund in Credit Memo Tab --> - <click selector="{{AdminOrderDetailsOrderViewSection.creditMemos}}" stepKey="clickCreditMemoTab"/> - <waitForPageLoad stepKey="waitForTabLoad"/> - <grabTextFrom selector="{{AdminCreditMemosGridSection.memoId}}" stepKey="grabMemoId"/> - <assertNotEmpty stepKey="assertMemoIdIsNotEmpty" after="grabMemoId"> - <actualResult type="const">$grabMemoId</actualResult> - </assertNotEmpty> - <click selector="{{AdminCreditMemosGridSection.memoId}}" stepKey="clickView"/> - <waitForPageLoad stepKey="waitForCreditMemo"/> + <actionGroup ref="AdminOpenCreditMemoFromOrderPageActionGroup" stepKey="openCreditMemo" /> <scrollTo selector="{{AdminCreditMemoViewTotalSection.subtotal}}" stepKey="scrollToTotal"/> - <see selector="{{AdminCreditMemoViewTotalSection.subtotal}}" userInput="$0.00" stepKey="seeSubtotal"/> - <see selector="{{AdminCreditMemoViewTotalSection.adjustmentRefund}}" userInput="$10.00" stepKey="seeAdjustmentRefund"/> - <see selector="{{AdminCreditMemoViewTotalSection.adjustmentFee}}" userInput="$0.00" stepKey="seeAdjustmentFee"/> - <see selector="{{AdminCreditMemoViewTotalSection.grandTotal}}" userInput="$10.00" stepKey="assertRefundOnCreditMemoTab"/> - - <after> - <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> - - <deleteData createDataKey="product" stepKey="delete"/> - <deleteData createDataKey="simpleCustomer" stepKey="deleteSimpleCustomer"/> - <deleteData createDataKey="simple1" stepKey="deleteSimple1" before="deleteSimple2"/> - <deleteData createDataKey="simple2" stepKey="deleteSimple2" before="delete"/> - </after> + <actionGroup ref="AssertAdminCreditMemoViewPageTotalsActionGroup" stepKey="assertCreditMemoViewPageTotals"> + <argument name="subtotal" value="$0.00"/> + <argument name="adjustmentRefund" value="$10.00"/> + <argument name="adjustmentFee" value="$0.00"/> + <argument name="grandTotal" value="$10.00"/> + </actionGroup> </test> </tests> diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php index 13245e3ce2700..4cf571d3b6108 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoFactoryTest.php @@ -3,74 +3,121 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Sales\Test\Unit\Model\Order; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Sales\Model\Order\CreditmemoFactory; +use Magento\Sales\Model\Order\Item; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use ReflectionMethod; + /** * Unit test for creditmemo factory class. - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class CreditmemoFactoryTest extends \PHPUnit\Framework\TestCase +class CreditmemoFactoryTest extends TestCase { /** - * Subject of testing. - * - * @var \Magento\Sales\Model\Order\CreditmemoFactory + * @var CreditmemoFactory */ protected $subject; /** - * @return void - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @var ReflectionMethod */ - protected function setUp() - { - $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->subject = $objectManager->getObject(\Magento\Sales\Model\Order\CreditmemoFactory::class, []); - } + protected $testMethod; /** - * Check if order item can be refunded + * @var Item|MockObject + */ + protected $orderItemMock; + + /** + * @var Item|MockObject + */ + protected $orderChildItemOneMock; + + /** + * @var Item|MockObject */ - public function testCanRefundItem() + protected $orderChildItemTwoMock; + + /** + * @inheritDoc + */ + protected function setUp(): void { - $orderItem = $this->createPartialMock( - \Magento\Sales\Model\Order\Item::class, + $this->orderItemMock = $this->createPartialMock( + Item::class, ['getChildrenItems', 'isDummy', 'getHasChildren', 'getId', 'getParentItemId'] ); - $orderItem->expects($this->any()) - ->method('getId') - ->willReturn(1); - $orderItem->expects($this->any())->method('getParentItemId')->willReturn(false); - $orderItem->expects($this->any())->method('isDummy')->willReturn(true); - $orderItem->expects($this->any())->method('getHasChildren')->willReturn(true); - $orderChildItemOne = $this->createPartialMock( - \Magento\Sales\Model\Order\Item::class, + $this->orderChildItemOneMock = $this->createPartialMock( + Item::class, ['getQtyToRefund', 'getId'] ); - $orderChildItemOne->expects($this->any())->method('getQtyToRefund')->willReturn(1); - $orderChildItemOne->expects($this->any())->method('getId')->willReturn(2); - $orderChildItemTwo = $this->createPartialMock( - \Magento\Sales\Model\Order\Item::class, + $this->orderChildItemTwoMock = $this->createPartialMock( + Item::class, ['getQtyToRefund', 'getId'] ); - $orderChildItemTwo->expects($this->any())->method('getQtyToRefund')->willReturn(1); - $orderChildItemTwo->expects($this->any())->method('getId')->willReturn(3); - $orderItem->expects($this->any()) - ->method('getChildrenItems') - ->willReturn([$orderChildItemOne, $orderChildItemTwo]); - $testMethod = new \ReflectionMethod( - \Magento\Sales\Model\Order\CreditmemoFactory::class, - 'canRefundItem' - ); + $this->testMethod = new ReflectionMethod(CreditmemoFactory::class, 'canRefundItem'); + + $objectManagerHelper = new ObjectManagerHelper($this); + $this->subject = $objectManagerHelper->getObject(CreditmemoFactory::class, []); + } + + /** + * Check if order item can be refunded + * @return void + */ + public function testCanRefundItem(): void + { $orderItemQtys = [ 2 => 0, 3 => 0 ]; $invoiceQtysRefundLimits = []; - $testMethod->setAccessible(true); - $result = $testMethod->invoke($this->subject, $orderItem, $orderItemQtys, $invoiceQtysRefundLimits); - $expectedResult = true; - $this->assertEquals($expectedResult, $result); + + $this->orderItemMock->expects($this->any()) + ->method('getId') + ->willReturn(1); + $this->orderItemMock->expects($this->any()) + ->method('getParentItemId') + ->willReturn(false); + $this->orderItemMock->expects($this->any()) + ->method('isDummy') + ->willReturn(true); + $this->orderItemMock->expects($this->any()) + ->method('getHasChildren') + ->willReturn(true); + + $this->orderChildItemOneMock->expects($this->any()) + ->method('getQtyToRefund') + ->willReturn(1); + $this->orderChildItemOneMock->expects($this->any()) + ->method('getId') + ->willReturn(2); + + $this->orderChildItemTwoMock->expects($this->any()) + ->method('getQtyToRefund') + ->willReturn(1); + $this->orderChildItemTwoMock->expects($this->any()) + ->method('getId') + ->willReturn(3); + $this->orderItemMock->expects($this->any()) + ->method('getChildrenItems') + ->willReturn([$this->orderChildItemOneMock, $this->orderChildItemTwoMock]); + + $this->testMethod->setAccessible(true); + + $this->assertTrue( + $this->testMethod->invoke( + $this->subject, + $this->orderItemMock, + $orderItemQtys, + $invoiceQtysRefundLimits + ) + ); } }