diff --git a/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/UpdateQuoteItemPrice.php b/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/UpdateQuoteItemPrice.php new file mode 100644 index 0000000000000..8cb2fd48f427e --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/UpdateQuoteItemPrice.php @@ -0,0 +1,98 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * @inheritdoc + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->beginTransaction(); + try { + $this->applyPatch(); + $this->moduleDataSetup->getConnection()->commit(); + } catch (\Exception $e) { + $this->moduleDataSetup->getConnection()->rollBack(); + throw $e; + } + } + + /** + * Update 'price' value for quote items without price of configurable products subproducts. + * + * @return void + */ + private function applyPatch(): void + { + $connection = $this->moduleDataSetup->getConnection(); + $quoteItemTable = $this->moduleDataSetup->getTable('quote_item'); + $select = $connection->select(); + $select->joinLeft( + ['qi2' => $quoteItemTable], + 'qi1.parent_item_id = qi2.item_id', + ['price'] + )->where( + 'qi1.price = 0' + . ' AND qi1.parent_item_id IS NOT NULL' + . ' AND qi2.product_type = "' . Configurable::TYPE_CODE . '"' + ); + $updateQuoteItem = $this->moduleDataSetup->getConnection()->updateFromSelect( + $select, + ['qi1' => $quoteItemTable] + ); + $this->moduleDataSetup->getConnection()->query($updateQuoteItem); + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return []; + } + + /** + * @inheritdoc + */ + public static function getVersion() + { + return '2.2.2'; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Quote/Model/Quote/Item/Processor.php b/app/code/Magento/Quote/Model/Quote/Item/Processor.php index 2577008ecbae3..a69f5c27be11b 100644 --- a/app/code/Magento/Quote/Model/Quote/Item/Processor.php +++ b/app/code/Magento/Quote/Model/Quote/Item/Processor.php @@ -53,8 +53,8 @@ public function __construct( /** * Initialize quote item object * - * @param DataObject $request * @param Product $product + * @param DataObject $request * * @return Item */ @@ -95,7 +95,7 @@ public function prepare(Item $item, DataObject $request, Product $candidate): vo $item->setData(CartItemInterface::KEY_QTY, 0); } $item->addQty($candidate->getCartQty()); - + $item->setPrice($candidate->getFinalPrice()); $customPrice = $request->getCustomPrice(); if (!empty($customPrice)) { $item->setCustomPrice($customPrice); diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/ProcessorTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/ProcessorTest.php index a56de35b70f75..d253da8683a7b 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/ProcessorTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/ProcessorTest.php @@ -76,7 +76,8 @@ protected function setUp() 'addQty', 'setCustomPrice', 'setOriginalCustomPrice', - 'setData' + 'setData', + 'setprice' ]); $this->quoteItemFactoryMock->expects($this->any()) ->method('create') @@ -98,7 +99,14 @@ protected function setUp() $this->productMock = $this->createPartialMock( \Magento\Catalog\Model\Product::class, - ['getCustomOptions', '__wakeup', 'getParentProductId', 'getCartQty', 'getStickWithinParent'] + [ + 'getCustomOptions', + '__wakeup', + 'getParentProductId', + 'getCartQty', + 'getStickWithinParent', + 'getFinalPrice' + ] ); $this->objectMock = $this->createPartialMock( \Magento\Framework\DataObject::class, @@ -239,13 +247,16 @@ public function testPrepare() $customPrice = 400000000; $itemId = 1; $requestItemId = 1; - + $finalPrice = 1000000000; $this->productMock->expects($this->any()) ->method('getCartQty') ->will($this->returnValue($qty)); $this->productMock->expects($this->any()) ->method('getStickWithinParent') ->will($this->returnValue(false)); + $this->productMock->expects($this->once()) + ->method('getFinalPrice') + ->will($this->returnValue($finalPrice)); $this->itemMock->expects($this->once()) ->method('addQty') @@ -255,6 +266,9 @@ public function testPrepare() ->will($this->returnValue($itemId)); $this->itemMock->expects($this->never()) ->method('setData'); + $this->itemMock->expects($this->once()) + ->method('setPrice') + ->will($this->returnValue($this->itemMock)); $this->objectMock->expects($this->any()) ->method('getCustomPrice') @@ -282,6 +296,7 @@ public function testPrepareWithResetCountAndStick() $customPrice = 400000000; $itemId = 1; $requestItemId = 1; + $finalPrice = 1000000000; $this->productMock->expects($this->any()) ->method('getCartQty') @@ -289,6 +304,9 @@ public function testPrepareWithResetCountAndStick() $this->productMock->expects($this->any()) ->method('getStickWithinParent') ->will($this->returnValue(true)); + $this->productMock->expects($this->once()) + ->method('getFinalPrice') + ->will($this->returnValue($finalPrice)); $this->itemMock->expects($this->once()) ->method('addQty') @@ -298,6 +316,9 @@ public function testPrepareWithResetCountAndStick() ->will($this->returnValue($itemId)); $this->itemMock->expects($this->never()) ->method('setData'); + $this->itemMock->expects($this->once()) + ->method('setPrice') + ->will($this->returnValue($this->itemMock)); $this->objectMock->expects($this->any()) ->method('getCustomPrice') @@ -325,6 +346,7 @@ public function testPrepareWithResetCountAndNotStickAndOtherItemId() $customPrice = 400000000; $itemId = 1; $requestItemId = 2; + $finalPrice = 1000000000; $this->productMock->expects($this->any()) ->method('getCartQty') @@ -332,6 +354,9 @@ public function testPrepareWithResetCountAndNotStickAndOtherItemId() $this->productMock->expects($this->any()) ->method('getStickWithinParent') ->will($this->returnValue(false)); + $this->productMock->expects($this->once()) + ->method('getFinalPrice') + ->will($this->returnValue($finalPrice)); $this->itemMock->expects($this->once()) ->method('addQty') @@ -341,6 +366,9 @@ public function testPrepareWithResetCountAndNotStickAndOtherItemId() ->will($this->returnValue($itemId)); $this->itemMock->expects($this->never()) ->method('setData'); + $this->itemMock->expects($this->once()) + ->method('setPrice') + ->will($this->returnValue($this->itemMock)); $this->objectMock->expects($this->any()) ->method('getCustomPrice') @@ -368,6 +396,7 @@ public function testPrepareWithResetCountAndNotStickAndSameItemId() $customPrice = 400000000; $itemId = 1; $requestItemId = 1; + $finalPrice = 1000000000; $this->objectMock->expects($this->any()) ->method('getResetCount') @@ -386,10 +415,16 @@ public function testPrepareWithResetCountAndNotStickAndSameItemId() $this->productMock->expects($this->any()) ->method('getStickWithinParent') ->will($this->returnValue(false)); + $this->productMock->expects($this->once()) + ->method('getFinalPrice') + ->will($this->returnValue($finalPrice)); $this->itemMock->expects($this->once()) ->method('addQty') ->with($qty); + $this->itemMock->expects($this->once()) + ->method('setPrice') + ->will($this->returnValue($this->itemMock)); $this->objectMock->expects($this->any()) ->method('getCustomPrice') diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CartItemRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CartItemRepositoryTest.php index 18f57515c4d18..0bd1ee109be0a 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CartItemRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CartItemRepositoryTest.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Catalog\Api; use Magento\TestFramework\TestCase\WebapiAbstract; @@ -58,11 +59,12 @@ public function testAddProductToCartWithCustomOptions() $item = $quote->getAllItems()[0]; $this->assertEquals( [ - 'item_id' => $item->getItemId(), + 'item_id' => (int) $item->getItemId(), 'sku' => $item->getSku(), 'qty' => $item->getQty(), 'name' => $item->getName(), - + 'price' => $item->getPrice(), + 'product_type' => $item->getProductType(), 'quote_id' => $item->getQuoteId(), 'product_option' => [ @@ -70,6 +72,7 @@ public function testAddProductToCartWithCustomOptions() 'custom_options' => $this->getOptions(), ], ], + 'price' => $item->getPrice(), ], $response ); @@ -80,7 +83,7 @@ public function testAddProductToCartWithCustomOptions() */ public function testGetList() { - /** @var \Magento\Quote\Model\Quote $quote */ + /** @var \Magento\Quote\Model\Quote $quote */ $quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class); $quote->load('test_order_1', 'reserved_order_id'); $cartId = $quote->getId();