Skip to content

Commit 3c9435e

Browse files
committed
MAGETWO-82385: [CE 2.1.0 rc3] - Cancel an order [configurable product] #5313
1 parent d700436 commit 3c9435e

File tree

6 files changed

+192
-21
lines changed

6 files changed

+192
-21
lines changed

app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,4 +282,8 @@
282282
<data key="quantity">1</data>
283283
<requiredEntity type="product_extension_attribute">EavStock1</requiredEntity>
284284
</entity>
285+
<entity name="ApiSimpleWithQty100" extends="ApiSimpleOne">
286+
<data key="quantity">100</data>
287+
<requiredEntity type="product_extension_attribute">EavStock100</requiredEntity>
288+
</entity>
285289
</entities>

app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@
1414
<entity name="EavStock1" type="product_extension_attribute">
1515
<requiredEntity type="stock_item">Qty_1</requiredEntity>
1616
</entity>
17+
<entity name="EavStock100" type="product_extension_attribute">
18+
<requiredEntity type="stock_item">Qty_100</requiredEntity>
19+
</entity>
1720
</entities>

app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,8 @@
1616
<data key="qty">1</data>
1717
<data key="is_in_stock">true</data>
1818
</entity>
19+
<entity name="Qty_100" type="stock_item">
20+
<data key="qty">100</data>
21+
<data key="is_in_stock">true</data>
22+
</entity>
1923
</entities>
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
10+
<test name="AdminCheckingProductQtyAfterOrderCancelTest">
11+
<annotations>
12+
<features value="ConfigurableProduct"/>
13+
<stories value="Product quantity after order cancel"/>
14+
<title value="Products quantity return after order cancel"/>
15+
<description value="Checking product quantity after the order cancel"/>
16+
<severity value="CRITICAL"/>
17+
<testCaseId value="MC-13790"/>
18+
<group value="configurableProduct"/>
19+
</annotations>
20+
<before>
21+
<!--Create category-->
22+
<createData entity="ApiCategory" stepKey="createCategory"/>
23+
<!--Create configurable product and add it to the category-->
24+
<createData entity="ApiConfigurableProduct" stepKey="createConfigProduct">
25+
<requiredEntity createDataKey="createCategory"/>
26+
</createData>
27+
<!--Create attribute-->
28+
<createData entity="productAttributeWithDropdownTwoOptions" stepKey="createConfigProductAttribute"/>
29+
<createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOption1">
30+
<requiredEntity createDataKey="createConfigProductAttribute"/>
31+
</createData>
32+
<!--Add the attribute to default attribute set-->
33+
<createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet">
34+
<requiredEntity createDataKey="createConfigProductAttribute"/>
35+
</createData>
36+
<!--Get the option of the attribute-->
37+
<getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOption">
38+
<requiredEntity createDataKey="createConfigProductAttribute"/>
39+
</getData>
40+
<!--Create simple product and give it the attribute with option-->
41+
<createData entity="ApiSimpleWithQty100" stepKey="createConfigChildProduct">
42+
<requiredEntity createDataKey="createConfigProductAttribute"/>
43+
<requiredEntity createDataKey="getConfigAttributeOption"/>
44+
</createData>
45+
<!--Create configurable product-->
46+
<createData entity="ConfigurableProductTwoOptions" stepKey="createConfigProductOption">
47+
<requiredEntity createDataKey="createConfigProduct"/>
48+
<requiredEntity createDataKey="createConfigProductAttribute"/>
49+
<requiredEntity createDataKey="getConfigAttributeOption"/>
50+
</createData>
51+
<!--Add simple product to the configurable product-->
52+
<createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild">
53+
<requiredEntity createDataKey="createConfigProduct"/>
54+
<requiredEntity createDataKey="createConfigChildProduct"/>
55+
</createData>
56+
<!--Create customer-->
57+
<createData entity="Simple_US_Customer" stepKey="createCustomer"/>
58+
<!--Login-->
59+
<actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>
60+
</before>
61+
<after>
62+
<!--Clear grid filters-->
63+
<amOnPage url="{{AdminOrdersPage.url}}" stepKey="goToOrderGridPage"/>
64+
<actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearGridFilter"/>
65+
<!--Delete entities-->
66+
<deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/>
67+
<deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/>
68+
<deleteData createDataKey="createConfigChildProduct" stepKey="deleteConfigChildProduct"/>
69+
<deleteData createDataKey="createConfigProductAttribute" stepKey="deleteConfigProductAttribute"/>
70+
<deleteData createDataKey="createCategory" stepKey="deleteCategory"/>
71+
<!--Logout-->
72+
<actionGroup ref="logout" stepKey="logoutFromAdmin"/>
73+
<actionGroup ref="CustomerLogoutStorefrontActionGroup" stepKey="logoutFromStorefront"/>
74+
</after>
75+
76+
<!--Go to Storefront as Customer-->
77+
<actionGroup ref="CustomerLoginOnStorefront" stepKey="customerLogin">
78+
<argument name="customer" value="$$createCustomer$$" />
79+
</actionGroup>
80+
81+
<!--Go to the configurable product page on Storefront-->
82+
<amOnPage url="{{StorefrontProductPage.url($$createConfigProduct.sku$$)}}" stepKey="goToProductPage"/>
83+
<!--Select option-->
84+
<selectOption selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" userInput="$$getConfigAttributeOption.label$$" stepKey="selectOption"/>
85+
<!--Add product to the Shopping cart-->
86+
<actionGroup ref="StorefrontAddProductToCartQuantityActionGroup" stepKey="addProductToCart">
87+
<argument name="productName" value="$createConfigProduct.name$"/>
88+
<argument name="quantity" value="4"/>
89+
</actionGroup>
90+
91+
<!--Open Shopping cart-->
92+
<actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="openShoppingCartFromMinicart"/>
93+
<!--Place order-->
94+
<actionGroup ref="PlaceOrderWithLoggedUserActionGroup" stepKey="placeOrder">
95+
<argument name="shippingMethod" value="Flat Rate"/>
96+
<argument name="paymentMethod" value="Check / Money order"/>
97+
</actionGroup>
98+
<grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber22}}" stepKey="grabOrderNumber"/>
99+
100+
<!--Open order-->
101+
<actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById">
102+
<argument name="orderId" value="{$grabOrderNumber}"/>
103+
</actionGroup>
104+
<click selector="{{AdminDataGridTableSection.firstRow}}" stepKey="openOrderViewPage"/>
105+
<waitForPageLoad stepKey="waitForOrderViewPageOpen"/>
106+
107+
<!--Create Invoice-->
108+
<actionGroup ref="StartCreateInvoiceFromOrderPage" stepKey="startCreateInvoice"/>
109+
<fillField selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" userInput="1" stepKey="changeQtyToInvoice"/>
110+
<waitForElementVisible selector="{{AdminInvoiceItemsSection.updateQtyEnabled}}" stepKey="waitForUpdateQtyEnabled"/>
111+
<click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQty"/>
112+
<waitForLoadingMaskToDisappear stepKey="waitForQtyToUpdate"/>
113+
<waitForElementVisible selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="waitForSubmitInvoiceButton"/>
114+
<actionGroup ref="SubmitInvoice" stepKey="submitInvoice"/>
115+
<!--Create Shipment-->
116+
<actionGroup ref="StartCreateShipmentFromOrderPage" stepKey="startCreateShipment"/>
117+
<fillField selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" userInput="1" stepKey="changeItemQtyToShip"/>
118+
<actionGroup ref="SubmitShipment" stepKey="submitShipment"/>
119+
120+
<!--Cancel order-->
121+
<actionGroup ref="cancelCompleteOrder" stepKey="cancelOrder"/>
122+
<!--Check quantities in "Items Ordered" table-->
123+
<see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Invoiced 1" stepKey="seeInvoicedQuantity"/>
124+
<see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Shipped 1" stepKey="seeShippedQuantity"/>
125+
<see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Canceled 3" stepKey="seeCanceledQuantity"/>
126+
127+
<!--Go to catalog products page on Admin-->
128+
<amOnPage url="{{AdminCatalogProductPage.url}}" stepKey="goToCatalogProductPage"/>
129+
<actionGroup ref="filterProductGridBySku" stepKey="filterProductGrid">
130+
<argument name="product" value="$$createConfigChildProduct$$"/>
131+
</actionGroup>
132+
133+
<!--Check quantity of configurable child product-->
134+
<see selector="{{AdminProductGridSection.productGridCell('1', 'Quantity')}}" userInput="99" stepKey="seeProductSkuInGrid"/>
135+
</test>
136+
</tests>

