Skip to content

Commit 2fb6b3b

Browse files
author
Alexey Yakimovich
committed
MAGETWO-96545: Wrong calculation of invoiced items in shipment document in order with bundle product after partial invoice
- Partial invoice feature has been removed for bundled products when it should be shipped together;
1 parent 9291b8a commit 2fb6b3b

File tree

2 files changed

+84
-20
lines changed

2 files changed

+84
-20
lines changed

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

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

3030
<?php foreach ($items as $_item): ?>
31+
<?php
32+
$orderItem = $_item->getOrderItem();
33+
if ($orderItem->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) {
34+
$shipTogether = !$orderItem->isShipSeparately();
35+
} else {
36+
$shipTogether = !$orderItem->getParentItem()->isShipSeparately();
37+
}
38+
?>
3139
<?php $block->setPriceDataObject($_item) ?>
3240
<?php if ($_item->getOrderItem()->getParentItem()): ?>
41+
<?php
42+
if ($shipTogether) {
43+
continue;
44+
}
45+
?>
3346
<?php $attributes = $block->getSelectionAttributes($_item) ?>
3447
<?php if ($_prevOptionId != $attributes['option_id']): ?>
3548
<tr>
@@ -60,14 +73,14 @@
6073
</td>
6174
<?php endif; ?>
6275
<td class="col-price">
63-
<?php if ($block->canShowPriceInfo($_item)): ?>
76+
<?php if ($block->canShowPriceInfo($_item) || $shipTogether): ?>
6477
<?= $block->getColumnHtml($_item, 'price') ?>
6578
<?php else: ?>
6679
&nbsp;
6780
<?php endif; ?>
6881
</td>
6982
<td class="col-qty">
70-
<?php if ($block->canShowPriceInfo($_item)): ?>
83+
<?php if ($block->canShowPriceInfo($_item) || $shipTogether): ?>
7184
<table class="qty-table">
7285
<tr>
7386
<th><?= /* @escapeNotVerified */ __('Ordered') ?></th>
@@ -116,7 +129,7 @@
116129
<?php endif; ?>
117130
</td>
118131
<td class="col-qty-invoice">
119-
<?php if ($block->canShowPriceInfo($_item)): ?>
132+
<?php if ($block->canShowPriceInfo($_item) || $shipTogether): ?>
120133
<?php if ($block->canEditQty()) : ?>
121134
<input type="text"
122135
class="input-text admin__control-text qty-input"

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

Lines changed: 68 additions & 17 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
/**
@@ -142,10 +157,10 @@ public function prepareInvoice(Order $order, array $qtys = [])
142157
continue;
143158
}
144159
$item = $this->orderConverter->itemToInvoiceItem($orderItem);
145-
if ($orderItem->isDummy()) {
146-
$qty = $orderItem->getQtyOrdered() ? $orderItem->getQtyOrdered() : 1;
147-
} elseif (isset($qtys[$orderItem->getId()])) {
160+
if (isset($qtys[$orderItem->getId()])) {
148161
$qty = (double) $qtys[$orderItem->getId()];
162+
} elseif ($orderItem->isDummy()) {
163+
$qty = $orderItem->getQtyOrdered() ? $orderItem->getQtyOrdered() : 1;
149164
} elseif (empty($qtys)) {
150165
$qty = $orderItem->getQtyToInvoice();
151166
} else {
@@ -172,25 +187,61 @@ private function prepareItemsQty(Order $order, array $qtys = [])
172187
{
173188
foreach ($order->getAllItems() as $orderItem) {
174189
if (empty($qtys[$orderItem->getId()])) {
175-
continue;
190+
if ($orderItem->getProductType() == Type::TYPE_BUNDLE && !$orderItem->isShipSeparately()) {
191+
$qtys[$orderItem->getId()] = $orderItem->getQtyOrdered() - $orderItem->getQtyInvoiced();
192+
} else {
193+
continue;
194+
}
176195
}
177-
if ($orderItem->isDummy()) {
178-
if ($orderItem->getHasChildren()) {
179-
foreach ($orderItem->getChildrenItems() as $child) {
180-
if (!isset($qtys[$child->getId()])) {
181-
$qtys[$child->getId()] = $child->getQtyToInvoice();
182-
}
183-
}
184-
} elseif ($orderItem->getParentItem()) {
185-
$parent = $orderItem->getParentItem();
186-
if (!isset($qtys[$parent->getId()])) {
187-
$qtys[$parent->getId()] = $parent->getQtyToInvoice();
196+
197+
$this->prepareItemQty($orderItem, $qtys);
198+
}
199+
200+
return $qtys;
201+
}
202+
203+
/**
204+
* Prepare qty_invoiced for order item
205+
*
206+
* @param \Magento\Sales\Api\Data\OrderItemInterface $orderItem
207+
* @param array $qtys
208+
*/
209+
private function prepareItemQty(\Magento\Sales\Api\Data\OrderItemInterface $orderItem, &$qtys)
210+
{
211+
$this->prepareBundleQty($orderItem, $qtys);
212+
213+
if ($orderItem->isDummy()) {
214+
if ($orderItem->getHasChildren()) {
215+
foreach ($orderItem->getChildrenItems() as $child) {
216+
if (!isset($qtys[$child->getId()])) {
217+
$qtys[$child->getId()] = $child->getQtyToInvoice();
188218
}
189219
}
220+
} elseif ($orderItem->getParentItem()) {
221+
$parent = $orderItem->getParentItem();
222+
if (!isset($qtys[$parent->getId()])) {
223+
$qtys[$parent->getId()] = $parent->getQtyToInvoice();
224+
}
190225
}
191226
}
227+
}
192228

193-
return $qtys;
229+
/**
230+
* Prepare qty to invoice for bundle products
231+
*
232+
* @param \Magento\Sales\Api\Data\OrderItemInterface $orderItem
233+
* @param array $qtys
234+
*/
235+
private function prepareBundleQty(\Magento\Sales\Api\Data\OrderItemInterface $orderItem, &$qtys)
236+
{
237+
if ($orderItem->getProductType() == Type::TYPE_BUNDLE && !$orderItem->isShipSeparately()) {
238+
foreach ($orderItem->getChildrenItems() as $childItem) {
239+
$bundleSelectionAttributes = $this->serializer->unserialize(
240+
$childItem->getProductOptionByCode('bundle_selection_attributes')
241+
);
242+
$qtys[$childItem->getId()] = $qtys[$orderItem->getId()] * $bundleSelectionAttributes['qty'];
243+
}
244+
}
194245
}
195246

196247
/**

0 commit comments

Comments
 (0)