commerce-8.x-2.8/modules/order/tests/src/Kernel/Entity/OrderTest.php
modules/order/tests/src/Kernel/Entity/OrderTest.php
<?php
namespace Drupal\Tests\commerce_order\Kernel\Entity;
use Drupal\commerce_order\Adjustment;
use Drupal\commerce_order\Entity\Order;
use Drupal\commerce_order\Entity\OrderItem;
use Drupal\commerce_order\Entity\OrderItemType;
use Drupal\commerce_price\Exception\CurrencyMismatchException;
use Drupal\commerce_price\Price;
use Drupal\profile\Entity\Profile;
use Drupal\Tests\commerce\Kernel\CommerceKernelTestBase;
/**
* Tests the Order entity.
*
* @coversDefaultClass \Drupal\commerce_order\Entity\Order
*
* @group commerce
*/
class OrderTest extends CommerceKernelTestBase {
/**
* A sample user.
*
* @var \Drupal\user\UserInterface
*/
protected $user;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'entity_reference_revisions',
'profile',
'state_machine',
'commerce_product',
'commerce_order',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('profile');
$this->installEntitySchema('commerce_order');
$this->installEntitySchema('commerce_order_item');
$this->installConfig('commerce_order');
// An order item type that doesn't need a purchasable entity, for simplicity.
OrderItemType::create([
'id' => 'test',
'label' => 'Test',
'orderType' => 'default',
])->save();
$user = $this->createUser();
$this->user = $this->reloadEntity($user);
}
/**
* Tests the order entity and its methods.
*
* @covers ::getOrderNumber
* @covers ::setOrderNumber
* @covers ::getStore
* @covers ::setStore
* @covers ::getStoreId
* @covers ::setStoreId
* @covers ::getCustomer
* @covers ::setCustomer
* @covers ::getCustomerId
* @covers ::setCustomerId
* @covers ::getEmail
* @covers ::setEmail
* @covers ::getIpAddress
* @covers ::setIpAddress
* @covers ::getBillingProfile
* @covers ::setBillingProfile
* @covers ::getItems
* @covers ::setItems
* @covers ::hasItems
* @covers ::addItem
* @covers ::removeItem
* @covers ::hasItem
* @covers ::getAdjustments
* @covers ::setAdjustments
* @covers ::addAdjustment
* @covers ::removeAdjustment
* @covers ::clearAdjustments
* @covers ::collectAdjustments
* @covers ::getSubtotalPrice
* @covers ::recalculateTotalPrice
* @covers ::getTotalPrice
* @covers ::getState
* @covers ::getRefreshState
* @covers ::setRefreshState
* @covers ::getData
* @covers ::setData
* @covers ::isLocked
* @covers ::lock
* @covers ::unlock
* @covers ::getCreatedTime
* @covers ::setCreatedTime
* @covers ::getPlacedTime
* @covers ::setPlacedTime
* @covers ::getCompletedTime
* @covers ::setCompletedTime
*/
public function testOrder() {
$profile = Profile::create([
'type' => 'customer',
]);
$profile->save();
$profile = $this->reloadEntity($profile);
/** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */
$order_item = OrderItem::create([
'type' => 'test',
'quantity' => '1',
'unit_price' => new Price('2.00', 'USD'),
]);
$order_item->save();
$order_item = $this->reloadEntity($order_item);
/** @var \Drupal\commerce_order\Entity\OrderItemInterface $another_order_item */
$another_order_item = OrderItem::create([
'type' => 'test',
'quantity' => '2',
'unit_price' => new Price('3.00', 'USD'),
]);
$another_order_item->save();
$another_order_item = $this->reloadEntity($another_order_item);
$order = Order::create([
'type' => 'default',
'state' => 'completed',
]);
$order->save();
$order->setOrderNumber(7);
$this->assertEquals(7, $order->getOrderNumber());
$order->setStore($this->store);
$this->assertEquals($this->store, $order->getStore());
$this->assertEquals($this->store->id(), $order->getStoreId());
$order->setStoreId(0);
$this->assertEquals(NULL, $order->getStore());
$order->setStoreId([$this->store->id()]);
$this->assertEquals($this->store, $order->getStore());
$this->assertEquals($this->store->id(), $order->getStoreId());
$order->setCustomer($this->user);
$this->assertEquals($this->user, $order->getCustomer());
$this->assertEquals($this->user->id(), $order->getCustomerId());
$order->setCustomerId(0);
$this->assertEquals(NULL, $order->getCustomer());
$order->setCustomerId($this->user->id());
$this->assertEquals($this->user, $order->getCustomer());
$this->assertEquals($this->user->id(), $order->getCustomerId());
$order->setEmail('commerce@example.com');
$this->assertEquals('commerce@example.com', $order->getEmail());
$order->setIpAddress('127.0.0.2');
$this->assertEquals('127.0.0.2', $order->getIpAddress());
$order->setBillingProfile($profile);
$this->assertEquals($profile, $order->getBillingProfile());
$order->setItems([$order_item, $another_order_item]);
$this->assertEquals([$order_item, $another_order_item], $order->getItems());
$this->assertNotEmpty($order->hasItems());
$order->removeItem($another_order_item);
$this->assertEquals([$order_item], $order->getItems());
$this->assertNotEmpty($order->hasItem($order_item));
$this->assertEmpty($order->hasItem($another_order_item));
$order->addItem($another_order_item);
$this->assertEquals([$order_item, $another_order_item], $order->getItems());
$this->assertNotEmpty($order->hasItem($another_order_item));
$this->assertEquals(new Price('8.00', 'USD'), $order->getTotalPrice());
$adjustments = [];
$adjustments[] = new Adjustment([
'type' => 'custom',
'label' => '10% off',
'amount' => new Price('-1.00', 'USD'),
]);
$adjustments[] = new Adjustment([
'type' => 'fee',
'label' => 'Handling fee',
'amount' => new Price('10.00', 'USD'),
'locked' => TRUE,
]);
$order->addAdjustment($adjustments[0]);
$order->addAdjustment($adjustments[1]);
$this->assertEquals($adjustments, $order->getAdjustments());
$collected_adjustments = $order->collectAdjustments();
$this->assertEquals($adjustments[0]->getAmount(), $collected_adjustments[0]->getAmount());
$this->assertEquals($adjustments[1]->getAmount(), $collected_adjustments[1]->getAmount());
$order->removeAdjustment($adjustments[0]);
$this->assertEquals(new Price('8.00', 'USD'), $order->getSubtotalPrice());
$this->assertEquals(new Price('18.00', 'USD'), $order->getTotalPrice());
$this->assertEquals([$adjustments[1]], $order->getAdjustments());
$order->setAdjustments($adjustments);
$this->assertEquals($adjustments, $order->getAdjustments());
$this->assertEquals(new Price('17.00', 'USD'), $order->getTotalPrice());
// Confirm that locked adjustments persist after clear.
// Custom adjustments are locked by default.
$order->addAdjustment(new Adjustment([
'type' => 'fee',
'label' => 'Random fee',
'amount' => new Price('10.00', 'USD'),
]));
$order->clearAdjustments();
$this->assertEquals($adjustments, $order->getAdjustments());
$this->assertEquals('completed', $order->getState()->value);
$order->setRefreshState(Order::REFRESH_ON_SAVE);
$this->assertEquals(Order::REFRESH_ON_SAVE, $order->getRefreshState());
$this->assertEquals('default', $order->getData('test', 'default'));
$order->setData('test', 'value');
$this->assertEquals('value', $order->getData('test', 'default'));
$this->assertFalse($order->isLocked());
$order->lock();
$this->assertTrue($order->isLocked());
$order->unlock();
$this->assertFalse($order->isLocked());
$order->setCreatedTime(635879700);
$this->assertEquals(635879700, $order->getCreatedTime());
$order->setPlacedTime(635879800);
$this->assertEquals(635879800, $order->getPlacedTime());
$order->setCompletedTime(635879900);
$this->assertEquals(635879900, $order->getCompletedTime());
}
/**
* Tests the handling of legacy order item adjustments on adjustment clear.
*
* @covers ::clearAdjustments
* @covers ::collectAdjustments
*/
public function testHandlingLegacyOrderItemAdjustments() {
/** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */
$order_item = OrderItem::create([
'type' => 'test',
'quantity' => '2',
'unit_price' => new Price('10.00', 'USD'),
'adjustments' => [
new Adjustment([
'type' => 'custom',
'label' => '10% off',
'amount' => new Price('-1.00', 'USD'),
'percentage' => '0.1',
]),
new Adjustment([
'type' => 'fee',
'label' => 'Random fee',
'amount' => new Price('2.00', 'USD'),
]),
],
'uses_legacy_adjustments' => TRUE,
]);
$order_item->save();
$order = Order::create([
'type' => 'default',
'order_items' => [$order_item],
'state' => 'draft',
]);
// Confirm that legacy adjustments are multiplied by quantity.
$adjustments = $order->collectAdjustments();
$this->assertCount(2, $adjustments);
$this->assertEquals('-2.00', $adjustments[0]->getAmount()->getNumber());
$this->assertEquals('4.00', $adjustments[1]->getAmount()->getNumber());
// Confirm that the legacy order item adjustments are converted on clear.
$order->clearAdjustments();
$order_items = $order->getItems();
$order_item = reset($order_items);
$adjustments = $order_item->getAdjustments();
$this->assertFalse($order_item->usesLegacyAdjustments());
$this->assertCount(1, $adjustments);
$this->assertEquals('-2.00', $adjustments[0]->getAmount()->getNumber());
// The order item adjustments are no longer multiplied by quantity.
$this->assertEquals($adjustments, $order->collectAdjustments());
}
/**
* Tests the order total recalculation logic.
*
* @covers ::recalculateTotalPrice
*/
public function testTotalCalculation() {
$order = Order::create([
'type' => 'default',
'state' => 'completed',
]);
$order->save();
/** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */
$order_item = OrderItem::create([
'type' => 'test',
'quantity' => '2',
'unit_price' => new Price('2.00', 'USD'),
]);
$order_item->save();
$order_item = $this->reloadEntity($order_item);
/** @var \Drupal\commerce_order\Entity\OrderItemInterface $another_order_item */
$another_order_item = OrderItem::create([
'type' => 'test',
'quantity' => '1',
'unit_price' => new Price('3.00', 'USD'),
]);
$another_order_item->save();
$another_order_item = $this->reloadEntity($another_order_item);
$adjustments = [];
$adjustments[0] = new Adjustment([
'type' => 'tax',
'label' => 'Tax',
'amount' => new Price('100.00', 'USD'),
'included' => TRUE,
]);
$adjustments[1] = new Adjustment([
'type' => 'tax',
'label' => 'Tax',
'amount' => new Price('2.121', 'USD'),
'source_id' => 'us_sales_tax',
]);
$adjustments[2] = new Adjustment([
'type' => 'tax',
'label' => 'Tax',
'amount' => new Price('5.344', 'USD'),
'source_id' => 'us_sales_tax',
]);
// Included adjustments do not affect the order total.
$order->addAdjustment($adjustments[0]);
$order_item->addAdjustment($adjustments[1]);
$another_order_item->addAdjustment($adjustments[2]);
$order->setItems([$order_item, $another_order_item]);
$collected_adjustments = $order->collectAdjustments();
$this->assertCount(3, $collected_adjustments);
$this->assertEquals($adjustments[1], $collected_adjustments[0]);
$this->assertEquals($adjustments[2], $collected_adjustments[1]);
$this->assertEquals($adjustments[0], $collected_adjustments[2]);
// The total will be correct only if the adjustments were correctly
// combined, and rounded.
$this->assertEquals(new Price('14.47', 'USD'), $order->getTotalPrice());
}
/**
* Tests the order with order items using different currencies.
*
* @covers ::getSubtotalPrice
* @covers ::recalculateTotalPrice
* @covers ::getTotalPrice
*/
public function testMultipleCurrencies() {
$currency_importer = \Drupal::service('commerce_price.currency_importer');
$currency_importer->import('EUR');
$usd_order_item = OrderItem::create([
'type' => 'test',
'quantity' => '1',
'unit_price' => new Price('2.00', 'USD'),
]);
$usd_order_item->save();
$eur_order_item = OrderItem::create([
'type' => 'test',
'quantity' => '1',
'unit_price' => new Price('3.00', 'EUR'),
]);
$eur_order_item->save();
$order = Order::create([
'type' => 'default',
'state' => 'completed',
]);
$order->save();
// The order currency should match the currency of the first order item.
$this->assertNull($order->getTotalPrice());
$order->addItem($usd_order_item);
$this->assertEquals($usd_order_item->getTotalPrice(), $order->getTotalPrice());
// Replacing the order item should replace the order total and its currency.
$order->removeItem($usd_order_item);
$order->addItem($eur_order_item);
$this->assertEquals($eur_order_item->getTotalPrice(), $order->getTotalPrice());
// Adding a second order item with a different currency should fail.
$currency_mismatch = FALSE;
try {
$order->addItem($usd_order_item);
}
catch (CurrencyMismatchException $e) {
$currency_mismatch = TRUE;
}
$this->assertTrue($currency_mismatch);
}
/**
* Tests that an order's email updates with the customer.
*/
public function testOrderEmail() {
$customer = $this->createUser(['mail' => 'test@example.com']);
$order_with_customer = Order::create([
'type' => 'default',
'state' => 'completed',
'uid' => $customer,
]);
$order_with_customer->save();
$this->assertEquals($customer->getEmail(), $order_with_customer->getEmail());
$order_without_customer = Order::create([
'type' => 'default',
'state' => 'completed',
]);
$order_without_customer->save();
$this->assertEquals('', $order_without_customer->getEmail());
$order_without_customer->setCustomer($customer);
$order_without_customer->save();
$this->assertEquals($customer->getEmail(), $order_without_customer->getEmail());
}
}
