Skip to content

Commit aca3c0d

Browse files
Merge branch 'MAGETWO-96545' of https://github.com/magento-epam/magento2ce into MAGETWO-96545
2 parents 8dfe26a + ffbb3a4 commit aca3c0d

File tree

5 files changed

+185
-11
lines changed

5 files changed

+185
-11
lines changed

app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ public function getChildren($item)
100100
}
101101

102102
/**
103+
* Check if item can be shipped separately
104+
*
103105
* @param mixed $item
104106
* @return bool
105107
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
@@ -136,6 +138,8 @@ public function isShipmentSeparately($item = null)
136138
}
137139

138140
/**
141+
* Check if child items calculated
142+
*
139143
* @param mixed $item
140144
* @return bool
141145
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
@@ -174,6 +178,8 @@ public function isChildCalculated($item = null)
174178
}
175179

176180
/**
181+
* Retrieve selection attributes values
182+
*
177183
* @param mixed $item
178184
* @return mixed|null
179185
*/
@@ -191,6 +197,8 @@ public function getSelectionAttributes($item)
191197
}
192198

193199
/**
200+
* Retrieve order item options array
201+
*
194202
* @return array
195203
*/
196204
public function getOrderOptions()
@@ -212,6 +220,8 @@ public function getOrderOptions()
212220
}
213221

214222
/**
223+
* Retrieve order item
224+
*
215225
* @return mixed
216226
*/
217227
public function getOrderItem()
@@ -223,6 +233,8 @@ public function getOrderItem()
223233
}
224234

225235
/**
236+
* Get html info for item
237+
*
226238
* @param mixed $item
227239
* @return string
228240
*/
@@ -245,6 +257,8 @@ public function getValueHtml($item)
245257
}
246258

247259
/**
260+
* Check if we can show price info for this item
261+
*
248262
* @param object $item
249263
* @return bool
250264
*/
@@ -257,4 +271,22 @@ public function canShowPriceInfo($item)
257271
}
258272
return false;
259273
}
274+
275+
/**
276+
* Check if this iten should be shipped together
277+
*
278+
* @param object $item
279+
* @return bool
280+
*/
281+
public function isShipTogether($item)
282+
{
283+
$orderItem = $item->getOrderItem();
284+
if ($orderItem->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) {
285+
$shipTogether = !$orderItem->isShipSeparately();
286+
} else {
287+
$shipTogether = !$orderItem->getParentItem()->isShipSeparately();
288+
}
289+
290+
return $shipTogether;
291+
}
260292
}

app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,16 @@
2828
<?php endif; ?>
2929

3030
<?php foreach ($items as $_item): ?>
31+
<?php
32+
$shipTogether = $block->isShipTogether($_item);
33+
?>
3134
<?php $block->setPriceDataObject($_item) ?>
3235
<?php if ($_item->getOrderItem()->getParentItem()): ?>
36+
<?php
37+
if ($shipTogether) {
38+
continue;
39+
}
40+
?>
3341
<?php $attributes = $block->getSelectionAttributes($_item) ?>
3442
<?php if ($_prevOptionId != $attributes['option_id']): ?>
3543
<tr>
@@ -60,14 +68,14 @@
6068
</td>
6169
<?php endif; ?>
6270
<td class="col-price">
63-
<?php if ($block->canShowPriceInfo($_item)): ?>
71+
<?php if ($block->canShowPriceInfo($_item) || $shipTogether): ?>
6472
<?= $block->getColumnHtml($_item, 'price') ?>
6573
<?php else: ?>
6674
&nbsp;
6775
<?php endif; ?>
6876
</td>
6977
<td class="col-qty">
70-
<?php if ($block->canShowPriceInfo($_item)): ?>
78+
<?php if ($block->canShowPriceInfo($_item) || $shipTogether): ?>
7179
<table class="qty-table">
7280
<tr>
7381
<th><?= /* @escapeNotVerified */ __('Ordered') ?></th>
@@ -116,7 +124,7 @@
116124
<?php endif; ?>
117125
</td>
118126
<td class="col-qty-invoice">
119-
<?php if ($block->canShowPriceInfo($_item)): ?>
127+
<?php if ($block->canShowPriceInfo($_item) || $shipTogether): ?>
120128
<?php if ($block->canEditQty()) : ?>
121129
<input type="text"
122130
class="input-text admin__control-text qty-input"

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

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@
77

88
use Magento\Sales\Api\InvoiceManagementInterface;
99
use Magento\Sales\Model\Order;
10+
use Magento\Framework\App\ObjectManager;
11+
use Magento\Framework\Serialize\Serializer\Json;
12+
use Magento\Catalog\Model\Product\Type;
1013

