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); } }