contacts_events-8.x-1.x-dev/modules/village_allocation/tests/src/Kernel/AutomaticAllocationTest.php
modules/village_allocation/tests/src/Kernel/AutomaticAllocationTest.php
<?php
namespace Drupal\Tests\village_allocation\Kernel;
use Drupal\commerce_order\Entity\Order;
use Drupal\commerce_order\Entity\OrderItem;
use Drupal\commerce_store\Entity\Store;
use Drupal\contacts_events\Entity\Event;
use Drupal\contacts_events_accommodation\Entity\Accommodation;
use Drupal\contacts_events_villages\Entity\Village;
use Drupal\contacts_events_villages\Entity\VillageGroup;
use Drupal\taxonomy\Entity\Term;
use Drupal\Tests\commerce\Kernel\CommerceKernelTestBase;
/**
* Tests for automatic VA.
*
* @package Drupal\Tests\village_allocation\Kernel
*/
class AutomaticAllocationTest extends CommerceKernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = [
'block',
'commerce',
'commerce_checkout',
'commerce_order',
'commerce_price',
'commerce_payment',
'commerce_store',
'crm_tools',
'bookkeeping',
'contacts',
'contacts_events',
'contacts_events_accommodation',
'contacts_events_villages',
'village_allocation',
'village_allocation_test',
'facets',
'search_api',
'search_api_db',
'taxonomy',
'ctools',
'datetime',
'datetime_range',
'field_group',
'entity',
'entity_reference_revisions',
'field',
'file',
'image',
'state_machine',
'profile',
'name',
'image',
'views',
'views_data_export',
'rest',
'serialization',
'dynamic_entity_reference',
];
/**
* {@inheritdoc}
*/
protected $strictConfigSchema = FALSE;
/**
* Test village.
*
* @var \Drupal\contacts_events_villages\Entity\Village
*/
private $village1;
/**
* Test village.
*
* @var \Drupal\contacts_events_villages\Entity\Village
*/
private $village2;
/**
* Test village.
*
* @var \Drupal\contacts_events_villages\Entity\Village
*/
private $village3;
/**
* Event for testing.
*
* @var \Drupal\contacts_events\Entity\Event
*/
private $event;
/**
* Fake accommodation instance for testing.
*
* @var \Drupal\contacts_events_accommodation\Entity\Accommodation
*/
private $accommodation;
/**
* Whether debugging is enabled.
*
* @var bool
*/
private $debug;
/**
* {@inheritdoc}
*/
protected function setUp() : void {
parent::setUp();
$this->installEntitySchema('file');
$this->installEntitySchema('profile');
$this->installEntitySchema('commerce_order');
$this->installEntitySchema('commerce_order_item');
$this->installEntitySchema('commerce_payment');
$this->installEntitySchema('contacts_event');
$this->installEntitySchema('c_events_village');
$this->installEntitySchema('c_events_accommodation');
$this->installEntitySchema('c_events_village_group');
$this->installEntitySchema('search_api_task');
$this->installEntitySchema('bookkeeping_transaction');
$this->installEntitySchema('taxonomy_term');
$this->installConfig('search_api');
$this->installConfig('field_group');
$this->installConfig('bookkeeping');
$this->installConfig('contacts');
$this->installConfig('commerce_order');
$this->installConfig('commerce_payment');
$this->installConfig('contacts_events');
$this->installConfig('contacts_events_accommodation');
$this->installConfig('contacts_events_villages');
$this->installConfig('village_allocation');
$this->installConfig('village_allocation_test');
$this->event = Event::create(['type' => 'default']);
$this->event->save();
$this->store = Store::create([
'name' => 'Default',
'type' => 'online',
'default_currency' => 'GBP',
]);
$this->store->save();
// Create a couple of villages.
// Create a couple villages.
$this->village1 = Village::create([
'name' => 'Blue 1',
'event' => $this->event,
'pitches' => 10,
'fill_value' => 80,
'weight' => 1,
]);
$this->village2 = Village::create([
'name' => 'Blue 2',
'event' => $this->event,
'pitches' => 10,
'fill_value' => 80,
'weight' => 2,
]);
$this->village3 = Village::create([
'name' => 'Blue 3',
'event' => $this->event,
'pitches' => 10,
'fill_value' => 80,
'weight' => 3,
]);
$this->village1->save();
$this->village2->save();
$this->village3->save();
// Fake accomodation item.
$this->accommodation = Accommodation::create([
'pitch_size' => 1,
'title' => 'Tent',
'event' => $this->event,
'bundle' => 'camping',
]);
$this->accommodation->save();
// Set to TRUE to see full debug output in tests.
$this->debug = FALSE;
if ($this->debug) {
$this->container->set('devel.dumper', new ConsoleDumper());
}
}
/**
* Tests allocation.
*
* All tests are in the same test method to prevent multiple drupal installs.
* Remember to call deleteOrders between each test.
*/
public function testAllocation() {
$church = $this->createChurch('Church1', 'WD24 6GX');
$group = $this->createChurchGroup($church);
// Simple allocation with single booking - assigns to first village.
$booking = $this->createBooking($group);
$this->runAllocation();
$booking = Order::load($booking->id());
$this->assertEqual($booking->get('village')->entity->name->value, 'Blue 1');
$this->deleteOrders();
// 2 bookings. One already allocated one not. Second one should end in the
// same village as the first one.
$booking1 = $this->createBooking($group);
$booking2 = $this->createBooking($group);
$booking1->set('village', $this->village2->id());
$booking1->save();
$this->runAllocation();
$booking2 = Order::load($booking2->id());
$this->assertEqual($booking2->get('village')->entity->name->value, 'Blue 2');
$this->deleteOrders();
// 2 bookings, one already allocated. If the village is full then the second
// booking should end up in a different village.
// Create booking1 with 8 order items (1 pitch per item), which will fill
// the village to 80% (which is it's limit).
$booking1 = $this->createBooking($group, 8);
$booking2 = $this->createBooking($group);
$booking1->set('village', $this->village1->id());
$booking1->save();
$this->runAllocation();
$booking2 = Order::load($booking2->id());
$this->assertEqual($booking2->get('village')->entity->name->value, 'Blue 2');
$this->deleteOrders();
// 3 bookings. 1st allocate to Blue 1 (which is now full). 2nd is part of
// a different group, but has a similar postcode in Blue 3. Our booking
// should be allocated to Blue 3, even though Blue 2 is the next available
// empty village.
$church2 = $this->createChurch('Church2', 'WD24 7XA');
$group2 = $this->createChurchGroup($church2);
$booking1 = $this->createBooking($group, 8);
$booking2 = $this->createBooking($group);
$booking3 = $this->createBooking($group2);
$booking1->set('village', $this->village1->id());
$booking3->set('village', $this->village3->id());
$booking1->save();
$booking3->save();
$this->runAllocation();
$booking2 = Order::load($booking2->id());
$this->assertEqual($booking2->get('village')->entity->name->value, 'Blue 3');
$this->deleteOrders();
}
/**
* Creates a test booking.
*
* @param \Drupal\contacts_events_villages\Entity\VillageGroup $group
* The parent group.
* @param int $quantity
* Accommodation quantity (each item is 1 pitch for testing purposes).
* Defaults to 1.
*
* @return \Drupal\commerce_order\Entity\Order
* Booking order.
*/
private function createBooking(VillageGroup $group, $quantity = 1) {
// Create a booking.
$order = Order::create([
'type' => 'contacts_booking',
'event' => $this->event,
'village_group' => $group,
'store_id' => $this->store->id(),
'state' => 'paid_in_full',
]);
$order_item = OrderItem::create([
'type' => 'ce_accom_camping',
'purchased_entity' => $this->accommodation,
'total_price' => ['number' => 10, 'currency_code' => 'GBP'],
'quantity' => $quantity,
]);
$order->addItem($order_item);
$order->save();
$order->get('state')->first()->applyTransitionById('confirmed_paid_in_full');
$order->save();
return $order;
}
/**
* Creates a church group for bookings.
*
* @param \Drupal\taxonomy\Entity\Term $church
* The church associated with the group.
*
* @return \Drupal\contacts_events_villages\Entity\VillageGroup
* The created group.
*/
private function createChurchGroup(Term $church) {
$group = VillageGroup::create([
'type' => 'church',
'name' => 'Group',
'church' => $church->id(),
'allocation_sorting_code' => $church->church_address->postal_code,
]);
$group->save();
return $group;
}
/**
* Creates a church.
*
* @param string $name
* Church name.
* @param string $postcode
* Postcode for allocation purposes.
*
* @return \Drupal\taxonomy\Entity\Term
* Taxonomy term for the church.
*/
private function createChurch($name, $postcode) {
$church = Term::create(['vid' => 'church', 'name' => $name]);
$church->set('church_address', [
'country_code' => 'GB',
'locality' => 'X',
'given_name' => 'X',
'family_name' => 'X',
'postal_code' => $postcode,
]);
$church->save();
return $church;
}
/**
* Runs the allocation.
*/
private function runAllocation() {
/** @var \Drupal\village_allocation\AutomaticAllocation $allocator */
$allocator = $this->container->get('village_allocation.automatic');
// Fake the batch api context.
$context = ['finished' => FALSE];
while (!$context['finished']) {
$allocator->process($this->event, $context);
}
if ($this->debug) {
print_r($context['results']);
}
}
/**
* Deletes all orders.
*/
private function deleteOrders() {
$storage = $this->entityTypeManager->getStorage('commerce_order');
$all = $storage->loadMultiple();
$storage->delete($all);
}
}