app/code/Magento/Sales/Model/Service/InvoiceService.php

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
namespace Magento\Sales\Model\Service;
77

8+
use Magento\Sales\Api\Data\OrderItemInterface;
89
use Magento\Sales\Api\InvoiceManagementInterface;
910
use Magento\Sales\Model\Order;
1011

@@ -136,14 +137,14 @@ public function prepareInvoice(Order $order, array $qtys = [])
136137
$totalQty = 0;
137138
$qtys = $this->prepareItemsQty($order, $qtys);
138139
foreach ($order->getAllItems() as $orderItem) {
139-
if (!$this->_canInvoiceItem($orderItem)) {
140+
if (!$this->_canInvoiceItem($orderItem, $qtys)) {
140141
continue;
141142
}
142143
$item = $this->orderConverter->itemToInvoiceItem($orderItem);
143-
if ($orderItem->isDummy()) {
144-
$qty = $orderItem->getQtyOrdered() ? $orderItem->getQtyOrdered() : 1;
145-
} elseif (isset($qtys[$orderItem->getId()])) {
144+
if (isset($qtys[$orderItem->getId()])) {
146145
$qty = (double) $qtys[$orderItem->getId()];
146+
} elseif ($orderItem->isDummy()) {
147+
$qty = $orderItem->getQtyOrdered() ? $orderItem->getQtyOrdered() : 1;
147148
} elseif (empty($qtys)) {
148149
$qty = $orderItem->getQtyToInvoice();
149150
} else {
@@ -170,38 +171,55 @@ private function prepareItemsQty(Order $order, array $qtys = [])
170171
{
171172
foreach ($order->getAllItems() as $orderItem) {
172173
if (empty($qtys[$orderItem->getId()])) {
173-
continue;
174-
}
175-
if ($orderItem->isDummy()) {
176-
if ($orderItem->getHasChildren()) {
177-
foreach ($orderItem->getChildrenItems() as $child) {
178-
if (!isset($qtys[$child->getId()])) {
179-
$qtys[$child->getId()] = $child->getQtyToInvoice();
180-
}
181-
}
182-
} elseif ($orderItem->getParentItem()) {
183-
$parent = $orderItem->getParentItem();
184-
if (!isset($qtys[$parent->getId()])) {
185-
$qtys[$parent->getId()] = $parent->getQtyToInvoice();
186-
}
174+
$parentId = $orderItem->getParentItemId();
175+
if ($parentId && array_key_exists($parentId, $qtys)) {
176+
$qtys[$orderItem->getId()] = $qtys[$parentId];
177+
} else {
178+
continue;
187179
}
188180
}
181+
$this->prepareItemQty($orderItem, $qtys);
189182
}
190183

191184
return $qtys;
192185
}
193186

187+
/**
188+
* Prepare qty to invoice item.
189+
*
190+
* @param OrderItemInterface $orderItem
191+
* @param array $qtys
192+
* @return void
193+
*/
194+
private function prepareItemQty(OrderItemInterface $orderItem, array &$qtys)
195+
{
196+
if ($orderItem->isDummy()) {
197+
if ($orderItem->getHasChildren()) {
198+
foreach ($orderItem->getChildrenItems() as $child) {
199+
if (!isset($qtys[$child->getId()])) {
200+
$qtys[$child->getId()] = $child->getQtyToInvoice();
201+
}
202+
}
203+
} elseif ($orderItem->getParentItem()) {
204+
$parent = $orderItem->getParentItem();
205+
if (!isset($qtys[$parent->getId()])) {
206+
$qtys[$parent->getId()] = $parent->getQtyToInvoice();
207+
}
208+
}
209+
}
210+
}
211+
194212
/**
195213
* Check if order item can be invoiced. Dummy item can be invoiced or with his children or
196214
* with parent item which is included to invoice
197215
*
198-
* @param \Magento\Sales\Api\Data\OrderItemInterface $item
216+
* @param OrderItemInterface $item
217+
* @param array $qtys
199218
* @return bool
200219
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
201220
*/
202-
protected function _canInvoiceItem(\Magento\Sales\Api\Data\OrderItemInterface $item)
221+
protected function _canInvoiceItem(OrderItemInterface $item, array $qtys = [])
203222
{
204-
$qtys = [];
205223
if ($item->getLockedDoInvoice()) {
206224
return false;
207225
}

app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
<see selector="{{AdminOrderDetailsInformationSection.orderStatus}}" userInput="Canceled" stepKey="seeOrderStatusCanceled"/>
1919
</actionGroup>
2020

21+
<!--Cancel order that is in complete status-->
22+
<actionGroup name="cancelCompleteOrder" extends="cancelPendingOrder">
23+
<remove keyForRemoval="seeOrderStatusCanceled"/>
24+
<see selector="{{AdminOrderDetailsInformationSection.orderStatus}}" after="seeCancelSuccessMessage" userInput="Complete" stepKey="seeOrderStatusComplete"/>
25+
</actionGroup>
26+
2127
<!--Navigate to create order page (New Order -> Create New Customer)-->
2228
<actionGroup name="navigateToNewOrderPageNewCustomerSingleStore">
2329
<arguments>

0 commit comments

Comments
 (0)