Skip to content

Commit 5cc44b7

Browse files
committed
MC-6420: Ship Order API. Two bundle products with ship bundle items set to separately in order
1 parent c3f29ce commit 5cc44b7

File tree

5 files changed

+354
-27
lines changed

5 files changed

+354
-27
lines changed

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

Lines changed: 132 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
*/
66
namespace Magento\Sales\Service\V1;
77

8+
use Magento\Catalog\Api\ProductRepositoryInterface;
9+
use Magento\Framework\ObjectManagerInterface;
10+
use Magento\Sales\Api\Data\OrderItemInterface;
11+
use Magento\Sales\Api\ShipmentRepositoryInterface;
12+
use Magento\Sales\Model\Order;
13+
814
/**
915
* API test for creation of Shipment for certain Order.
1016
*/
@@ -14,22 +20,28 @@ class ShipOrderTest extends \Magento\TestFramework\TestCase\WebapiAbstract
1420
const SERVICE_VERSION = 'V1';
1521

1622
/**
17-
* @var \Magento\Framework\ObjectManagerInterface
23+
* @var ObjectManagerInterface
1824
*/
1925
private $objectManager;
2026

2127
/**
22-
* @var \Magento\Sales\Api\ShipmentRepositoryInterface
28+
* @var ShipmentRepositoryInterface
2329
*/
2430
private $shipmentRepository;
2531

32+
/**
33+
* @var ProductRepositoryInterface
34+
*/
35+
private $productRepository;
36+
37+
/**
38+
* @inheritdoc
39+
*/
2640
protected function setUp()
2741
{
2842
$this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
29-
30-
$this->shipmentRepository = $this->objectManager->get(
31-
\Magento\Sales\Api\ShipmentRepositoryInterface::class
32-
);
43+
$this->shipmentRepository = $this->objectManager->get(ShipmentRepositoryInterface::class);
44+
$this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class);
3345
}
3446

3547
/**
@@ -40,9 +52,8 @@ public function testConfigurableShipOrder()
4052
$this->markTestIncomplete('https://github.com/magento-engcom/msi/issues/1335');
4153
$productsQuantity = 1;
4254

43-
/** @var \Magento\Sales\Model\Order $existingOrder */
44-
$existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
45-
->loadByIncrementId('100000001');
55+
/** @var Order $existingOrder */
56+
$existingOrder = $this->getOrder('100000001');
4657

