Skip to content

Commit 46e545d

Browse files
committed
Merge remote-tracking branch 'trigger/MAGETWO-95346' into BugFixPR
2 parents 91e6e33 + fc90587 commit 46e545d

File tree

4 files changed

+190
-5
lines changed

4 files changed

+190
-5
lines changed

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ public function setVoid($id)
125125
}
126126

127127
/**
128+
* Creates an invoice based on the order and quantities provided
129+
*
128130
* @param Order $order
129131
* @param array $qtys
130132
* @return \Magento\Sales\Model\Order\Invoice
@@ -136,7 +138,7 @@ public function prepareInvoice(Order $order, array $qtys = [])
136138
$totalQty = 0;
137139
$qtys = $this->prepareItemsQty($order, $qtys);
138140
foreach ($order->getAllItems() as $orderItem) {
139-
if (!$this->_canInvoiceItem($orderItem)) {
141+
if (!$this->_canInvoiceItem($orderItem, $qtys)) {
140142
continue;
141143
}
142144
$item = $this->orderConverter->itemToInvoiceItem($orderItem);
@@ -192,16 +194,15 @@ private function prepareItemsQty(Order $order, array $qtys = [])
192194
}
193195

194196
/**
195-
* Check if order item can be invoiced. Dummy item can be invoiced or with his children or
196-
* with parent item which is included to invoice
197+
* Check if order item can be invoiced.
197198
*
198199
* @param \Magento\Sales\Api\Data\OrderItemInterface $item
200+
* @param array $qtys
199201
* @return bool
200202
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
201203
*/
202-
protected function _canInvoiceItem(\Magento\Sales\Api\Data\OrderItemInterface $item)
204+
protected function _canInvoiceItem(\Magento\Sales\Api\Data\OrderItemInterface $item, array $qtys = [])
203205
{
204-
$qtys = [];
205206
if ($item->getLockedDoInvoice()) {
206207
return false;
207208
}

dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,96 @@ public function testInvoiceCreate()
9090
'Failed asserting that Order status was changed'
9191
);
9292
}
93+
94+
/**
95+
* Tests that MAGETWO-95346 was fixed for bundled products
96+
*
97+
* @expectedException \Exception
98+
* @codingStandardsIgnoreStart
99+
* @expectedExceptionMessageRegExp /Invoice Document Validation Error\(s\):(?:\n|\\n)The invoice can't be created without products. Add products and try again./
100+
* @codingStandardsIgnoreEnd
101+
* @magentoApiDataFixture Magento/Sales/_files/order_with_bundle.php
102+
*/
103+
public function testOrderWithBundleInvoicedWithInvalidQuantitiesReturnsError()
104+
{
105+
/** @var \Magento\Sales\Model\Order $existingOrder */
106+
$existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
107+
->loadByIncrementId('100000001');
108+
109+
$serviceInfo = [
110+
'rest' => [
111+
'resourcePath' => '/V1/order/' . $existingOrder->getId() . '/invoice',
112+
'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
113+
],
114+
'soap' => [
115+
'service' => self::SERVICE_READ_NAME,
116+
'serviceVersion' => self::SERVICE_VERSION,
117+
'operation' => self::SERVICE_READ_NAME . 'execute',
118+
],
119+
];
120+
121+
$requestData = [
122+
'orderId' => $existingOrder->getId(),
123+
'notify' => true,
124+
'appendComment' => true,
125+
'items' => [
126+
[
127+
'order_item_id' => -1,
128+
'qty' => 1
129+
]
130+
],
131+
'comment' => [
132+
'comment' => 'Test offline',
133+
'isVisibleOnFront' => 1,
134+
],
135+
];
136+
137+
$this->_webApiCall($serviceInfo, $requestData);
138+
}
139+
140+
/**
141+
* Tests that MAGETWO-95346 was fixed for configurable products
142+
*
143+
* @expectedException \Exception
144+
* @codingStandardsIgnoreStart
145+
* @expectedExceptionMessageRegExp /Invoice Document Validation Error\(s\):(?:\n|\\n)The invoice can't be created without products. Add products and try again./
146+
* @codingStandardsIgnoreEnd
147+
* @magentoApiDataFixture Magento/Sales/_files/order_configurable_product.php
148+
*/
149+
public function testOrderWithConfigurableProductInvoicedWithInvalidQuantitiesReturnsError()
150+
{
151+
/** @var \Magento\Sales\Model\Order $existingOrder */
152+
$existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
153+
->loadByIncrementId('100000001');
154+
155+
$serviceInfo = [
156+
'rest' => [
157+
'resourcePath' => '/V1/order/' . $existingOrder->getId() . '/invoice',
158+
'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
159+
],
160+
'soap' => [
161+
'service' => self::SERVICE_READ_NAME,
162+
'serviceVersion' => self::SERVICE_VERSION,
163+
'operation' => self::SERVICE_READ_NAME . 'execute',
164+
],
165+
];
166+
167+
$requestData = [
168+
'orderId' => $existingOrder->getId(),
169+
'notify' => true,
170+
'appendComment' => true,
171+
'items' => [
172+
[
173+
'order_item_id' => -1,
174+
'qty' => 1
175+
]
176+
],
177+
'comment' => [
178+
'comment' => 'Test offline',
179+
'isVisibleOnFront' => 1,
180+
],
181+
];
182+
183+
$this->_webApiCall($serviceInfo, $requestData);
184+
}
93185
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Sales\Api\Data\OrderItemInterface;
9+
use Magento\Sales\Api\OrderItemRepositoryInterface;
10+
use Magento\Sales\Api\OrderRepositoryInterface;
11+
use Magento\Sales\Model\Order;
12+
use Magento\Sales\Model\Order\Item;
13+
use Magento\TestFramework\ObjectManager;
14+
15+
$objectManager = ObjectManager::getInstance();
16+
17+
require 'order.php';
18+
/** @var Order $order */
19+
20+
$orderItems = [
21+
[
22+
OrderItemInterface::PRODUCT_ID => 2,
23+
OrderItemInterface::BASE_PRICE => 100,
24+
OrderItemInterface::ORDER_ID => $order->getId(),
25+
OrderItemInterface::QTY_ORDERED => 2,
26+
OrderItemInterface::QTY_INVOICED => 2,
27+
OrderItemInterface::PRICE => 100,
28+
OrderItemInterface::ROW_TOTAL => 102,
29+
OrderItemInterface::PRODUCT_TYPE => 'bundle',
30+
'product_options' => [
31+
'product_calculations' => 0,
32+
],
33+
'children' => [
34+
[
35+
OrderItemInterface::PRODUCT_ID => 13,
36+
OrderItemInterface::ORDER_ID => $order->getId(),
37+
OrderItemInterface::QTY_ORDERED => 10,
38+
OrderItemInterface::QTY_INVOICED => 10,
39+
OrderItemInterface::BASE_PRICE => 90,
40+
OrderItemInterface::PRICE => 90,
41+
OrderItemInterface::ROW_TOTAL => 92,
42+
OrderItemInterface::PRODUCT_TYPE => 'simple',
43+
'product_options' => [
44+
'bundle_selection_attributes' => [
45+
'qty' => 2,
46+
],
47+
],
48+
],
49+
],
50+
],
51+
];
52+
53+
if (!function_exists('saveOrderItems')) {
54+
/**
55+
* Save Order Items.
56+
*
57+
* @param array $orderItems
58+
* @param Item|null $parentOrderItem [optional]
59+
* @return void
60+
*/
61+
function saveOrderItems(array $orderItems, Order $order, $parentOrderItem = null)
62+
{
63+
$objectManager = ObjectManager::getInstance();
64+
65+
foreach ($orderItems as $orderItemData) {
66+
/** @var Item $orderItem */
67+
$orderItem = $objectManager->create(Item::class);
68+
if (null !== $parentOrderItem) {
69+
$orderItemData['parent_item'] = $parentOrderItem;
70+
}
71+
$orderItem->setData($orderItemData);
72+
$order->addItem($orderItem);
73+
74+
if (isset($orderItemData['children'])) {
75+
saveOrderItems($orderItemData['children'], $order, $orderItem);
76+
}
77+
}
78+
}
79+
}
80+
81+
saveOrderItems($orderItems, $order);
82+
/** @var OrderRepositoryInterface $orderRepository */
83+
$orderRepository = $objectManager->get(OrderRepositoryInterface::class);
84+
$order = $orderRepository->save($order);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
require 'order_rollback.php';

0 commit comments

Comments
 (0)