1114
/**
1215
* Class InvoiceService
16+
*
17+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1318
*/
1419
class InvoiceService implements InvoiceManagementInterface
1520
{
@@ -58,6 +63,13 @@ class InvoiceService implements InvoiceManagementInterface
5863
*/
5964
protected $orderConverter;
6065

66+
/**
67+
* Serializer interface instance.
68+
*
69+
* @var Json
70+
*/
71+
private $serializer;
72+
6173
/**
6274
* Constructor
6375
*
@@ -68,6 +80,7 @@ class InvoiceService implements InvoiceManagementInterface
6880
* @param \Magento\Sales\Model\Order\InvoiceNotifier $notifier
6981
* @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
7082
* @param \Magento\Sales\Model\Convert\Order $orderConverter
83+
* @param Json|null $serializer
7184
*/
7285
public function __construct(
7386
\Magento\Sales\Api\InvoiceRepositoryInterface $repository,
@@ -76,7 +89,8 @@ public function __construct(
7689
\Magento\Framework\Api\FilterBuilder $filterBuilder,
7790
\Magento\Sales\Model\Order\InvoiceNotifier $notifier,
7891
\Magento\Sales\Api\OrderRepositoryInterface $orderRepository,
79-
\Magento\Sales\Model\Convert\Order $orderConverter
92+
\Magento\Sales\Model\Convert\Order $orderConverter,
93+
Json $serializer = null
8094
) {
8195
$this->repository = $repository;
8296
$this->commentRepository = $commentRepository;
@@ -85,6 +99,7 @@ public function __construct(
8599
$this->invoiceNotifier = $notifier;
86100
$this->orderRepository = $orderRepository;
87101
$this->orderConverter = $orderConverter;
102+
$this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
88103
}
89104

90105
/**
@@ -172,34 +187,41 @@ private function prepareItemsQty(Order $order, array $qtys = [])
172187
{
173188
foreach ($order->getAllItems() as $orderItem) {
174189
if (empty($qtys[$orderItem->getId()])) {
175-
$parentId = $orderItem->getParentItemId();
176-
if ($parentId && array_key_exists($parentId, $qtys)) {
177-
$qtys[$orderItem->getId()] = $qtys[$parentId];
190+
if ($orderItem->getProductType() == Type::TYPE_BUNDLE && !$orderItem->isShipSeparately()) {
191+
$qtys[$orderItem->getId()] = $orderItem->getQtyOrdered() - $orderItem->getQtyInvoiced();
178192
} else {
179193
continue;
180194
}
181195
}
196+
182197
$this->prepareItemQty($orderItem, $qtys);
183198
}
184199

185200
return $qtys;
186201
}
187202

188203
/**
189-
* Prepare qty to invoice item.
204+
* Prepare qty_invoiced for order item
190205
*
191-
* @param Order\Item $orderItem
206+
* @param \Magento\Sales\Api\Data\OrderItemInterface $orderItem
192207
* @param array $qtys
193-
* @return void
194208
*/
195209
private function prepareItemQty(\Magento\Sales\Api\Data\OrderItemInterface $orderItem, &$qtys)
196210
{
211+
$this->prepareBundleQty($orderItem, $qtys);
212+
197213
if ($orderItem->isDummy()) {
198214
if ($orderItem->getHasChildren()) {
199215
foreach ($orderItem->getChildrenItems() as $child) {
200216
if (!isset($qtys[$child->getId()])) {
201217
$qtys[$child->getId()] = $child->getQtyToInvoice();
202218
}
219+
$parentId = $orderItem->getParentItemId();
220+
if ($parentId && array_key_exists($parentId, $qtys)) {
221+
$qtys[$orderItem->getId()] = $qtys[$parentId];
222+
} else {
223+
continue;
224+
}
203225
}
204226
} elseif ($orderItem->getParentItem()) {
205227
$parent = $orderItem->getParentItem();
@@ -210,6 +232,26 @@ private function prepareItemQty(\Magento\Sales\Api\Data\OrderItemInterface $orde
210232
}
211233
}
212234

235+
/**
236+
* Prepare qty to invoice for bundle products
237+
*
238+
* @param \Magento\Sales\Api\Data\OrderItemInterface $orderItem
239+
* @param array $qtys
240+
*/
241+
private function prepareBundleQty(\Magento\Sales\Api\Data\OrderItemInterface $orderItem, &$qtys)
242+
{
243+
if ($orderItem->getProductType() == Type::TYPE_BUNDLE && !$orderItem->isShipSeparately()) {
244+
foreach ($orderItem->getChildrenItems() as $childItem) {
245+
$bundleSelectionAttributes = $childItem->getProductOptionByCode('bundle_selection_attributes');
246+
if (is_string($bundleSelectionAttributes)) {
247+
$bundleSelectionAttributes = $this->serializer->unserialize($bundleSelectionAttributes);
248+
}
249+
250+
$qtys[$childItem->getId()] = $qtys[$orderItem->getId()] * $bundleSelectionAttributes['qty'];
251+
}
252+
}
253+
}
254+
213255
/**
214256
* Check if order item can be invoiced.
215257
*
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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+
9+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
11+
<test name="AdminCorrectnessInvoicedItemInBundleProductTest">
12+
<annotations>
13+
<features value="Sales"/>
14+
<title value="Check correctness of invoiced items in a Bundle Product"/>
15+
<description value="Check correctness of invoiced items in a Bundle Product"/>
16+
<severity value="CRITICAL"/>
17+
<testCaseId value="MC-11059"/>
18+
<useCaseId value="MC-10969"/>
19+
<group value="sales"/>
20+
</annotations>
21+
<before>
22+
<actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>
23+
24+
<!--Create category and simple product-->
25+
<createData entity="SimpleSubCategory" stepKey="createCategory"/>
26+
<createData entity="_defaultProduct" stepKey="createSimpleProduct">
27+
<requiredEntity createDataKey="createCategory"/>
28+
</createData>
29+
30+
<!--Create bundle product-->
31+
<createData entity="ApiBundleProductPriceViewRange" stepKey="createBundleProduct">
32+
<requiredEntity createDataKey="createCategory"/>
33+
</createData>
34+
<createData entity="DropDownBundleOption" stepKey="bundleOption">
35+
<requiredEntity createDataKey="createBundleProduct"/>
36+
</createData>
37+
<createData entity="ApiBundleLink" stepKey="createBundleLink1">
38+
<requiredEntity createDataKey="createBundleProduct"/>
39+
<requiredEntity createDataKey="bundleOption"/>
40+
<requiredEntity createDataKey="createSimpleProduct"/>
41+
<field key="qty">10</field>
42+
</createData>
43+
</before>
44+
<after>
45+
<!--Delete created data-->
46+
<deleteData createDataKey="createCategory" stepKey="deleteCategory"/>
47+
<deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/>
48+
<deleteData createDataKey="createBundleProduct" stepKey="deleteBundleProduct"/>
49+
50+
<actionGroup ref="logout" stepKey="logOut"/>
51+
</after>
52+
53+
<!--Complete Bundle product creation-->
54+
<amOnPage url="{{AdminProductEditPage.url($$createBundleProduct.id$$)}}" stepKey="goToProductEditPage"/>
55+
<actionGroup ref="saveProductForm" stepKey="saveProduct"/>
56+
57+
<!--Go to bundle product page-->
58+
<amOnPage url="{{StorefrontProductPage.url($$createCategory.name$$)}}" stepKey="navigateToBundleProductPage"/>
59+
60+
<!--Place order bundle product with 10 options-->
61+
<actionGroup ref="StorefrontAddCategoryBundleProductToCartActionGroup" stepKey="addBundleProductToCart">
62+
<argument name="product" value="$$createBundleProduct$$"/>
63+
<argument name="quantity" value="10"/>
64+
</actionGroup>
65+
<actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart" />
66+
<actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShipping"/>
67+
<actionGroup ref="CheckoutPlaceOrderActionGroup" stepKey="placeOrder">
68+
<argument name="orderNumberMessage" value="CONST.successGuestCheckoutOrderNumberMessage" />
69+
<argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage"/>
70+
</actionGroup>
71+
72+
<!--Go to order page submit invoice-->
73+
<grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/>
74+
<amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/>
75+
<actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById">
76+
<argument name="orderId" value="$grabOrderNumber"/>
77+
</actionGroup>
78+
<click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/>
79+
<waitForPageLoad stepKey="waitForCreatedOrderPageOpened"/>
80+
<actionGroup ref="goToInvoiceIntoOrder" stepKey="goToInvoiceIntoOrderPage"/>
81+
<fillField selector="{{AdminInvoiceItemsSection.qtyToInvoiceColumn}}" userInput="5" stepKey="ChangeQtyToInvoice"/>
82+
<click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQunatity"/>
83+
<waitForPageLoad stepKey="waitPageToBeLoaded"/>
84+
<actionGroup ref="submitInvoiceIntoOrder" stepKey="submitInvoice"/>
85+
86+
<!--Verify invoiced items qty in ship tab-->
87+
<actionGroup ref="goToShipmentIntoOrder" stepKey="goToShipment"/>
88+
<grabTextFrom selector="{{AdminShipmentItemsSection.itemQtyInvoiced('1')}}" stepKey="grabInvoicedItemQty"/>
89+
<assertEquals expected="5" expectedType="string" actual="$grabInvoicedItemQty" stepKey="assertInvoicedItemsQty"/>
90+
</test>
91+
</tests>

app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@
1515
<element name="itemQtyToShip" type="input" selector=".order-shipment-table tbody:nth-of-type({{var1}}) .col-qty input.qty-item" parameterized="true"/>
1616
<element name="nameColumn" type="text" selector=".order-shipment-table .col-product .product-title"/>
1717
<element name="skuColumn" type="text" selector=".order-shipment-table .col-product .product-sku-block"/>
18+
<element name="itemQtyInvoiced" type="text" selector="(//*[@class='col-ordered-qty']//th[contains(text(), 'Invoiced')]/following-sibling::td)[{{var}}]" parameterized="true"/>
1819
</section>
19-
</sections>
20+
</sections>

0 commit comments

Comments
 (0)