![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magento\GraphQl\Quote; use Magento\Catalog\Api\CategoryLinkManagementInterface; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Product; use Magento\SalesRule\Api\RuleRepositoryInterface; use Magento\SalesRule\Model\ResourceModel\Rule\Collection; use Magento\SalesRule\Model\Rule; use Magento\Tax\Model\ClassModel as TaxClassModel; use Magento\Tax\Model\ResourceModel\TaxClass\CollectionFactory as TaxClassCollectionFactory; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\GraphQlAbstract; /** * Test cases for applying cart promotions to items in cart */ class CartPromotionsTest extends GraphQlAbstract { /** * @var float */ private const EPSILON = 0.0000000001; /** * Test adding single cart rule to multiple products in a cart * * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php * @magentoApiDataFixture Magento/SalesRule/_files/rules_category.php */ public function testCartPromotionSingleCartRule() { $skus =['simple1', 'simple2']; $objectManager = Bootstrap::getObjectManager(); /** @var ProductRepositoryInterface $productRepository */ $productRepository = $objectManager->get(ProductRepositoryInterface::class); /** @var Product $prod2 */ $prod1 = $productRepository->get('simple1'); $prod2 = $productRepository->get('simple2'); $categoryId = 66; /** @var \Magento\Catalog\Api\CategoryLinkManagementInterface $categoryLinkManagement */ $categoryLinkManagement = $objectManager->create(CategoryLinkManagementInterface::class); foreach ($skus as $sku) { $categoryLinkManagement->assignProductToCategories( $sku, [$categoryId] ); } /** @var Collection $ruleCollection */ $ruleCollection = $objectManager->get(Collection::class); $ruleLabels = []; /** @var Rule $rule */ foreach ($ruleCollection as $rule) { $ruleLabels = $rule->getStoreLabels(); } $qty = 2; $cartId = $this->createEmptyCart(); $this->addMultipleSimpleProductsToCart($cartId, $qty, $skus[0], $skus[1]); $query = $this->getCartItemPricesQuery($cartId); $response = $this->graphQlMutation($query); $this->assertCount(2, $response['cart']['items']); $productsInCart = [$prod1, $prod2]; //validating the line item prices, quantity and discount $this->assertLineItemDiscountPrices($response, $productsInCart, $qty, $ruleLabels); //total discount on the cart which is the sum of the individual row discounts $this->assertEquals($response['cart']['prices']['discounts'][0]['amount']['value'], 21.98); } /** * Assert the row total discounts and individual discount break down and cart rule labels * * @param $response * @param $productsInCart * @param $qty * @param $ruleLabels */ private function assertLineItemDiscountPrices($response, $productsInCart, $qty, $ruleLabels) { $productsInResponse = array_map(null, $response['cart']['items'], $productsInCart); $count = count($productsInCart); for ($itemIndex = 0; $itemIndex < $count; $itemIndex++) { $this->assertNotEmpty($productsInResponse[$itemIndex]); $this->assertResponseFields( $productsInResponse[$itemIndex][0], [ 'quantity' => $qty, 'prices' => [ 'row_total' => ['value' => $productsInCart[$itemIndex]->getSpecialPrice()*$qty], 'row_total_including_tax' => ['value' => $productsInCart[$itemIndex]->getSpecialPrice()*$qty], 'total_item_discount' => ['value' => $productsInCart[$itemIndex]->getSpecialPrice()*$qty*0.5], 'discounts' => [ 0 =>[ 'amount' => ['value' => $productsInCart[$itemIndex]->getSpecialPrice()*$qty*0.5], 'label' => $ruleLabels[0] ] ] ], ] ); } } /** * Apply multiple cart rules to multiple products in a cart * * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php * @magentoApiDataFixture Magento/SalesRule/_files/rules_category.php * @magentoApiDataFixture Magento/SalesRule/_files/cart_rule_10_percent_off_qty_more_than_2_items.php * @magentoApiDataFixture Magento/SalesRule/_files/cart_rule_free_shipping.php */ public function testCartPromotionsMultipleCartRules() { $objectManager = Bootstrap::getObjectManager(); /** @var ProductRepositoryInterface $productRepository */ $productRepository = $objectManager->get(ProductRepositoryInterface::class); /** @var Product $prod2 */ $prod1 = $productRepository->get('simple1'); $prod2 = $productRepository->get('simple2'); $productsInCart = [$prod1, $prod2]; $skus =['simple1', 'simple2']; $categoryId = 66; /** @var \Magento\Catalog\Api\CategoryLinkManagementInterface $categoryLinkManagement */ $categoryLinkManagement = $objectManager->create(CategoryLinkManagementInterface::class); foreach ($skus as $sku) { $categoryLinkManagement->assignProductToCategories( $sku, [$categoryId] ); } /** @var Collection $ruleCollection */ $ruleCollection = $objectManager->get(Collection::class); $ruleLabels = []; /** @var Rule $rule */ foreach ($ruleCollection as $rule) { $ruleLabels[] = $rule->getStoreLabels(); } $qty = 2; $cartId = $this->createEmptyCart(); $this->addMultipleSimpleProductsToCart($cartId, $qty, $skus[0], $skus[1]); $this->setShippingAddressOnCart($cartId); $query = $this->getCartItemPricesQuery($cartId); $response = $this->graphQlMutation($query); $this->assertCount(2, $response['cart']['items']); //validating the individual discounts per line item and total discounts per line item $productsInResponse = array_map(null, $response['cart']['items'], $productsInCart); $count = count($productsInCart); for ($itemIndex = 0; $itemIndex < $count; $itemIndex++) { $this->assertNotEmpty($productsInResponse[$itemIndex]); $lineItemDiscount = $productsInResponse[$itemIndex][0]['prices']['discounts']; $expectedTotalDiscountValue = ($productsInCart[$itemIndex]->getSpecialPrice()*$qty*0.5) + ($productsInCart[$itemIndex]->getSpecialPrice()*$qty*0.5*0.1); $this->assertEqualsWithDelta( $productsInCart[$itemIndex]->getSpecialPrice()*$qty*0.5, current($lineItemDiscount)['amount']['value'], self::EPSILON ); $this->assertEquals('TestRule_Label', current($lineItemDiscount)['label']); $lineItemDiscountValue = next($lineItemDiscount)['amount']['value']; $this->assertEqualsWithDelta( round($productsInCart[$itemIndex]->getSpecialPrice()*$qty*0.5)*0.1, $lineItemDiscountValue, self::EPSILON ); $this->assertEquals('10% off with two items_Label', end($lineItemDiscount)['label']); $actualTotalDiscountValue = $lineItemDiscount[0]['amount']['value']+$lineItemDiscount[1]['amount']['value']; $this->assertEquals(round($expectedTotalDiscountValue, 2), $actualTotalDiscountValue); //removing the elements from the response so that the rest of the response values can be compared unset($productsInResponse[$itemIndex][0]['prices']['discounts']); unset($productsInResponse[$itemIndex][0]['prices']['total_item_discount']); $this->assertResponseFields( $productsInResponse[$itemIndex][0], [ 'quantity' => $qty, 'prices' => [ 'row_total' => ['value' => $productsInCart[$itemIndex]->getSpecialPrice()*$qty], 'row_total_including_tax' => ['value' => $productsInCart[$itemIndex]->getSpecialPrice()*$qty] ], ] ); } $this->assertEquals($response['cart']['prices']['discounts'][0]['amount']['value'], 24.18); } /** * Apply cart rules to multiple products in a cart with taxes * Tax settings : Including and Excluding tax for Price Display and Shopping cart display * Discount on Prices Includes Tax * Tax rate = 7.5% * Cart rule to apply 50% for products assigned to a specific category * * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_calculation_price_and_cart_display_settings.php * @magentoApiDataFixture Magento/SalesRule/_files/rules_category.php */ public function testCartPromotionsCartRulesWithTaxes() { $objectManager = Bootstrap::getObjectManager(); /** @var ProductRepositoryInterface $productRepository */ $productRepository = $objectManager->get(ProductRepositoryInterface::class); /** @var Product $prod2 */ $prod1 = $productRepository->get('simple1'); $prod2 = $productRepository->get('simple2'); $productsInCart = [$prod1, $prod2]; $skus =['simple1', 'simple2']; /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ $taxClassCollectionFactory = $objectManager->get(TaxClassCollectionFactory::class); $taxClassCollection = $taxClassCollectionFactory->create(); /** @var TaxClassModel $taxClass */ $taxClassCollection->addFieldToFilter('class_type', TaxClassModel::TAX_CLASS_TYPE_PRODUCT); $taxClass = $taxClassCollection->getFirstItem(); foreach ($productsInCart as $product) { $product->setCustomAttribute('tax_class_id', $taxClass->getClassId()); $productRepository->save($product); } $categoryId = 66; /** @var \Magento\Catalog\Api\CategoryLinkManagementInterface $categoryLinkManagement */ $categoryLinkManagement = $objectManager->create(CategoryLinkManagementInterface::class); foreach ($skus as $sku) { $categoryLinkManagement->assignProductToCategories( $sku, [$categoryId] ); } $qty = 1; $cartId = $this->createEmptyCart(); $this->addMultipleSimpleProductsToCart($cartId, $qty, $skus[0], $skus[1]); $this->setShippingAddressOnCart($cartId); $query = $this->getCartItemPricesQuery($cartId); $response = $this->graphQlMutation($query); $this->assertCount(2, $response['cart']['items']); $productsInResponse = array_map(null, $response['cart']['items'], $productsInCart); $count = count($productsInCart); for ($itemIndex = 0; $itemIndex < $count; $itemIndex++) { $this->assertNotEmpty($productsInResponse[$itemIndex]); $rowTotalIncludingTax = round( $productsInCart[$itemIndex]->getSpecialPrice()*$qty + $productsInCart[$itemIndex]->getSpecialPrice()*$qty*.075, 2 ); $this->assertResponseFields( $productsInResponse[$itemIndex][0], [ 'quantity' => $qty, 'prices' => [ // row_total is the line item price without the tax 'row_total' => ['value' => $productsInCart[$itemIndex]->getSpecialPrice()*$qty], // row_total including tax is the price + price * tax rate 'row_total_including_tax' => ['value' => $rowTotalIncludingTax], // discount from cart rule after tax is applied : 50% of row_total_including_tax 'total_item_discount' => ['value' => round($rowTotalIncludingTax/2, 2)], 'discounts' => [ 0 =>[ 'amount' => ['value' => round($rowTotalIncludingTax/2, 2)], 'label' => 'TestRule_Label' ] ] ], ] ); } // checking the total discount on the entire cart $this->assertEquals($response['cart']['prices']['discounts'][0]['amount']['value'], 11.82); } /** * Apply cart rule with a fixed discount when specific coupon code * * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php */ public function testCartPromotionsWithCoupons() { $objectManager = Bootstrap::getObjectManager(); /** @var ProductRepositoryInterface $productRepository */ $productRepository = $objectManager->get(ProductRepositoryInterface::class); /** @var Product $prod2 */ $prod1 = $productRepository->get('simple1'); $prod2 = $productRepository->get('simple2'); $productsInCart = [$prod1, $prod2]; $skus =['simple1', 'simple2']; /** @var Collection $ruleCollection */ $ruleCollection = $objectManager->get(Collection::class); $ruleLabels = []; /** @var Rule $rule */ foreach ($ruleCollection as $rule) { $ruleLabels = $rule->getStoreLabels(); } $qty = 2; // coupon code obtained from the fixture $couponCode = '2?ds5!2d'; $cartId = $this->createEmptyCart(); $this->addMultipleSimpleProductsToCart($cartId, $qty, $skus[0], $skus[1]); $this->applyCouponsToCart($cartId, $couponCode); $query = $this->getCartItemPricesQuery($cartId); $response = $this->graphQlMutation($query); $this->assertCount(2, $response['cart']['items']); $productsInResponse = array_map(null, $response['cart']['items'], $productsInCart); $count = count($productsInCart); for ($itemIndex = 0; $itemIndex < $count; $itemIndex++) { $this->assertNotEmpty($productsInResponse[$itemIndex]); $sumOfPricesForBothProducts = 43.96; $rowTotal = ($productsInCart[$itemIndex]->getSpecialPrice()*$qty); $this->assertResponseFields( $productsInResponse[$itemIndex][0], [ 'quantity' => $qty, 'prices' => [ 'row_total' => ['value' => $productsInCart[$itemIndex]->getSpecialPrice()*$qty], 'row_total_including_tax' => ['value' => $productsInCart[$itemIndex]->getSpecialPrice()*$qty], 'total_item_discount' => ['value' => round(($rowTotal/$sumOfPricesForBothProducts)*5, 2)], 'discounts' => [ 0 =>[ 'amount' => ['value' => round(($rowTotal/$sumOfPricesForBothProducts)*5, 2)], 'label' => $ruleLabels[0] ] ] ], ] ); } $this->assertEquals($response['cart']['prices']['discounts'][0]['amount']['value'], 5); } /** * If no discount is applicable to the cart, row total discount should be zero and no rule label shown * * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php * @magentoApiDataFixture Magento/SalesRule/_files/buy_3_get_1_free.php */ public function testCartPromotionsWhenNoDiscountIsAvailable() { $skus =['simple1', 'simple2']; $qty = 2; $cartId = $this->createEmptyCart(); $this->addMultipleSimpleProductsToCart($cartId, $qty, $skus[0], $skus[1]); $query = $this->getCartItemPricesQuery($cartId); $response = $this->graphQlMutation($query); $this->assertCount(2, $response['cart']['items']); foreach ($response['cart']['items'] as $cartItems) { $this->assertEquals(0, $cartItems['prices']['total_item_discount']['value']); $this->assertNull($cartItems['prices']['discounts']); } } /** * Validating if the discount label in the response shows the default value if no label is available on cart rule * * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php * @magentoApiDataFixture Magento/SalesRule/_files/cart_rule_10_percent_off.php */ public function testCartPromotionsWithNoRuleLabels() { $skus =['simple1', 'simple2']; $qty = 1; $cartId = $this->createEmptyCart(); $this->addMultipleSimpleProductsToCart($cartId, $qty, $skus[0], $skus[1]); $query = $this->getCartItemPricesQuery($cartId); $response = $this->graphQlMutation($query); //total items added to cart $this->assertCount(2, $response['cart']['items']); //checking the default label for individual line item when cart rule doesn't have a label set foreach ($response['cart']['items'] as $cartItem) { $this->assertEquals('Discount', $cartItem['prices']['discounts'][0]['label']); } } /** * Test fixed discount cannot be higher than products price * * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php */ public function testCartPromotionsFixedDiscountNotHigherThanProductsPrice() { /** @var ProductRepositoryInterface $productRepository */ $productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); /** @var Product $prod2 */ $prod1 = $productRepository->get('simple1'); $prod2 = $productRepository->get('simple2'); $productsInCart = [$prod1, $prod2]; $skus =['simple1', 'simple2']; $qty = 2; $sumOfPricesForBothProducts = 43.96; $couponCode = '2?ds5!2d'; /** @var RuleRepositoryInterface $ruleRepository */ $ruleRepository = Bootstrap::getObjectManager()->get(RuleRepositoryInterface::class); /** @var Collection $ruleCollection */ $ruleCollection = Bootstrap::getObjectManager()->get(Collection::class); $ruleLabels = []; /** @var Rule $rule */ foreach ($ruleCollection as $rule) { $ruleLabels = $rule->getStoreLabels(); $salesRule = $ruleRepository->getById($rule->getRuleId()); $salesRule->setDiscountAmount(50); $ruleRepository->save($salesRule); } $cartId = $this->createEmptyCart(); $this->addMultipleSimpleProductsToCart($cartId, $qty, $skus[0], $skus[1]); $this->applyCouponsToCart($cartId, $couponCode); $query = $this->getCartItemPricesQuery($cartId); $response = $this->graphQlMutation($query); $this->assertCount(2, $response['cart']['items']); $productsInResponse = array_map(null, $response['cart']['items'], $productsInCart); $count = count($productsInCart); for ($itemIndex = 0; $itemIndex < $count; $itemIndex++) { $this->assertNotEmpty($productsInResponse[$itemIndex]); $rowTotal = ($productsInCart[$itemIndex]->getSpecialPrice()*$qty); $this->assertResponseFields( $productsInResponse[$itemIndex][0], [ 'quantity' => $qty, 'prices' => [ 'row_total' => ['value' => $rowTotal], 'row_total_including_tax' => ['value' => $rowTotal], 'total_item_discount' => ['value' => $rowTotal], 'discounts' => [ 0 =>[ 'amount' => ['value' => $rowTotal], 'label' => $ruleLabels[0] ] ] ], ] ); } $this->assertEquals( $response['cart']['prices']['discounts'][0]['amount']['value'], $sumOfPricesForBothProducts ); } /** * Apply coupon to the cart * * @param string $cartId * @param string $couponCode */ private function applyCouponsToCart(string $cartId, string $couponCode) { $query = <<<QUERY mutation { applyCouponToCart(input: {cart_id: "$cartId", coupon_code: "$couponCode"}) { cart { applied_coupons { code } } } } QUERY; $response = $this->graphQlMutation($query); self::assertArrayHasKey('applyCouponToCart', $response); self::assertEquals($couponCode, $response['applyCouponToCart']['cart']['applied_coupons'][0]['code']); } /** * @param string $cartId * @return string */ private function getCartItemPricesQuery(string $cartId): string { return <<<QUERY { cart(cart_id:"{$cartId}"){ items{ quantity prices{ row_total{ value } row_total_including_tax{ value } total_item_discount{value} discounts{ amount{value} label } } } prices{ discounts{ amount{value} } } } } QUERY; } /** * @return string */ private function createEmptyCart(): string { $query = <<<QUERY mutation { createEmptyCart } QUERY; $response = $this->graphQlMutation($query); $cartId = $response['createEmptyCart']; return $cartId; } /** * @param string $cartId * @param int $sku1 * @param int $qty * @param string $sku2 */ private function addMultipleSimpleProductsToCart(string $cartId, int $qty, string $sku1, string $sku2): void { $query = <<<QUERY mutation { addSimpleProductsToCart(input: { cart_id: "{$cartId}", cart_items: [ { data: { quantity: $qty sku: "$sku1" } } { data: { quantity: $qty sku: "$sku2" } } ] } ) { cart { items { product{sku} quantity } } } } QUERY; $response = $this->graphQlMutation($query); self::assertArrayHasKey('cart', $response['addSimpleProductsToCart']); self::assertEquals($qty, $response['addSimpleProductsToCart']['cart']['items'][0]['quantity']); self::assertEquals($sku1, $response['addSimpleProductsToCart']['cart']['items'][0]['product']['sku']); self::assertEquals($qty, $response['addSimpleProductsToCart']['cart']['items'][1]['quantity']); self::assertEquals($sku2, $response['addSimpleProductsToCart']['cart']['items'][1]['product']['sku']); } /** * Set shipping address for the region for which tax rule is set * * @param string $cartId * @return void */ private function setShippingAddressOnCart(string $cartId) :void { $query = <<<QUERY mutation { setShippingAddressesOnCart( input: { cart_id: "$cartId" shipping_addresses: [ { address: { firstname: "John" lastname: "Doe" company: "Magento" street: ["test street 1", "test street 2"] city: "Montgomery" region: "AL" postcode: "36043" country_code: "US" telephone: "88776655" save_in_address_book: false } } ] } ) { cart { shipping_addresses { city region{label} } } } } QUERY; $response = $this->graphQlMutation($query); self::assertEquals( 'Montgomery', $response['setShippingAddressesOnCart']['cart']['shipping_addresses'][0]['city'] ); self::assertEquals( 'Alabama', $response['setShippingAddressesOnCart']['cart']['shipping_addresses'][0]['region']['label'] ); } }