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

508 lines
16 KiB
PHP
Executable File

<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Sales\Service\V1;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\Product\Type;
use Magento\Framework\ObjectManagerInterface;
use Magento\Sales\Api\Data\OrderItemInterface;
use Magento\Sales\Api\ShipmentRepositoryInterface;
use Magento\Sales\Model\Order;
/**
* API test for creation of Shipment for certain Order.
*/
class ShipOrderTest extends \Magento\TestFramework\TestCase\WebapiAbstract
{
public const SERVICE_READ_NAME = 'salesShipOrderV1';
public const SERVICE_VERSION = 'V1';
/**
* @var ObjectManagerInterface
*/
private $objectManager;
/**
* @var ShipmentRepositoryInterface
*/
private $shipmentRepository;
/**
* @var ProductRepositoryInterface
*/
private $productRepository;
/**
* @inheritdoc
*/
protected function setUp(): void
{
$this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
$this->shipmentRepository = $this->objectManager->get(ShipmentRepositoryInterface::class);
$this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class);
}
/**
* @magentoApiDataFixture Magento/Sales/_files/order_configurable_product.php
*/
public function testConfigurableShipOrder()
{
$this->markTestSkipped('https://github.com/magento-engcom/msi/issues/1335');
$productsQuantity = 1;
/** @var Order $existingOrder */
$existingOrder = $this->getOrder('100000001');
$requestData = [
'orderId' => $existingOrder->getId(),
];
$shipmentId = (int)$this->_webApiCall($this->getServiceInfo($existingOrder), $requestData);
$this->assertNotEmpty($shipmentId);
$shipment = null;
try {
$shipment = $this->shipmentRepository->get($shipmentId);
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
$this->fail('Failed asserting that Shipment was created');
}
$orderedQty = 0;
/** @var \Magento\Sales\Model\Order\Item $item */
foreach ($existingOrder->getItems() as $item) {
if ($item->isDummy(true)) {
continue;
}
$orderedQty += $item->getQtyOrdered();
}
$this->assertEquals(
(int)$shipment->getTotalQty(),
(int)$orderedQty,
'Failed asserting that quantity of ordered and shipped items is equal'
);
$this->assertEquals(
$productsQuantity,
count($shipment->getItems()),
'Failed asserting that quantity of products and sales shipment items is equal'
);
}
/**
* Tests that order doesn't change a status from custom to the default after shipment creation.
*
* @magentoApiDataFixture Magento/Sales/_files/order_status.php
*/
public function testShipOrderStatusPreserve()
{
$incrementId = '100000001';
$orderStatus = 'example';
/** @var Order $existingOrder */
$order = $this->getOrder($incrementId);
$this->assertEquals($orderStatus, $order->getStatus());
$requestData = [
'orderId' => $order->getId(),
];
/** @var OrderItemInterface $item */
foreach ($order->getAllItems() as $item) {
$requestData['items'][] = [
'order_item_id' => $item->getItemId(),
'qty' => $item->getQtyOrdered(),
];
}
$shipmentId = $this->_webApiCall($this->getServiceInfo($order), $requestData);
$this->assertNotEmpty($shipmentId);
$actualOrder = $this->getOrder($order->getIncrementId());
$this->assertEquals(
$order->getStatus(),
$actualOrder->getStatus(),
'Failed asserting that Order status wasn\'t changed'
);
}
/**
* @magentoApiDataFixture Magento/Sales/_files/order_new.php
*/
public function testShipOrder()
{
/** @var Order $existingOrder */
$existingOrder = $this->getOrder('100000001');
$requestData = [
'orderId' => $existingOrder->getId(),
'items' => [],
'comment' => [
'comment' => 'Test Comment',
'is_visible_on_front' => 1,
],
'tracks' => [
[
'track_number' => 'TEST_TRACK_0001',
'title' => 'Simple shipment track',
'carrier_code' => 'UPS',
],
],
];
/** @var OrderItemInterface $item */
foreach ($existingOrder->getAllItems() as $item) {
$requestData['items'][] = [
'order_item_id' => $item->getItemId(),
'qty' => $item->getQtyOrdered(),
];
}
$result = $this->_webApiCall($this->getServiceInfo($existingOrder), $requestData);
$this->assertNotEmpty($result);
try {
$this->shipmentRepository->get($result);
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
$this->fail('Failed asserting that Shipment was created');
}
/** @var Order $updatedOrder */
$updatedOrder = $this->getOrder('100000001');
$this->assertNotEquals(
$existingOrder->getStatus(),
$updatedOrder->getStatus(),
'Failed asserting that Order status was changed'
);
}
/**
* Tests that not providing a tracking number produces the correct error. See MAGETWO-95429
* @codingStandardsIgnoreStart
* @codingStandardsIgnoreEnd
* @magentoApiDataFixture Magento/Sales/_files/order_new.php
*/
public function testShipOrderWithoutTrackingNumberReturnsError()
{
$this->expectException(\Exception::class);
$this->expectExceptionMessageMatches(
'/Shipment Document Validation Error\\(s\\):(?:\\n|\\\\n)Please enter a tracking number./'
);
$this->_markTestAsRestOnly('SOAP requires an tracking number to be provided so this case is not possible.');
/** @var Order $existingOrder */
$existingOrder = $this->getOrder('100000001');
$requestData = [
'orderId' => $existingOrder->getId(),
'comment' => [
'comment' => 'Test Comment',
'is_visible_on_front' => 1,
],
'tracks' => [
[
'title' => 'Simple shipment track',
'carrier_code' => 'UPS',
],
],
];
$this->_webApiCall($this->getServiceInfo($existingOrder), $requestData);
}
/**
* @magentoApiDataFixture Magento/Bundle/_files/order_with_bundle_shipped_separately.php
*/
public function testPartialShipOrderWithBundleShippedSeparately()
{
$existingOrder = $this->getOrder('100000001');
$requestData = [
'orderId' => $existingOrder->getId(),
'items' => [],
'comment' => [
'comment' => 'Test Comment',
'is_visible_on_front' => 1,
],
'tracks' => [
[
'track_number' => 'TEST_TRACK_0001',
'title' => 'Simple shipment track',
'carrier_code' => 'UPS',
],
],
];
$shippedItemId = null;
foreach ($existingOrder->getAllItems() as $item) {
if ($item->getProductType() == 'simple') {
$requestData['items'][] = [
'order_item_id' => $item->getItemId(),
'qty' => $item->getQtyOrdered(),
];
$shippedItemId = $item->getItemId();
break;
}
}
$shipmentId = $this->_webApiCall($this->getServiceInfo($existingOrder), $requestData);
$this->assertNotEmpty($shipmentId);
$shipment = null;
try {
$shipment = $this->shipmentRepository->get($shipmentId);
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
$this->fail('Failed asserting that Shipment was created');
}
$this->assertEquals(1, $shipment->getTotalQty());
/** @var Order $existingOrder */
$existingOrder = $this->getOrder('100000001');
foreach ($existingOrder->getAllItems() as $item) {
if ($item->getItemId() == $shippedItemId) {
$this->assertEquals(1, $item->getQtyShipped());
continue;
} elseif ($item->getParentItem()) {
$this->assertEquals(0, $item->getQtyShipped());
}
}
}
/**
* @magentoApiDataFixture Magento/Bundle/_files/order_with_2_bundles_shipping_separately.php
*/
public function testPartialShipOrderWithTwoBundleShippedSeparatelyContainsSameSimple()
{
$order = $this->getOrder('order_bundle_separately_shipped');
$requestData = [
'orderId' => $order->getId(),
'items' => [],
'comment' => [
'comment' => 'Test Comment',
'is_visible_on_front' => 1,
],
'tracks' => [],
];
$shippedItemId = null;
$parentItemId = null;
foreach ($order->getAllItems() as $item) {
if ($item->getSku() === 'simple1') {
$requestData['items'][] = [
'order_item_id' => $item->getItemId(),
'qty' => $item->getQtyOrdered(),
];
$shippedItemId = $item->getItemId();
$parentItemId = $item->getParentItemId();
break;
}
}
$shipmentId = $this->_webApiCall($this->getServiceInfo($order), $requestData);
$this->assertNotEmpty($shipmentId);
$shipment = null;
try {
$shipment = $this->shipmentRepository->get($shipmentId);
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
$this->fail('Failed asserting that Shipment was created');
}
$this->assertEquals(1, $shipment->getTotalQty());
$order = $this->getOrder('order_bundle_separately_shipped');
foreach ($order->getAllItems() as $item) {
if (in_array($item->getItemId(), [$shippedItemId, $parentItemId])) {
$this->assertEquals(1, $item->getQtyShipped());
continue;
}
$this->assertEquals(0, $item->getQtyShipped());
}
try {
$this->_webApiCall($this->getServiceInfo($order), $requestData);
$this->fail('Expected exception was not raised');
} catch (\Exception $exception) {
$this->assertExceptionMessage(
$exception,
'Shipment Document Validation Error(s): You can\'t create a shipment without products.'
);
}
}
/**
* @magentoApiDataFixture Magento/Bundle/_files/order_with_bundle_shipped_separately.php
*/
public function testValidationShipTogetherWithBundleShippedSeparate()
{
$order = $this->getOrder('100000001');
$requestData = [
'orderId' => $order->getId(),
'items' => [],
'comment' => [
'comment' => 'Test Comment',
'is_visible_on_front' => 1,
],
'tracks' => [],
];
foreach ($order->getAllItems() as $item) {
if ($item->getProductType() === Type::TYPE_BUNDLE) {
$requestData['items'][] = [
'order_item_id' => $item->getItemId(),
'qty' => $item->getQtyOrdered(),
];
break;
}
}
try {
$this->_webApiCall($this->getServiceInfo($order), $requestData);
$this->fail('Expected exception was not raised');
} catch (\Exception $exception) {
$this->assertExceptionMessage(
$exception,
'Shipment Document Validation Error(s): '
. 'You can\'t create a shipment without products. '
. 'Cannot create shipment as bundle product "bundle-product" has shipment type "Separately". '
. 'Bundle product options should be shipped instead.'
);
}
foreach ($order->getAllItems() as $item) {
if ($item->getProductType() === Type::TYPE_SIMPLE) {
$requestData['items'] = [
[
'order_item_id' => $item->getItemId(),
'qty' => $item->getQtyOrdered(),
],
];
break;
}
}
$this->_webApiCall($this->getServiceInfo($order), $requestData);
}
/**
* @magentoApiDataFixture Magento/Bundle/_files/order_with_bundle_shipped_together.php
*/
public function testValidationShipTogetherWithBundleShippedTogether()
{
$order = $this->getOrder('100000001');
$requestData = [
'orderId' => $order->getId(),
'items' => [],
'comment' => [
'comment' => 'Test Comment',
'is_visible_on_front' => 1,
],
'tracks' => [],
];
foreach ($order->getAllItems() as $item) {
if ($item->getProductType() === Type::TYPE_SIMPLE) {
$requestData['items'][] = [
'order_item_id' => $item->getItemId(),
'qty' => $item->getQtyOrdered(),
];
break;
}
}
try {
$this->_webApiCall($this->getServiceInfo($order), $requestData);
$this->fail('Expected exception was not raised');
} catch (\Exception $exception) {
$this->assertExceptionMessage(
$exception,
'Shipment Document Validation Error(s): '
. 'You can\'t create a shipment without products. '
. 'Cannot create shipment as bundle product "bundle-product" has shipment type "Together". '
. 'Bundle product itself should be shipped instead.'
);
}
foreach ($order->getAllItems() as $item) {
if ($item->getProductType() === Type::TYPE_BUNDLE) {
$requestData['items'] = [
[
'order_item_id' => $item->getItemId(),
'qty' => $item->getQtyOrdered(),
],
];
break;
}
}
$this->_webApiCall($this->getServiceInfo($order), $requestData);
}
/**
* @param Order $order
* @return array
*/
private function getServiceInfo(Order $order): array
{
$serviceInfo = [
'rest' => [
'resourcePath' => '/V1/order/' . $order->getId() . '/ship',
'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
],
'soap' => [
'service' => self::SERVICE_READ_NAME,
'serviceVersion' => self::SERVICE_VERSION,
'operation' => self::SERVICE_READ_NAME . 'execute',
],
];
return $serviceInfo;
}
/**
* Returns order by increment id.
*
* @param string $incrementId
* @return Order
*/
private function getOrder(string $incrementId): Order
{
return $this->objectManager->create(Order::class)->loadByIncrementId($incrementId);
}
/**
* Assert correct exception message.
*
* @param \Exception $exception
* @param string $expectedMessage
* @return void
*/
private function assertExceptionMessage(\Exception $exception, string $expectedMessage): void
{
$actualMessage = '';
switch (TESTS_WEB_API_ADAPTER) {
case self::ADAPTER_SOAP:
$actualMessage = trim(preg_replace('/\s+/', ' ', $exception->getMessage()));
break;
case self::ADAPTER_REST:
$error = $this->processRestExceptionResult($exception);
$actualMessage = $error['message'];
break;
}
$this->assertEquals($expectedMessage, $actualMessage);
}
}