diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemPrices.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemPrices.php index abbd81475e77d..804d8120e6e06 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemPrices.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemPrices.php @@ -64,24 +64,35 @@ public function resolve(Field $field, $context, ResolveInfo $info, ?array $value } /** @var Item $cartItem */ $cartItem = $value['model']; - if (!$this->totals) { + + // Collect totals only if discount, original item price and original rowtotal is there in the request + // avoid retrieve totals with the below keys if its not absolutely required + // except discounts can be removed if original_item_price and original_row_total is saved in db + if (!$this->totals && !empty(array_intersect( + [ + 'discounts', 'original_item_price', 'original_row_total', + 'catalog_discount', 'row_catalog_discount' + ], + array_keys($info->getFieldSelection(1)) + )) + ) { // The totals calculation is based on quote address. // But the totals should be calculated even if no address is set $this->totals = $this->totalsCollector->collectQuoteTotals($cartItem->getQuote()); } + $currencyCode = $cartItem->getQuote()->getQuoteCurrencyCode(); /** calculate bundle product discount */ + $discountAmount = 0; if ($cartItem->getProductType() == 'bundle') { - $discounts = $cartItem->getExtensionAttributes()->getDiscounts() ?? []; - $discountAmount = 0; - foreach ($discounts as $discount) { - $discountAmount += $discount->getDiscountData()->getAmount(); + foreach ($cartItem->getChildren() as $childItem) { + $discountAmount += $childItem->getDiscountAmount(); } - } else { - $discountAmount = $cartItem->getDiscountAmount(); } + $discountAmount += $cartItem->getDiscountAmount(); + return [ 'model' => $cartItem, 'price' => [ diff --git a/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Resolver/CartItemPricesTest.php b/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Resolver/CartItemPricesTest.php new file mode 100644 index 0000000000000..c0bd9409f1393 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Resolver/CartItemPricesTest.php @@ -0,0 +1,215 @@ +totalsCollectorMock = $this->createMock(TotalsCollector::class); + $this->getDiscountsMock = $this->createMock(GetDiscounts::class); + $this->priceCurrencyMock = $this->createMock(PriceCurrencyInterface::class); + $this->getOptionsRegularPriceMock = $this->createMock(GetOptionsRegularPrice::class); + $this->productMock = $this->getMockBuilder(Product::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCustomOption']) + ->getMock(); + $this->fieldMock = $this->createMock(Field::class); + $this->resolveInfoMock = $this->createMock(ResolveInfo::class); + $this->contextMock = $this->createMock(Context::class); + $this->quoteMock = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->addMethods(['getQuoteCurrencyCode']) + ->getMock(); + $this->itemMock = $this->getMockBuilder(Item::class) + ->addMethods([ + 'getPriceInclTax', 'getRowTotal', + 'getRowTotalInclTax', 'getDiscountAmount' + ]) + ->onlyMethods([ + 'getCalculationPrice', 'getQuote', 'getExtensionAttributes', + 'getProduct', 'getOriginalPrice' + ]) + ->disableOriginalConstructor() + ->getMock(); + $this->itemExtensionMock = $this->getMockBuilder( + ExtensionAttributesInterface::class + )->addMethods(['getDiscounts'])->getMockForAbstractClass(); + + $this->cartItemPrices = new CartItemPrices( + $this->totalsCollectorMock, + $this->getDiscountsMock, + $this->priceCurrencyMock, + $this->getOptionsRegularPriceMock + ); + } + + public function testResolve(): void + { + $this->valueMock = ['model' => $this->itemMock]; + + $this->resolveInfoMock->expects($this->once()) + ->method('getFieldSelection') + ->with(1) + ->willReturn([]); + + $this->itemMock + ->expects($this->exactly(2)) + ->method('getQuote') + ->willReturn($this->quoteMock); + + $this->quoteMock + ->expects($this->once()) + ->method('getQuoteCurrencyCode') + ->willReturn('USD'); + + $this->itemMock + ->expects($this->once()) + ->method('getDiscountAmount'); + + $this->itemMock + ->expects($this->once()) + ->method('getCalculationPrice'); + + $this->itemMock + ->expects($this->once()) + ->method('getPriceInclTax'); + + $this->itemMock + ->expects($this->any()) + ->method('getOriginalPrice') + ->willReturn(0); + + $this->itemMock + ->expects($this->once()) + ->method('getRowTotal'); + + $this->itemMock + ->expects($this->once()) + ->method('getRowTotalInclTax'); + + $this->itemMock + ->expects($this->once()) + ->method('getExtensionAttributes') + ->willReturn($this->itemExtensionMock); + + $this->itemMock + ->expects($this->any()) + ->method('getProduct') + ->willReturn($this->productMock); + + $this->productMock + ->expects($this->exactly(2)) + ->method('getCustomOption') + ->willReturn(null); + + $this->itemExtensionMock + ->expects($this->once()) + ->method('getDiscounts') + ->willReturn([]); + + $this->getDiscountsMock + ->expects($this->once()) + ->method('execute') + ->with($this->quoteMock, []); + + $this->cartItemPrices->resolve($this->fieldMock, $this->contextMock, $this->resolveInfoMock, $this->valueMock); + } + + public function testResolveWithoutModelInValueParameter(): void + { + $this->expectException(LocalizedException::class); + $this->expectExceptionMessage('"model" value should be specified'); + $this->cartItemPrices->resolve($this->fieldMock, $this->contextMock, $this->resolveInfoMock, $this->valueMock); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetMaskedQuoteIdByReservedOrderId.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetMaskedQuoteIdByReservedOrderId.php index 49dfafca5c14d..bf6dc74826010 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetMaskedQuoteIdByReservedOrderId.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetMaskedQuoteIdByReservedOrderId.php @@ -1,7 +1,7 @@ quoteFactory->create(); $quote->setSharedStoreIds(['*']); $this->quoteResource->load($quote, $reservedOrderId, 'reserved_order_id'); + // If dataprovider is used, we need to collect totals manually and save quote + if ($forceCollectTotal) { + $this->quoteResource->save($quote->collectTotals()); + } + return $this->quoteIdToMaskedId->execute((int)$quote->getId()); } } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/CartItemPricesWithFPTTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/CartItemPricesWithFPTTest.php index 99bd59eb34181..78e3270be4057 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/CartItemPricesWithFPTTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/CartItemPricesWithFPTTest.php @@ -1,7 +1,7 @@ writeConfig($taxSettings); - $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + // Second argument true is to ensure collectTotals and save after every quote update + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote', true); $query = $this->getQuery($maskedQuoteId); $result = $this->graphQlQuery($query); $this->assertArrayNotHasKey('errors', $result);