4758
$requestData = [
4859
'orderId' => $existingOrder->getId(),
@@ -83,9 +94,8 @@ public function testConfigurableShipOrder()
8394
*/
8495
public function testShipOrder()
8596
{
86-
/** @var \Magento\Sales\Model\Order $existingOrder */
87-
$existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
88-
->loadByIncrementId('100000001');
97+
/** @var Order $existingOrder */
98+
$existingOrder = $this->getOrder('100000001');
8999

90100
$requestData = [
91101
'orderId' => $existingOrder->getId(),
@@ -103,7 +113,7 @@ public function testShipOrder()
103113
]
104114
];
105115

106-
/** @var \Magento\Sales\Api\Data\OrderItemInterface $item */
116+
/** @var OrderItemInterface $item */
107117
foreach ($existingOrder->getAllItems() as $item) {
108118
$requestData['items'][] = [
109119
'order_item_id' => $item->getItemId(),
@@ -121,9 +131,8 @@ public function testShipOrder()
121131
$this->fail('Failed asserting that Shipment was created');
122132
}
123133

124-
/** @var \Magento\Sales\Model\Order $updatedOrder */
125-
$updatedOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
126-
->loadByIncrementId('100000001');
134+
/** @var Order $updatedOrder */
135+
$updatedOrder = $this->getOrder('100000001');
127136

128137
$this->assertNotEquals(
129138
$existingOrder->getStatus(),
@@ -144,9 +153,8 @@ public function testShipOrderWithoutTrackingNumberReturnsError()
144153
{
145154
$this->_markTestAsRestOnly('SOAP requires an tracking number to be provided so this case is not possible.');
146155

147-
/** @var \Magento\Sales\Model\Order $existingOrder */
148-
$existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
149-
->loadByIncrementId('100000001');
156+
/** @var Order $existingOrder */
157+
$existingOrder = $this->getOrder('100000001');
150158

151159
$requestData = [
152160
'orderId' => $existingOrder->getId(),
@@ -170,9 +178,7 @@ public function testShipOrderWithoutTrackingNumberReturnsError()
170178
*/
171179
public function testPartialShipOrderWithBundleShippedSeparately()
172180
{
173-
/** @var \Magento\Sales\Model\Order $existingOrder */
174-
$existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
175-
->loadByIncrementId('100000001');
181+
$existingOrder = $this->getOrder('100000001');
176182

177183
$requestData = [
178184
'orderId' => $existingOrder->getId(),
@@ -213,9 +219,8 @@ public function testPartialShipOrderWithBundleShippedSeparately()
213219

214220
$this->assertEquals(1, $shipment->getTotalQty());
215221

216-
/** @var \Magento\Sales\Model\Order $existingOrder */
217-
$existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
218-
->loadByIncrementId('100000001');
222+
/** @var Order $existingOrder */
223+
$existingOrder = $this->getOrder('100000001');
219224

220225
foreach ($existingOrder->getAllItems() as $item) {
221226
if ($item->getItemId() == $shippedItemId) {
@@ -227,10 +232,75 @@ public function testPartialShipOrderWithBundleShippedSeparately()
227232
}
228233

229234
/**
230-
* @param \Magento\Sales\Model\Order $order
235+
* @magentoApiDataFixture Magento/Bundle/_files/order_with_2_bundles_shipping_separately.php
236+
*/
237+
public function testPartialShipOrderWithTwoBundleShippedSeparatelyContainsSameSimple()
238+
{
239+
/** @var Order $order */
240+
$order = $this->getOrder('order_bundle_separately_shipped');
241+
242+
$requestData = [
243+
'orderId' => $order->getId(),
244+
'items' => [],
245+
'comment' => [
246+
'comment' => 'Test Comment',
247+
'is_visible_on_front' => 1,
248+
],
249+
'tracks' => []
250+
];
251+
252+
$shippedItemId = null;
253+
$parentItemId = null;
254+
foreach ($order->getAllItems() as $item) {
255+
if ($item->getSku() === 'simple1') {
256+
$requestData['items'][] = [
257+
'order_item_id' => $item->getItemId(),
258+
'qty' => $item->getQtyOrdered(),
259+
];
260+
$shippedItemId = $item->getItemId();
261+
$parentItemId = $item->getParentItemId();
262+
break;
263+
}
264+
}
265+
266+
$shipmentId = $this->_webApiCall($this->getServiceInfo($order), $requestData);
267+
$this->assertNotEmpty($shipmentId);
268+
269+
try {
270+
$shipment = $this->shipmentRepository->get($shipmentId);
271+
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
272+
$this->fail('Failed asserting that Shipment was created');
273+
}
274+
275+
$this->assertEquals(1, $shipment->getTotalQty());
276+
277+
/** @var Order $existingOrder */
278+
$order = $this->getOrder('order_bundle_separately_shipped');
279+
280+
foreach ($order->getAllItems() as $item) {
281+
if (in_array($item->getItemId(), [$shippedItemId, $parentItemId])) {
282+
$this->assertEquals(1, $item->getQtyShipped());
283+
continue;
284+
}
285+
$this->assertEquals(0, $item->getQtyShipped());
286+
}
287+
288+
try {
289+
$this->_webApiCall($this->getServiceInfo($order), $requestData);
290+
$this->fail('Expected exception was not raised');
291+
} catch (\Exception $exception) {
292+
$this->assertExceptionMessage(
293+
$exception,
294+
'Shipment Document Validation Error(s): You can\'t create a shipment without products.'
295+
);
296+
}
297+
}
298+
299+
/**
300+
* @param Order $order
231301
* @return array
232302
*/
233-
private function getServiceInfo(\Magento\Sales\Model\Order $order)
303+
private function getServiceInfo(Order $order): array
234304
{
235305
$serviceInfo = [
236306
'rest' => [
@@ -243,6 +313,41 @@ private function getServiceInfo(\Magento\Sales\Model\Order $order)
243313
'operation' => self::SERVICE_READ_NAME . 'execute',
244314
],
245315
];
316+
246317
return $serviceInfo;
247318
}
319+
320+
/**
321+
* Returns order by increment id.
322+
*
323+
* @param string $incrementId
324+
* @return Order
325+
*/
326+
private function getOrder(string $incrementId): Order
327+
{
328+
return $this->objectManager->create(Order::class)->loadByIncrementId($incrementId);
329+
}
330+
331+
/**
332+
* Assert correct exception message.
333+
*
334+
* @param \Exception $exception
335+
* @param string $expectedMessage
336+
* @return void
337+
*/
338+
private function assertExceptionMessage(\Exception $exception, string $expectedMessage): void
339+
{
340+
$actualMessage = '';
341+
switch (TESTS_WEB_API_ADAPTER) {
342+
case self::ADAPTER_SOAP:
343+
$actualMessage = trim(preg_replace('/\s+/', ' ', $exception->getMessage()));
344+
break;
345+
case self::ADAPTER_REST:
346+
$error = $this->processRestExceptionResult($exception);
347+
$actualMessage = $error['message'];
348+
break;
349+
}
350+
351+
$this->assertEquals($expectedMessage, $actualMessage);
352+
}
248353
}
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+
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
9+
10+
require __DIR__ . '/two_bundle_products_with_separate_shipping.php';
11+
$addressData = include __DIR__ . '/../../../Magento/Sales/_files/address_data.php';
12+
13+
$billingAddress = $objectManager->create(\Magento\Quote\Model\Quote\Address::class, ['data' => $addressData]);
14+
$billingAddress->setAddressType('billing');
15+
16+
$shippingAddress = clone $billingAddress;
17+
$shippingAddress->setId(null)->setAddressType('shipping')->setShippingMethod('flatrate_flatrate');
18+
19+
/** @var \Magento\Quote\Model\Quote\Payment $payment */
20+
$payment = $objectManager->create(\Magento\Quote\Model\Quote\Payment::class);
21+
$payment->setMethod('checkmo');
22+
23+
/** @var \Magento\Catalog\Model\ProductRepository $productRepository */
24+
$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
25+
26+
$bundleProduct = $productRepository->get('bundle-product-separate-shipping-1');
27+
$bundleProduct2 = $productRepository->get('bundle-product-separate-shipping-2');
28+
$selectionProducts = [
29+
$bundleProduct->getId() => [10, 12],
30+
$bundleProduct2->getId() => [11, 13],
31+
];
32+
33+
/** @var $cart \Magento\Checkout\Model\Cart */
34+
$cart = $objectManager->create(\Magento\Checkout\Model\Cart::class);
35+
36+
foreach ([$bundleProduct, $bundleProduct2] as $product) {
37+
38+
/** @var $typeInstance \Magento\Bundle\Model\Product\Type */
39+
$typeInstance = $product->getTypeInstance();
40+
$typeInstance->setStoreFilter($product->getStoreId(), $product);
41+
$optionCollection = $typeInstance->getOptionsCollection($product);
42+
43+
$bundleOptions = [];
44+
$bundleOptionsQty = [];
45+
$optionsData = [];
46+
foreach ($optionCollection as $option) {
47+
/** @var $option \Magento\Bundle\Model\Option */
48+
$selectionsCollection = $typeInstance->getSelectionsCollection([$option->getId()], $product);
49+
$selectionIds = $selectionProducts[$product->getId()];
50+
$selectionsCollection->addIdFilter($selectionIds);
51+
52+
foreach ($selectionIds as $productId) {
53+
$selection = $selectionsCollection->getItemByColumnValue('product_id', $productId);
54+
if ($selection !== null) {
55+
$bundleOptions[$option->getId()] = $selection->getSelectionId();
56+
$optionsData[$option->getId()] = $selection->getProductId();
57+
$bundleOptionsQty[$option->getId()] = 1;
58+
}
59+
}
60+
}
61+
62+
$requestInfo = [
63+
'product' => $product->getId(),
64+
'bundle_option' => $bundleOptions,
65+
'bundle_option_qty' => $bundleOptionsQty,
66+
'qty' => 1,
67+
];
68+
69+
$cart->addProduct($product, $requestInfo);
70+
}
71+
72+
$cart->getQuote()
73+
->setReservedOrderId('order_bundle_separately_shipped')
74+
->setBillingAddress($billingAddress)
75+
->setShippingAddress($shippingAddress)
76+
->setCheckoutMethod(\Magento\Quote\Api\CartManagementInterface::METHOD_GUEST)
77+
->setPayment($payment);
78+
$cart->save();
79+
80+
/** @var \Magento\Quote\Model\QuoteManagement $quoteManager */
81+
$quoteManager = $objectManager->get(\Magento\Quote\Model\QuoteManagement::class);
82+
$orderId = $quoteManager->placeOrder($cart->getQuote()->getId());
83+
84+
$objectManager->removeSharedInstance(\Magento\Checkout\Model\Session::class);
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 __DIR__ . '/../../../Magento/Sales/_files/default_rollback.php';

0 commit comments

Comments
 (0)