Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MC-34298: Introduce separate POST and PUT API for carts/mine/items #31018

Open
wants to merge 6 commits into
base: 2.5-develop
Choose a base branch
from
28 changes: 28 additions & 0 deletions app/code/Magento/Quote/Api/AddCartItemInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Quote\Api;

use Magento\Quote\Api\Data\CartItemInterface;

/**
* Interface AddCartItemInterface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide meaningful description for interface

* @api
*/
interface AddCartItemInterface
{
/**
* Add the specified cart item.
*
* @param \Magento\Quote\Api\Data\CartItemInterface $cartItem The item.
* @return \Magento\Quote\Api\Data\CartItemInterface Item.
* @throws \Magento\Framework\Exception\NoSuchEntityException The specified cart does not exist.
* @throws \Magento\Framework\Exception\CouldNotSaveException The specified item could not be saved to the cart.
* @throws \Magento\Framework\Exception\InputException The specified item or cart is not valid.
*/
public function execute(CartItemInterface $cartItem): CartItemInterface;
}
5 changes: 5 additions & 0 deletions app/code/Magento/Quote/Api/CartItemRepositoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ public function getList($cartId);
* @throws \Magento\Framework\Exception\NoSuchEntityException The specified cart does not exist.
* @throws \Magento\Framework\Exception\CouldNotSaveException The specified item could not be saved to the cart.
* @throws \Magento\Framework\Exception\InputException The specified item or cart is not valid.
*
* @deprecated Post and put endpoint should be separated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why its deprecated? It widely used in code (I mean implementation of this method) not only for API

*
* @see \Magento\Quote\Api\AddCartItemInterface
* @see \Magento\Quote\Api\UpdateCartItemInterface
*/
public function save(\Magento\Quote\Api\Data\CartItemInterface $cartItem);

Expand Down
28 changes: 28 additions & 0 deletions app/code/Magento/Quote/Api/UpdateCartItemInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Quote\Api;

use Magento\Quote\Api\Data\CartItemInterface;

/**
* Interface UpdateCartItemInterface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide meaningful description for interface

* @api
*/
interface UpdateCartItemInterface
{
/**
* Update the specified cart item.
*
* @param \Magento\Quote\Api\Data\CartItemInterface $cartItem The item.
* @return \Magento\Quote\Api\Data\CartItemInterface Item.
* @throws \Magento\Framework\Exception\NoSuchEntityException The specified cart does not exist.
* @throws \Magento\Framework\Exception\CouldNotSaveException The specified item could not be saved to the cart.
* @throws \Magento\Framework\Exception\InputException The specified item or cart is not valid.
*/
public function execute(CartItemInterface $cartItem): CartItemInterface;
}
42 changes: 42 additions & 0 deletions app/code/Magento/Quote/Model/Quote/Item/AddCartItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Quote\Model\Quote\Item;

use Magento\Quote\Api\AddCartItemInterface;
use Magento\Quote\Api\Data\CartItemInterface;

/**
* Add the specified cart item
*/
class AddCartItem implements AddCartItemInterface
{
/**
* @var Repository
*/
private $quoteItemRepository;

/**
* @param Repository $quoteItemRepository
*/
public function __construct(Repository $quoteItemRepository)
{
$this->quoteItemRepository = $quoteItemRepository;
}

/**
* @inheritDoc
*/
public function execute(CartItemInterface $cartItem): CartItemInterface
{
if (isset($cartItem[CartItemInterface::KEY_ITEM_ID])) {
unset($cartItem[CartItemInterface::KEY_ITEM_ID]);
}

return $this->quoteItemRepository->save($cartItem);
}
}
38 changes: 38 additions & 0 deletions app/code/Magento/Quote/Model/Quote/Item/UpdateCartItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Quote\Model\Quote\Item;

use Magento\Quote\Api\Data\CartItemInterface;
use Magento\Quote\Api\UpdateCartItemInterface;

