From 9c09aac45829b2631c513b4251e7f1a9f5f11213 Mon Sep 17 00:00:00 2001 From: eliseacornejo Date: Tue, 21 May 2024 14:48:26 +0200 Subject: [PATCH] LYNX-411: add custom options price to origin_row_total (#247) --- .../Model/Resolver/CartItemPrices.php | 25 +- ...roductsWithCustomOptionsCartPricesTest.php | 387 ++++++++++++++++++ 2 files changed, 411 insertions(+), 1 deletion(-) create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/ProductsWithCustomOptionsCartPricesTest.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemPrices.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemPrices.php index 9d5a83c31ce10..3b834ccb25c49 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemPrices.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemPrices.php @@ -118,6 +118,29 @@ private function getOriginalRowTotal(Item $cartItem): float { $qty = $cartItem->getTotalQty(); // Round unit price before multiplying to prevent losing 1 cent on subtotal - return $this->priceCurrency->round($cartItem->getOriginalPrice()) * $qty; + return $this->priceCurrency->round($cartItem->getOriginalPrice() + $this->getOptionsPrice($cartItem)) * $qty; + } + + /** + * Get the product custom options price + * + * @param Item $cartItem + * @return float + */ + private function getOptionsPrice(Item $cartItem): float + { + $price = 0.0; + $optionIds = $cartItem->getProduct()->getCustomOption('option_ids'); + if (!$optionIds) { + return $price; + } + foreach (explode(',', $optionIds->getValue() ?? '') as $optionId) { + $option = $cartItem->getProduct()->getOptionById($optionId); + if ($option) { + $price += $option->getRegularPrice(); + } + } + + return $price; } } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/ProductsWithCustomOptionsCartPricesTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/ProductsWithCustomOptionsCartPricesTest.php new file mode 100644 index 0000000000000..4904a2dee9693 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/ProductsWithCustomOptionsCartPricesTest.php @@ -0,0 +1,387 @@ +objectManager = Bootstrap::getObjectManager(); + $this->quoteIdToMaskedQuoteIdInterface = $this->objectManager->get(QuoteIdToMaskedQuoteIdInterface::class); + $this->fixtures = $this->objectManager->get(DataFixtureStorageManager::class)->getStorage(); + $this->uidEncoder = $this->objectManager->create(Uid::class); + } + + #[ + DataFixture(GuestCart::class, as: 'quote'), + DataFixture( + Product::class, + [ + 'sku' => 'simple1', + 'price' => 30, + 'special_price' => 15, + 'options' => [ + [ + 'title' => 'option1', + 'type' => ProductCustomOptionInterface::OPTION_TYPE_FIELD, + 'price' => 10 + ], + [ + 'title' => 'option2', + 'type' => ProductCustomOptionInterface::OPTION_TYPE_FIELD, + 'price' => 40, + 'is_require' => false + ], + [ + 'title' => 'option3', + 'type' => ProductCustomOptionInterface::OPTION_TYPE_FIELD, + 'price' => 0 + ], + ] + ], + 'product' + ) + ] + public function testProductsWithOneCustomOptionEnteredWithFixedPrice() + { + $cart = $this->fixtures->get('quote'); + $maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute((int) $cart->getId()); + $product = $this->fixtures->get('product'); + $sku = $product->getSku(); + + $options = $product->getOptions(); + $optionUid = $this->uidEncoder->encode( + 'custom-option' . '/' . $options[0]->getData()['option_id'] + ); + $optionUid2 = $this->uidEncoder->encode( + 'custom-option' . '/' . $options[2]->getData()['option_id'] + ); + $this->graphQlMutation( + $this->addProductWithOptionMutation($maskedQuoteId, 2, $sku, $optionUid, $optionUid2) + ); + + $query = $this->getCartQuery($maskedQuoteId); + $response = $this->graphQlQuery($query); + + $expectedResponse = [ + "cart" => [ + "itemsV2" => [ + "items" => [ + 0 => [ + "prices" => [ + "price" => [ + "value" => 25, + "currency" => "USD" + ], + "row_total" => [ + "value" => 50, + "currency" => "USD" + ], + "original_row_total" => [ + "value" => 80, + "currency" => "USD" + ] + ] + ] + ] + ] + ] + ]; + + $this->assertEquals($expectedResponse, $response); + } + + #[ + DataFixture(GuestCart::class, as: 'quote'), + DataFixture( + Product::class, + [ + 'sku' => 'simple1', + 'price' => 30, + 'special_price' => 15, + 'options' => [ + [ + 'title' => 'option1', + 'type' => ProductCustomOptionInterface::OPTION_TYPE_FIELD, + 'price_type' => ProductPriceOptionsInterface::VALUE_PERCENT, + 'price' => 10, + ], + [ + 'title' => 'option2', + 'type' => ProductCustomOptionInterface::OPTION_TYPE_FIELD, + 'price' => 40, + 'is_require' => false + ], + [ + 'title' => 'option3', + 'type' => ProductCustomOptionInterface::OPTION_TYPE_FIELD, + 'price' => 0 + ], + ] + ], + 'product' + ) + ] + public function testProductsWithOneCustomOptionEnteredWithPercentPrice() + { + $cart = $this->fixtures->get('quote'); + $maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute((int) $cart->getId()); + $product = $this->fixtures->get('product'); + $sku = $product->getSku(); + + $options = $product->getOptions(); + $optionUid = $this->uidEncoder->encode( + 'custom-option' . '/' . $options[0]->getData()['option_id'] + ); + $optionUid2 = $this->uidEncoder->encode( + 'custom-option' . '/' . $options[2]->getData()['option_id'] + ); + + $this->graphQlMutation( + $this->addProductWithOptionMutation($maskedQuoteId, 2, $sku, $optionUid, $optionUid2) + ); + + $query = $this->getCartQuery($maskedQuoteId); + $response = $this->graphQlQuery($query); + + $expectedResponse = [ + "cart" => [ + "itemsV2" => [ + "items" => [ + 0 => [ + "prices" => [ + "price" => [ + "value" => 16.5, + "currency" => "USD" + ], + "row_total" => [ + "value" => 33, + "currency" => "USD" + ], + "original_row_total" => [ + "value" => 66, + "currency" => "USD" + ] + ] + ] + ] + ] + ] + ]; + + $this->assertEquals($expectedResponse, $response); + } + + #[ + DataFixture(GuestCart::class, as: 'quote'), + DataFixture( + Product::class, + [ + 'sku' => 'simple1', + 'price' => 30, + 'special_price' => 15, + 'options' => [ + [ + 'title' => 'option1', + 'type' => ProductCustomOptionInterface::OPTION_TYPE_FIELD, + 'price_type' => ProductPriceOptionsInterface::VALUE_PERCENT, + 'price' => 10, + ], + [ + 'title' => 'option2', + 'type' => ProductCustomOptionInterface::OPTION_TYPE_FIELD, + 'is_require' => false, + 'price' => 40.0 + ], + [ + 'title' => 'option3', + 'type' => ProductCustomOptionInterface::OPTION_TYPE_FIELD, + 'price' => 50.0 + ] + ] + ], + 'product' + ) + ] + public function testProductsWithOneCustomOptionEnteredWithPercentPriceAndOneWithFixedPrice() + { + $cart = $this->fixtures->get('quote'); + $maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute((int) $cart->getId()); + $product = $this->fixtures->get('product'); + $sku = $product->getSku(); + + $options = $product->getOptions(); + $optionUid = $this->uidEncoder->encode( + 'custom-option' . '/' . $options[0]->getData()['option_id'] + ); + $optionUid2 = $this->uidEncoder->encode( + 'custom-option' . '/' . $options[2]->getData()['option_id'] + ); + + $this->graphQlMutation( + $this->addProductWithOptionMutation($maskedQuoteId, 2, $sku, $optionUid, $optionUid2) + ); + + $query = $this->getCartQuery($maskedQuoteId); + $response = $this->graphQlQuery($query); + + $expectedResponse = [ + "cart" => [ + "itemsV2" => [ + "items" => [ + 0 => [ + "prices" => [ + "price" => [ + "value" => 66.5, + "currency" => "USD" + ], + "row_total" => [ + "value" => 133, + "currency" => "USD" + ], + "original_row_total" => [ + "value" => 166, + "currency" => "USD" + ] + ] + ] + ] + ] + ] + ]; + + $this->assertEquals($expectedResponse, $response); + } + + /** + * Create cart query with prices data + * + * @param string $maskedQuoteId + * @return string + */ + private function getCartQuery(string $maskedQuoteId): string + { + return <<