You are here

public function BuyXGetYTest::testAutoAddOrderItem in Commerce Core 8.2

Tests the 'auto-add' offered item capability.

@covers ::apply

File

modules/promotion/tests/src/Kernel/Plugin/Commerce/PromotionOffer/BuyXGetYTest.php, line 535

Class

BuyXGetYTest
Tests the "Buy X Get Y" offer.

Namespace

Drupal\Tests\commerce_promotion\Kernel\Plugin\Commerce\PromotionOffer

Code

public function testAutoAddOrderItem() {

  // Configure a "buy 3 of anything, get 1 specific product free" offer.
  $offer = $this->promotion
    ->getOffer();
  $offer_configuration = $offer
    ->getConfiguration();

  // The customer purchases 3 quantities of any product.
  $offer_configuration['buy_quantity'] = '3';
  $offer_configuration['buy_conditions'] = [];

  // The customer receives 1 specific product for free.
  $offer_configuration['get_quantity'] = '1';
  $offer_configuration['get_conditions'] = [
    [
      'plugin' => 'order_item_purchased_entity:commerce_product_variation',
      'configuration' => [
        'entities' => [
          $this->variations[2]
            ->uuid(),
        ],
      ],
    ],
  ];
  $offer_configuration['get_auto_add'] = TRUE;
  $offer_configuration['offer_type'] = 'percentage';
  $offer_configuration['offer_percentage'] = '1';
  $offer_configuration['offer_amount'] = NULL;
  $offer
    ->setConfiguration($offer_configuration);
  $this->promotion
    ->setOffer($offer);

  /** @var \Drupal\commerce_order\OrderItemStorageInterface $order_item_storage */
  $order_item_storage = \Drupal::entityTypeManager()
    ->getStorage('commerce_order_item');

  // Price of first order item: 10. Matches the first required quantity of the
  // buy condition.
  $first_order_item = $order_item_storage
    ->createFromPurchasableEntity($this->variations[0], [
    'quantity' => '3',
  ]);
  $this->order
    ->setItems([
    $first_order_item,
  ]);
  $this->order
    ->save();
  $this->container
    ->get('commerce_order.order_refresh')
    ->refresh($this->order);

  // The offer automatically added a second order item.
  list($first_order_item, $second_order_item) = $this->order
    ->getItems();
  $this
    ->assertCount(0, $first_order_item
    ->getAdjustments());
  $this
    ->assertCount(1, $second_order_item
    ->getAdjustments());
  $this
    ->assertEquals(1, $second_order_item
    ->getQuantity());
  $this
    ->assertEquals($this->variations[2]
    ->id(), $second_order_item
    ->getPurchasedEntityId());
  $this
    ->assertAdjustmentPrice($second_order_item
    ->getAdjustments()[0], '-30');

  // Increase the quantity of the "buy" product to 4, the quantity of the
  // offered product will not change.
  $first_order_item
    ->setQuantity(4);
  $this->order
    ->setItems([
    $first_order_item,
    $second_order_item,
  ]);
  $this->order
    ->save();
  $this->container
    ->get('commerce_order.order_refresh')
    ->refresh($this->order);
  list($first_order_item, $second_order_item) = $this->order
    ->getItems();
  $this
    ->assertCount(0, $first_order_item
    ->getAdjustments());
  $this
    ->assertEquals(4, $first_order_item
    ->getQuantity());
  $this
    ->assertCount(1, $second_order_item
    ->getAdjustments());
  $this
    ->assertEquals(1, $second_order_item
    ->getQuantity());

  // Increase the quantity of the "buy" product to 6, the quantity of the
  // offered product will be increased to 2.
  $first_order_item
    ->setQuantity(6);
  $this->order
    ->setItems([
    $first_order_item,
    $second_order_item,
  ]);
  $this->order
    ->save();
  $this->container
    ->get('commerce_order.order_refresh')
    ->refresh($this->order);
  list($first_order_item, $second_order_item) = $this->order
    ->getItems();
  $this
    ->assertEquals(6, $first_order_item
    ->getQuantity());
  $this
    ->assertCount(0, $first_order_item
    ->getAdjustments());
  $this
    ->assertEquals(2, $second_order_item
    ->getQuantity());
  $this
    ->assertCount(1, $second_order_item
    ->getAdjustments());
  $this
    ->assertAdjustmentPrice($second_order_item
    ->getAdjustments()[0], '-60');

  // Try to remove the "get" product from the order, it will be added back
  // automatically.
  $this->order
    ->removeItem($second_order_item);
  $this
    ->assertCount(1, $this->order
    ->getItems());
  $this->order
    ->save();
  $this->container
    ->get('commerce_order.order_refresh')
    ->refresh($this->order);
  list($first_order_item, $second_order_item) = $this->order
    ->getItems();
  $this
    ->assertEquals(6, $first_order_item
    ->getQuantity());
  $this
    ->assertEquals(2, $second_order_item
    ->getQuantity());
  $this
    ->assertCount(1, $second_order_item
    ->getAdjustments());
  $this
    ->assertAdjustmentPrice($second_order_item
    ->getAdjustments()[0], '-60');

  // Decrease the quantity of the "buy" product from the order, the "get"
  // quantity will be decreased and the discount will only be applied once.
  $first_order_item
    ->setQuantity(5);
  $this->order
    ->setItems([
    $first_order_item,
    $second_order_item,
  ]);
  $this->order
    ->save();
  $this->container
    ->get('commerce_order.order_refresh')
    ->refresh($this->order);
  list($first_order_item, $second_order_item) = $this->order
    ->getItems();
  $this
    ->assertEquals(5, $first_order_item
    ->getQuantity());
  $this
    ->assertEquals(1, $second_order_item
    ->getQuantity());
  $this
    ->assertCount(1, $second_order_item
    ->getAdjustments());
  $this
    ->assertAdjustmentPrice($second_order_item
    ->getAdjustments()[0], '-30');

  // Test that the order item data key holding the auto-added quantity is
  // cleared when the get order item is no longer eligible for the offer, but
  // extra quantity was added by the customer.
  $this
    ->assertNotNull($second_order_item
    ->getData('promotion:1:auto_add_quantity'));
  $second_order_item
    ->setQuantity('2');
  $first_order_item
    ->setQuantity('1');
  $this->container
    ->get('commerce_order.order_refresh')
    ->refresh($this->order);
  list(, $second_order_item) = $this->order
    ->getItems();
  $this
    ->assertNull($second_order_item
    ->getData('promotion:1:auto_add_quantity'));
  $this
    ->assertEquals(1, $second_order_item
    ->getQuantity());
}