diff --git a/app/code/Magento/Bundle/Model/Product/OriginalPrice.php b/app/code/Magento/Bundle/Model/Product/OriginalPrice.php
new file mode 100644
index 0000000000000..ca3a616f3ee06
--- /dev/null
+++ b/app/code/Magento/Bundle/Model/Product/OriginalPrice.php
@@ -0,0 +1,133 @@
+hasCustomOptions()) {
+ return $price;
+ }
+
+ $selectionIds = $this->getBundleSelectionIds($product);
+
+ if (empty($selectionIds)) {
+ return $price;
+ }
+
+ $selections = $product->getTypeInstance()->getSelectionsByIds($selectionIds, $product);
+ foreach ($selections->getItems() as $selection) {
+ if (!$selection->isSalable()) {
+ continue;
+ }
+
+ $selectionQty = $product->getCustomOption('selection_qty_' . $selection->getSelectionId());
+ if ($selectionQty) {
+ $price += $this->getSelectionOriginalTotalPrice(
+ $product,
+ $selection,
+ (float) $selectionQty->getValue()
+ );
+ }
+ }
+
+ return $price;
+ }
+
+ /**
+ * Calculate total original price of selection
+ *
+ * @param Product $bundleProduct
+ * @param Product $selectionProduct
+ * @param float $selectionQty
+ *
+ * @return float
+ */
+ private function getSelectionOriginalTotalPrice(
+ Product $bundleProduct,
+ Product $selectionProduct,
+ float $selectionQty
+ ): float {
+ $price = $this->getSelectionOriginalPrice($bundleProduct, $selectionProduct);
+
+ return $price * $selectionQty;
+ }
+
+ /**
+ * Calculate the original price of selection
+ *
+ * @param Product $bundleProduct
+ * @param Product $selectionProduct
+ *
+ * @return float
+ */
+ public function getSelectionOriginalPrice(Product $bundleProduct, Product $selectionProduct): float
+ {
+ if ($bundleProduct->getPriceType() == Price::PRICE_TYPE_DYNAMIC) {
+ return (float) $selectionProduct->getPrice();
+ }
+ if ($selectionProduct->getSelectionPriceType()) {
+ // percent
+ return $bundleProduct->getPrice() * ($selectionProduct->getSelectionPriceValue() / 100);
+ }
+
+ // fixed
+ return (float) $selectionProduct->getSelectionPriceValue();
+ }
+
+ /**
+ * Retrieve array of bundle selection IDs
+ *
+ * @param Product $product
+ * @return array
+ */
+ private function getBundleSelectionIds(Product $product): array
+ {
+ $customOption = $product->getCustomOption('bundle_selection_ids');
+ if ($customOption) {
+ $selectionIds = $this->serializer->unserialize($customOption->getValue());
+ if (is_array($selectionIds)) {
+ return $selectionIds;
+ }
+ }
+ return [];
+ }
+}
diff --git a/app/code/Magento/Bundle/Plugin/Quote/UpdateBundleQuoteItemBaseOriginalPrice.php b/app/code/Magento/Bundle/Plugin/Quote/UpdateBundleQuoteItemBaseOriginalPrice.php
new file mode 100644
index 0000000000000..89b729d2a645a
--- /dev/null
+++ b/app/code/Magento/Bundle/Plugin/Quote/UpdateBundleQuoteItemBaseOriginalPrice.php
@@ -0,0 +1,69 @@
+getAllVisibleItems() as $quoteItem) {
+ if ($quoteItem->getProductType() === Type::TYPE_CODE) {
+ $price = $quoteItem->getProduct()->getPrice();
+ $price += $this->price->getTotalBundleItemsOriginalPrice($quoteItem->getProduct());
+ $quoteItem->setBaseOriginalPrice($price);
+ }
+ }
+ return $result;
+ }
+}
diff --git a/app/code/Magento/Bundle/etc/di.xml b/app/code/Magento/Bundle/etc/di.xml
index 3ddefc1a05596..210b0e091b898 100644
--- a/app/code/Magento/Bundle/etc/di.xml
+++ b/app/code/Magento/Bundle/etc/di.xml
@@ -284,4 +284,9 @@
+
+
+
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Bundle/BundleProductCartPricesTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Bundle/BundleProductCartPricesTest.php
new file mode 100644
index 0000000000000..a00031f4b6335
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Bundle/BundleProductCartPricesTest.php
@@ -0,0 +1,704 @@
+quoteIdToMaskedQuoteIdInterface = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class);
+ $this->fixtures = $objectManager->get(DataFixtureStorageManager::class)->getStorage();
+ }
+
+ #[
+ DataFixture(ProductFixture::class, ['price' => 20], 'product1'),
+ DataFixture(ProductFixture::class, ['price' => 10], 'product2'),
+ DataFixture(BundleSelectionFixture::class, ['sku' => '$product1.sku$'], 'selection1'),
+ DataFixture(BundleSelectionFixture::class, ['sku' => '$product2.sku$'], 'selection2'),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection1$']], 'opt1'),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection2$']], 'opt2'),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-fixed-price',
+ 'price' => 15,
+ 'price_type' => Price::PRICE_TYPE_FIXED,
+ '_options' => ['$opt1$', '$opt2$']
+ ],
+ 'bundle_product_1'
+ ),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-fixed-price-special-price',
+ 'price' => 15,
+ 'price_type' => Price::PRICE_TYPE_FIXED,
+ '_options' => ['$opt1$', '$opt2$'],
+ 'special_price' => 90 // it is the 90% of the original price
+ ],
+ 'bundle_product_2'
+ ),
+ DataFixture(GuestCartFixture::class, as: 'cart'),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_1.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ ),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_2.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ )
+ ]
+ public function testBundleProductFixedPriceWithOptionsWithoutPrices()
+ {
+ $cart = $this->fixtures->get('cart');
+ $maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute((int) $cart->getId());
+ $query = $this->getCartQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query);
+
+ // price is the bundle product price as in this case the options don't have prices
+ // specialPrice is the bundle product price * bundle product special price %
+ $expectedResponse = $this->getExpectedResponse(15, 30, 30, 13.5, 27);
+
+ $this->assertEquals($expectedResponse, $response);
+ }
+
+ #[
+ DataFixture(ProductFixture::class, ['price' => 20], 'product1'),
+ DataFixture(ProductFixture::class, ['price' => 10], 'product2'),
+ DataFixture(BundleSelectionFixture::class, ['sku' => '$product1.sku$'], 'selection1'),
+ DataFixture(
+ BundleSelectionFixture::class,
+ [
+ 'sku' => '$product2.sku$',
+ 'price' => 10,
+ 'price_type' => LinkInterface::PRICE_TYPE_FIXED
+ ],
+ 'selection2'
+ ),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection1$']], 'opt1'),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection2$']], 'opt2'),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-fixed-price',
+ 'price' => 15,
+ 'price_type' => Price::PRICE_TYPE_FIXED,
+ '_options' => ['$opt1$', '$opt2$'],
+ ],
+ 'bundle_product_1'
+ ),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-fixed-price-special-price',
+ 'price' => 15,
+ 'price_type' => Price::PRICE_TYPE_FIXED,
+ '_options' => ['$opt1$', '$opt2$'],
+ 'special_price' => 90 // it is the 90% of the original price
+ ],
+ 'bundle_product_2'
+ ),
+ DataFixture(GuestCartFixture::class, as: 'cart'),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_1.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ ),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_2.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ )
+ ]
+ public function testBundleProductFixedPriceWithOneOptionFixedPrice()
+ {
+ $cart = $this->fixtures->get('cart');
+ $maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute((int) $cart->getId());
+ $query = $this->getCartQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query);
+
+ // price is the bundle product price + option fixed price
+ // specialPrice is the bundle product price + option fixed price * bundle product special price %
+ $expectedResponse = $this->getExpectedResponse(25, 50, 50, 22.5, 45);
+
+ $this->assertEquals($expectedResponse, $response);
+ }
+
+ #[
+ DataFixture(ProductFixture::class, ['price' => 20], 'product1'),
+ DataFixture(ProductFixture::class, ['price' => 10], 'product2'),
+ DataFixture(
+ BundleSelectionFixture::class,
+ [
+ 'sku' => '$product1.sku$',
+ 'price' => 20,
+ 'price_type' => LinkInterface::PRICE_TYPE_FIXED
+ ],
+ 'selection1'
+ ),
+ DataFixture(
+ BundleSelectionFixture::class,
+ [
+ 'sku' => '$product2.sku$',
+ 'price' => 10,
+ 'price_type' => LinkInterface::PRICE_TYPE_FIXED
+ ],
+ 'selection2'
+ ),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection1$']], 'opt1'),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection2$']], 'opt2'),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-fixed-price',
+ 'price' => 15,
+ 'price_type' => Price::PRICE_TYPE_FIXED,
+ '_options' => ['$opt1$', '$opt2$'],
+ ],
+ 'bundle_product_1'
+ ),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-fixed-price-special-price',
+ 'price' => 15,
+ 'price_type' => Price::PRICE_TYPE_FIXED,
+ '_options' => ['$opt1$', '$opt2$'],
+ 'special_price' => 90 // it is the 90% of the original price
+ ],
+ 'bundle_product_2'
+ ),
+ DataFixture(GuestCartFixture::class, as: 'cart'),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_1.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ ),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_2.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ )
+ ]
+ public function testBundleProductFixedPriceWithBothOptionsFixedPrice()
+ {
+ $cart = $this->fixtures->get('cart');
+ $maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute((int) $cart->getId());
+ $query = $this->getCartQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query);
+
+ // price is the bundle product price + options fixed prices
+ // specialPrice is the bundle product price + options fixed prices * bundle product special price %
+ $expectedResponse = $this->getExpectedResponse(45, 90, 90, 40.50, 81);
+
+ $this->assertEquals($expectedResponse, $response);
+ }
+
+ #[
+ DataFixture(ProductFixture::class, ['price' => 20], 'product1'),
+ DataFixture(ProductFixture::class, ['price' => 10], 'product2'),
+ DataFixture(BundleSelectionFixture::class, ['sku' => '$product1.sku$'], 'selection1'),
+ DataFixture(
+ BundleSelectionFixture::class,
+ [
+ 'sku' => '$product2.sku$',
+ 'price' => 20,
+ 'price_type' => LinkInterface::PRICE_TYPE_PERCENT
+ ],
+ 'selection2'
+ ),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection1$']], 'opt1'),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection2$']], 'opt2'),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-fixed-price',
+ 'price' => 15,
+ 'price_type' => Price::PRICE_TYPE_FIXED,
+ '_options' => ['$opt1$', '$opt2$'],
+ ],
+ 'bundle_product_1'
+ ),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-fixed-price-special-price',
+ 'price' => 15,
+ 'price_type' => Price::PRICE_TYPE_FIXED,
+ '_options' => ['$opt1$', '$opt2$'],
+ 'special_price' => 90 // it is the 90% of the original price
+ ],
+ 'bundle_product_2'
+ ),
+ DataFixture(GuestCartFixture::class, as: 'cart'),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_1.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ ),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_2.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ )
+ ]
+ public function testBundleProductFixedPriceWithOneOptionPercentPrice()
+ {
+ $cart = $this->fixtures->get('cart');
+ $maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute((int) $cart->getId());
+ $query = $this->getCartQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query);
+
+ // price is the (bundle product price * option percent price) + bundle product price
+ // specialPrice is the (bundle product price * option percent price) +
+ // bundle product price * bundle product special price %
+ $expectedResponse = $this->getExpectedResponse(18, 36, 36, 16.20, 32.40);
+
+ $this->assertEquals($expectedResponse, $response);
+ }
+
+ #[
+ DataFixture(ProductFixture::class, ['price' => 20], 'product1'),
+ DataFixture(ProductFixture::class, ['price' => 10], 'product2'),
+ DataFixture(
+ BundleSelectionFixture::class,
+ [
+ 'sku' => '$product1.sku$',
+ 'price' => 10,
+ 'price_type' => LinkInterface::PRICE_TYPE_PERCENT
+ ],
+ 'selection1'
+ ),
+ DataFixture(
+ BundleSelectionFixture::class,
+ [
+ 'sku' => '$product2.sku$',
+ 'price' => 20,
+ 'price_type' => LinkInterface::PRICE_TYPE_PERCENT
+ ],
+ 'selection2'
+ ),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection1$']], 'opt1'),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection2$']], 'opt2'),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-fixed-price',
+ 'price' => 15,
+ 'price_type' => Price::PRICE_TYPE_FIXED,
+ '_options' => ['$opt1$', '$opt2$'],
+ ],
+ 'bundle_product_1'
+ ),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-fixed-price-special-price',
+ 'price' => 15,
+ 'price_type' => Price::PRICE_TYPE_FIXED,
+ '_options' => ['$opt1$', '$opt2$'],
+ 'special_price' => 90 // it is the 90% of the original price
+ ],
+ 'bundle_product_2'
+ ),
+ DataFixture(GuestCartFixture::class, as: 'cart'),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_1.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ ),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_2.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ )
+ ]
+ public function testBundleProductFixedPriceWithBothOptionsPercentPrices()
+ {
+ $cart = $this->fixtures->get('cart');
+ $maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute((int) $cart->getId());
+ $query = $this->getCartQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query);
+
+ // price is the (bundle product price * options percent price) + bundle product price
+ // specialPrice is the (bundle product price * options percent price) +
+ // bundle product price * bundle product special price %
+ $expectedResponse = $this->getExpectedResponse(19.5, 39, 39, 17.55, 35.10);
+
+ $this->assertEquals($expectedResponse, $response);
+ }
+
+ #[
+ DataFixture(ProductFixture::class, ['price' => 20], 'product1'),
+ DataFixture(ProductFixture::class, ['price' => 10], 'product2'),
+ DataFixture(
+ BundleSelectionFixture::class,
+ [
+ 'sku' => '$product1.sku$',
+ 'price' => 10,
+ 'price_type' => LinkInterface::PRICE_TYPE_FIXED
+ ],
+ 'selection1'
+ ),
+ DataFixture(
+ BundleSelectionFixture::class,
+ [
+ 'sku' => '$product2.sku$',
+ 'price' => 20,
+ 'price_type' => LinkInterface::PRICE_TYPE_PERCENT
+ ],
+ 'selection2'
+ ),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection1$']], 'opt1'),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection2$']], 'opt2'),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-fixed-price',
+ 'price' => 15,
+ 'price_type' => Price::PRICE_TYPE_FIXED,
+ '_options' => ['$opt1$', '$opt2$'],
+ ],
+ 'bundle_product_1'
+ ),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-fixed-price-special-price',
+ 'price' => 15,
+ 'price_type' => Price::PRICE_TYPE_FIXED,
+ '_options' => ['$opt1$', '$opt2$'],
+ 'special_price' => 90 // it is the 90% of the original price
+ ],
+ 'bundle_product_2'
+ ),
+ DataFixture(GuestCartFixture::class, as: 'cart'),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_1.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ ),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_2.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ )
+ ]
+ public function testBundleProductFixedPriceWithOneOptionFixedAndOnePercentPrice()
+ {
+ $cart = $this->fixtures->get('cart');
+ $maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute((int) $cart->getId());
+ $query = $this->getCartQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query);
+
+ // price is the (bundle product price * option percent price) + bundle product price + option fixed price
+ // specialPrice is the (bundle product price * option percent price) + bundle product price +
+ // option fixed price * bundle product special price %
+ $expectedResponse = $this->getExpectedResponse(28, 56, 56, 25.20, 50.40);
+
+ $this->assertEquals($expectedResponse, $response);
+ }
+
+ #[
+ DataFixture(ProductFixture::class, ['price' => 20], 'product1'),
+ DataFixture(ProductFixture::class, ['price' => 10], 'product2'),
+ DataFixture(BundleSelectionFixture::class, ['sku' => '$product1.sku$'], 'selection1'),
+ DataFixture(BundleSelectionFixture::class, ['sku' => '$product2.sku$'], 'selection2'),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection1$']], 'opt1'),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection2$']], 'opt2'),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-dynamic-price',
+ '_options' => ['$opt1$', '$opt2$'],
+ ],
+ 'bundle_product_1'
+ ),
+ DataFixture(GuestCartFixture::class, as: 'cart'),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_1.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ )
+ ]
+ public function testBundleProductDynamicPriceWithoutSpecialPrice()
+ {
+ $cart = $this->fixtures->get('cart');
+ $maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute((int) $cart->getId());
+ $query = $this->getCartQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query);
+
+ $expectedResponse = [
+ "cart" => [
+ "items" => [
+ 0 => [
+ "prices" => [
+ "price" => [
+ "value" => 30,
+ "currency" => "USD"
+ ],
+ "row_total" => [
+ "value" => 60,
+ "currency" => "USD"
+ ],
+ "original_row_total" => [
+ "value" => 60,
+ "currency" => "USD"
+ ]
+ ]
+ ]
+ ]
+ ]
+ ];
+
+ $this->assertEquals($expectedResponse, $response);
+ }
+
+ #[
+ DataFixture(ProductFixture::class, ['price' => 20, 'special_price' => 15], 'product1'),
+ DataFixture(ProductFixture::class, ['price' => 10], 'product2'),
+ DataFixture(BundleSelectionFixture::class, ['sku' => '$product1.sku$'], 'selection1'),
+ DataFixture(BundleSelectionFixture::class, ['sku' => '$product2.sku$'], 'selection2'),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection1$']], 'opt1'),
+ DataFixture(BundleOptionFixture::class, ['product_links' => ['$selection2$']], 'opt2'),
+ DataFixture(
+ BundleProductFixture::class,
+ [
+ 'sku' => 'bundle-product-dynamic-price',
+ '_options' => ['$opt1$', '$opt2$'],
+ ],
+ 'bundle_product_1'
+ ),
+ DataFixture(GuestCartFixture::class, as: 'cart'),
+ DataFixture(
+ AddBundleProductToCart::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$bundle_product_1.id$',
+ 'selections' => [['$product1.id$'], ['$product2.id$']],
+ 'qty' => 2
+ ]
+ )
+ ]
+ public function testBundleProductDynamicPriceWithSpecialPrice()
+ {
+ $cart = $this->fixtures->get('cart');
+ $maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute((int) $cart->getId());
+ $query = $this->getCartQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query);
+
+ $expectedResponse = [
+ "cart" => [
+ "items" => [
+ 0 => [
+ "prices" => [
+ "price" => [
+ "value" => 25,
+ "currency" => "USD"
+ ],
+ "row_total" => [
+ "value" => 50,
+ "currency" => "USD"
+ ],
+ "original_row_total" => [
+ "value" => 60,
+ "currency" => "USD"
+ ]
+ ]
+ ]
+ ]
+ ]
+ ];
+
+ $this->assertEquals($expectedResponse, $response);
+ }
+
+ /**
+ * Generates GraphQl query for get cart prices
+ *
+ * @param string $maskedQuoteId
+ * @return string
+ */
+ private function getCartQuery(string $maskedQuoteId): string
+ {
+ return << [
+ "items" => [
+ 0 => [
+ "prices" => [
+ "price" => [
+ "value" => $price,
+ "currency" => "USD"
+ ],
+ "row_total" => [
+ "value" => $rowTotal,
+ "currency" => "USD"
+ ],
+ "original_row_total" => [
+ "value" => $originalRowTotal,
+ "currency" => "USD"
+ ]
+ ]
+ ],
+ 1 => [
+ "prices" => [
+ "price" => [
+ "value" => $specialPrice,
+ "currency" => "USD"
+ ],
+ "row_total" => [
+ "value" => $specialRowTotal,
+ "currency" => "USD"
+ ],
+ "original_row_total" => [
+ "value" => $originalRowTotal,
+ "currency" => "USD"
+ ]
+ ]
+ ]
+ ]
+ ]
+ ];
+ }
+}