/**
* Update the specified cart item
*/
class UpdateCartItem implements UpdateCartItemInterface
{
/**
* @var Repository
*/
private $quoteItemRepository;

/**
* @param Repository $quoteItemRepository
*/
public function __construct(Repository $quoteItemRepository)
{
$this->quoteItemRepository = $quoteItemRepository;
}

/**
* @inheritDoc
*/
public function execute(CartItemInterface $cartItem): CartItemInterface
{
return $this->quoteItemRepository->save($cartItem);
}
}
2 changes: 2 additions & 0 deletions app/code/Magento/Quote/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
<preference for="Magento\Quote\Api\Data\AddressInterface" type="Magento\Quote\Model\Quote\Address" />
<preference for="Magento\Quote\Api\Data\CartItemInterface" type="Magento\Quote\Model\Quote\Item" />
<preference for="Magento\Quote\Api\Data\CartInterface" type="Magento\Quote\Model\Quote" />
<preference for="Magento\Quote\Api\AddCartItemInterface" type="Magento\Quote\Model\Quote\Item\AddCartItem" />
<preference for="Magento\Quote\Api\UpdateCartItemInterface" type="Magento\Quote\Model\Quote\Item\UpdateCartItem" />
<preference for="Magento\Quote\Api\CartItemRepositoryInterface" type="Magento\Quote\Model\Quote\Item\Repository" />
<preference for="Magento\Quote\Api\CartRepositoryInterface" type="Magento\Quote\Model\QuoteRepository" />
<preference for="Magento\Quote\Api\Data\CartSearchResultsInterface" type="Magento\Quote\Model\CartSearchResults" />
Expand Down
8 changes: 4 additions & 4 deletions app/code/Magento/Quote/etc/webapi.xml
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,13 @@
</resources>
</route>
<route url="/V1/carts/:quoteId/items" method="POST">
<service class="Magento\Quote\Api\CartItemRepositoryInterface" method="save"/>
<service class="Magento\Quote\Api\AddCartItemInterface" method="execute"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about Guest carts? I suppose should be same logic there

<resources>
<resource ref="Magento_Cart::manage" />
</resources>
</route>
<route url="/V1/carts/:cartId/items/:itemId" method="PUT">
<service class="Magento\Quote\Api\CartItemRepositoryInterface" method="save"/>
<service class="Magento\Quote\Api\UpdateCartItemInterface" method="execute"/>
<resources>
<resource ref="Magento_Cart::manage" />
</resources>
Expand Down Expand Up @@ -232,7 +232,7 @@
</data>
</route>
<route url="/V1/carts/mine/items" method="POST">
<service class="Magento\Quote\Api\CartItemRepositoryInterface" method="save"/>
<service class="Magento\Quote\Api\AddCartItemInterface" method="execute"/>
<resources>
<resource ref="self" />
</resources>
Expand All @@ -241,7 +241,7 @@
</data>
</route>
<route url="/V1/carts/mine/items/:itemId" method="PUT">
<service class="Magento\Quote\Api\CartItemRepositoryInterface" method="save"/>
<service class="Magento\Quote\Api\UpdateCartItemInterface" method="execute"/>
<resources>
<resource ref="self" />
</resources>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Bundle\Api;

use Magento\Catalog\Model\Product;
use Magento\Framework\Webapi\Rest\Request;
use Magento\Quote\Model\Quote;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\ObjectManager;
use Magento\TestFramework\TestCase\WebapiAbstract;

/**
* API test for add cart item with bundle product.
*/
class CartItemAddTest extends WebapiAbstract
{
const SERVICE_VERSION = 'V1';
const SERVICE_NAME = 'quoteAddCartItemV1';
const RESOURCE_PATH = '/V1/carts/';

/**
* @var ObjectManager
*/
protected $objectManager;

/**
* @inheritDoc
*/
protected function setUp(): void
{
$this->objectManager = Bootstrap::getObjectManager();
}

/**
* @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php
* @magentoApiDataFixture Magento/Bundle/_files/product.php
*/
public function testAddItem(): void
{
/** @var Product $product */
$product = $this->objectManager->create(Product::class)->load(3);
/** @var Quote $quote */
$quote = $this->objectManager->create(Quote::class)->load(
'test_order_1',
'reserved_order_id'
);

$itemQty = 1;
$bundleProductOptions = $product->getExtensionAttributes()->getBundleProductOptions();
$bundleOptionId = $bundleProductOptions[0]->getId();
$optionSelections = $bundleProductOptions[0]->getProductLinks()[0]->getId();
$buyRequest = [
'bundle_option' => [$bundleOptionId => [$optionSelections]],
'bundle_option_qty' => [$bundleOptionId => 1],
'qty' => $itemQty,
'original_qty' => $itemQty,
];

$productSku = $product->getSku();
$productId = $product->getId();
$cartId = $quote->getId();

$serviceInfo = [
'rest' => [
'resourcePath' => self::RESOURCE_PATH . $cartId . '/items',
'httpMethod' => Request::HTTP_METHOD_POST,
],
'soap' => [
'service' => self::SERVICE_NAME,
'serviceVersion' => self::SERVICE_VERSION,
'operation' => self::SERVICE_NAME . 'Execute',
],
];

$requestData = [
"cartItem" => [
"sku" => $productSku,
"qty" => $itemQty,
"quote_id" => $cartId,
"product_option" => [
"extension_attributes" => [
"bundle_options" => [
[
"option_id" => (int)$bundleOptionId,
"option_qty" => $itemQty,
"option_selections" => [(int)$optionSelections],
],
],
],
],
],
];
$response = $this->_webApiCall($serviceInfo, $requestData);
$this->assertTrue($quote->hasProductId($productId));
$this->assertEquals($buyRequest, $quote->getItemById($response['item_id'])->getBuyRequest()->getData());
}
}