contacts_events-8.x-1.x-dev/tests/src/Kernel/TeamBookingStateTransitionTest.php

tests/src/Kernel/TeamBookingStateTransitionTest.php
<?php

namespace Drupal\Tests\contacts_events\Kernel;

use Drupal\commerce_order\Entity\Order;
use Drupal\commerce_order\Entity\OrderItem;
use Drupal\commerce_payment\Entity\Payment;
use Drupal\commerce_price\Price;
use Drupal\contacts_events\Entity\Ticket;
use Drupal\contacts_events_teams\Entity\Team;
use Drupal\contacts_events_teams\Entity\TeamApplication;
use Drupal\contacts_events_teams\Entity\TeamInterface;

/**
 * Test the booking process team transition events.
 *
 * @group contacts_events
 */
class TeamBookingStateTransitionTest extends EventTransitionTestBase {

  /**
   * {@inheritdoc}
   */
  public static $modules = [
    'commerce',
    'commerce_checkout',
    'commerce_order',
    'commerce_price',
    'commerce_payment',
    'commerce_store',
    'contacts',
    'contacts_events',
    'contacts_events_teams',
    'ctools',
    'datetime',
    'datetime_range',
    'decoupled_auth',
    'entity',
    'entity_reference_revisions',
    'facets',
    'field',
    'file',
    'image',
    'name',
    'options',
    'profile',
    'rest',
    'serialization',
    'state_machine',
    'taxonomy',
    'views',
    'views_data_export',
  ];

  /**
   * The default team.
   *
   * @var \Drupal\contacts_events_teams\Entity\Team
   */
  protected $team;

  /**
   * {@inheritdoc}
   */
  protected function getTransitions() {
    return [
      'place',
      'confirm',
      'confirmed_paid_in_full',
      'team_app_in_progress',
      'team_app_back_to_pending',
      'team_payment_undone',
      'paid_in_full',
      'payment_undone',
      'cancel',
    ];
  }

  /**
   * {@inheritdoc}
   */
  protected function setUp() : void {
    parent::setUp();

    // 8.7.x introduced a change to how entities are retrieved in
    // EntityConverter that uses the current user context, but that is not set
    // by default in Kernel tests, so set it explicitly now. However, this
    // method was only introduced in 8.7.x, so we need to check it exists first.
    // If it doesn't, we are <8.7 and therefore don't need it.
    // @todo Remove this if https://drupal.org/node/3063236 gets a better fix.
    if (method_exists($this, 'setUpCurrentUser')) {
      $this->setUpCurrentUser(['uid' => 0]);
    }
  }

  /**
   * {@inheritdoc}
   */
  protected function cachedSetup() {
    parent::cachedSetup();
    $this->installEntitySchema('c_events_team');
    $this->installEntitySchema('c_events_team_app');
    $this->installEntitySchema('contacts_ticket');
    $this->installConfig('commerce_payment');
    $this->installConfig('contacts_events');
    $this->installConfig('contacts_events_teams');

    $contacts_events_config = $this->container->get('config.factory')->getEditable('contacts_events.booking_settings');
    $contacts_events_config->set('store_id', $this->store->id())->save();

    $this->team = Team::create([
      'id' => 1,
      'name' => 'Other Team 101',
      'event' => $this->event->id(),
    ]);
    $this->team->save();
  }

  /**
   * {@inheritdoc}
   */
  protected function uncachedSetup() {
    parent::uncachedSetup();
    $this->team = Team::load(1);
  }

  /**
   * {@inheritdoc}
   */
  protected function getEventData() {
    return [
      'type' => 'default',
      'id' => 101,
      'title' => 'Other Event 101',
      'settings' => [
        'teams' => ['enabled' => TeamInterface::STATUS_OPEN],
      ],
    ];
  }

  /**
   * Test checks order item transitions for the process of placing an order.
   *
   * @dataProvider dataOnOrderPlaced
   */
  public function testOrderPlacedTransitions($is_team, $ticket_state_before, $order_status_paid, $ticket_state_after, $transition, $additional) {
    $user = $this->createUser();
    $user->save();

    /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
    $entity_type_manager = $this->container->get('entity_type.manager');
    $order_storage = $entity_type_manager->getStorage('commerce_order');
    $order_item_storage = $entity_type_manager->getStorage('commerce_order_item');

    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = Order::create([
      'type' => 'contacts_booking',
      'order_id' => 101,
      'store_id' => $this->store,
      'state' => 'draft',
      'event' => $this->event->id(),
    ]);
    $order->save();

    // Create the payment before adding line items so we don't trigger state
    // changes earlier than desired.
    if ($order_status_paid) {
      Payment::create([
        'type' => 'payment_default',
        'payment_gateway' => $this->gateway->id(),
        'order_id' => $order->id(),
        'state' => 'completed',
        'amount' => new Price('10', 'USD'),
      ])->save();

      // Reload the order so we have the update total paid.
      $order = $order_storage->loadUnchanged($order->id());
    }

    $ticket = Ticket::create([
      'type' => 'contacts_ticket',
      'price' => new Price('10', 'USD'),
      'event' => $this->event->id(),
      'mapped_price' => [
        'booking_window' => 'standard',
        'class' => 'standard',
      ],
      'contact' => $user,
    ]);
    if ($is_team) {
      $ticket->set('is_team_ticket', TRUE);
      $ticket->set('team', $this->team->id());
    }
    $ticket->save();

    // Create our order item.
    $order_item = OrderItem::create([
      'type' => 'contacts_ticket',
      'state' => $ticket_state_before,
      'unit_price' => new Price('10', 'USD'),
      'mapped_price' => [
        'booking_window' => 'standard',
        'class' => 'standard',
      ],
      'order_id' => $order,
    ]);
    $order_item->set('purchased_entity', $ticket->id());
    $order_item->save();

    // Join everything together.
    $ticket->set('order_item', $order_item)->save();
    $order->addItem($order_item)->save();

    // Clear any previous events.
    $this->triggeredEvents = [];
    $this->triggeredEventsByGroup = [];

    // Start transition.
    $order = $order_storage->loadUnchanged($order->id());
    $order->getState()->applyTransitionById('place');
    $order->save();

    if (!empty($transition)) {
      $this->checkTransitions($transition, $additional);
    }
    else {
      static::assertTrue(!isset($this->triggeredEventsByGroup['contacts_events_order_items']), 'No transitions expected.');
    }

    // Check new ticket state.
    $order_item = $order_item_storage->loadUnchanged($order_item->id());
    static::assertEquals($ticket_state_after, $order_item->get('state')->value);
  }

  /**
   * Data provider for testOrderPlacedTransitions.
   */
  public function dataOnOrderPlaced() {
    // GROUP 1:  Ticket in pending status.
    $data['non_team_pending_not_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'pending',
      'order_status' => FALSE,
      'ticket_state_after' => 'confirmed',
      'transition' => 'confirm',
      'additional' => [],
    ];
    $data['non_team_pending_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'pending',
      'order_status' => TRUE,
      'ticket_state_after' => 'paid_in_full',
      'transition' => 'confirmed_paid_in_full',
      'additional' => ['confirm', 'paid_in_full'],
    ];
    $data['team_pending_not_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'pending',
      'order_status' => FALSE,
      'ticket_state_after' => 'team_app_in_progress',
      'transition' => 'team_app_in_progress',
      'additional' => ['confirm'],
    ];
    $data['team_pending_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'pending',
      'order_status' => TRUE,
      'ticket_state_after' => 'team_app_in_progress',
      'transition' => 'team_app_in_progress',
      'additional' => ['confirm'],
    ];

    // GROUP 2:  Ticket in confirmed status.
    $data['non_team_confirmed_not_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'confirmed',
      'order_status' => FALSE,
      'ticket_state_after' => 'confirmed',
      'transition' => '',
      'additional' => [],
    ];

    // We are ignoring non_team_confirmed_paid as it is an invalid scenario.
    // If the order is paid in full then the ticket should be as well, not
    // confirmed.
    // Team tickets should never be in the confirmed state.
    // GROUP 3: Ticket in team_app_in_progress status.
    // Non team tickets should never be in the team_app_in_progress state.
    $data['team_team_app_in_progress_not_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'team_app_in_progress',
      'order_status' => FALSE,
      'ticket_state_after' => 'team_app_in_progress',
      'transition' => '',
      'additional' => [],
    ];
    $data['team_team_app_in_progress_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'team_app_in_progress',
      'order_status' => TRUE,
      'ticket_state_after' => 'team_app_in_progress',
      'transition' => '',
      'additional' => [],
    ];

    // GROUP 4: Ticket in paid_in_full status.
    $data['non_team_paid_in_full_not_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'paid_in_full',
      'order_status' => FALSE,
      'ticket_state_after' => 'confirmed',
      'transition' => 'payment_undone',
      'additional' => [],
    ];
    $data['non_team_paid_in_full_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'paid_in_full',
      'order_status' => TRUE,
      'ticket_state_after' => 'paid_in_full',
      'transition' => '',
      'additional' => [],
    ];
    $data['team_paid_in_full_not_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'paid_in_full',
      'order_status' => FALSE,
      'ticket_state_after' => 'team_app_in_progress',
      'transition' => 'team_payment_undone',
      'additional' => [],
    ];
    $data['team_paid_in_full_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'paid_in_full',
      'order_status' => TRUE,
      'ticket_state_after' => 'paid_in_full',
      'transition' => '',
      'additional' => [],
    ];

    // GROUP 4: Ticket in cancelled status.
    $data['non_team_cancelled_not_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'cancelled',
      'order_status' => FALSE,
      'ticket_state_after' => 'cancelled',
      'transition' => '',
      'additional' => [],
    ];
    $data['non_team_cancelled_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'cancelled',
      'order_status' => TRUE,
      'ticket_state_after' => 'cancelled',
      'transition' => '',
      'additional' => [],
    ];
    $data['team_cancelled_not_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'cancelled',
      'order_status' => FALSE,
      'ticket_state_after' => 'cancelled',
      'transition' => '',
      'additional' => [],
    ];
    $data['team_cancelled_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'cancelled',
      'order_status' => TRUE,
      'ticket_state_after' => 'cancelled',
      'transition' => '',
      'additional' => [],
    ];

    return $data;
  }

  /**
   * Test checks order item transitions for the process of placing an order.
   *
   * @dataProvider dataOnPaymentMade
   */
  public function testPaymentMadeTransitions($is_team, $ticket_state_before, $order_status_paid, $ticket_state_after, $transition = NULL, $additional = [], $team_app_approved = FALSE) {
    /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
    $entity_type_manager = $this->container->get('entity_type.manager');
    $order_item_storage = $entity_type_manager->getStorage('commerce_order_item');

    $ticket = Ticket::create([
      'type' => 'contacts_ticket',
      'price' => new Price('10', 'USD'),
      'event' => $this->event->id(),
      'mapped_price' => [
        'booking_window' => 'standard',
        'class' => 'standard',
      ],
    ]);
    if ($is_team) {
      $ticket->set('is_team_ticket', TRUE);
      $ticket->set('team', $this->team->id());
    }
    $ticket->save();

    if ($team_app_approved) {
      TeamApplication::create([
        'type' => 'standard',
        'ticket' => $ticket->id(),
        'state' => 'approved',
      ])->save();
    }

    $order_item = OrderItem::create([
      'type' => 'contacts_ticket',
      'state' => $ticket_state_before,
      'unit_price' => new Price('10', $this->store->getDefaultCurrencyCode()),
      'mapped_price' => [
        'booking_window' => 'standard',
        'class' => 'standard',
      ],
    ]);
    $order_item->set('purchased_entity', $ticket->id());
    $order_item->save();

    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = Order::create([
      'type' => 'contacts_booking',
      'store_id' => $this->store,
      'order_items' => [$order_item],
      'state' => 'draft',
      'event' => $this->event->id(),
    ]);
    $order->save();

    $payment_amount = $order->getTotalPrice();

    if (!$order_status_paid) {
      $payment_amount = $payment_amount->subtract(new Price('1', $this->store->getDefaultCurrencyCode()));
    }

    // Clear any previous events.
    $this->triggeredEvents = [];
    $this->triggeredEventsByGroup = [];

    // Make the payment.
    Payment::create([
      'type' => 'payment_default',
      'payment_gateway' => $this->gateway->id(),
      'order_id' => $order->id(),
      'state' => 'completed',
      'amount' => $payment_amount,
    ])->save();

    // Trigger the order update to apply transitions.
    $this->container->get('commerce_payment.order_updater')->updateOrder($order, TRUE);

    if (!empty($transition)) {
      $this->checkTransitions($transition, $additional);
    }
    else {
      static::assertTrue(!isset($this->triggeredEventsByGroup['contacts_events_order_items']));
    }

    // Check new ticket state.
    $order_item = $order_item_storage->loadUnchanged($order_item->id());
    static::assertEquals($order_item->get('state')->value, $ticket_state_after);
  }

  /**
   * Data provider for testPaymentMadeTransitions.
   */
  public function dataOnPaymentMade() {
    // GROUP 1:  Ticket in pending status.
    $data['non_team_pending_not_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'pending',
      'order_status' => FALSE,
      'ticket_state_after' => 'pending',
      'transition' => '',
      'additional' => [],
    ];
    $data['non_team_pending_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'pending',
      'order_status' => TRUE,
      'ticket_state_after' => 'pending',
      'transition' => '',
      'additional' => [],
    ];
    $data['team_pending_not_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'pending',
      'order_status' => FALSE,
      'ticket_state_after' => 'pending',
      'transition' => '',
      'additional' => [],
    ];
    $data['team_pending_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'pending',
      'order_status' => TRUE,
      'ticket_state_after' => 'pending',
      'transition' => '',
      'additional' => [],
    ];

    // GROUP 2:  Ticket in confirmed status.
    $data['non_team_confirmed_not_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'confirmed',
      'order_status' => FALSE,
      'ticket_state_after' => 'confirmed',
      'transition' => '',
      'additional' => [],
    ];

    // We are ignoring non_team_confirmed_paid as it is an invalid scenario.
    // If the order is paid in full then the ticket should be as well, not
    // confirmed.
    // Team tickets should never be in the confirmed state.
    // GROUP 3:  Ticket in team_app_in_progress status.
    $data['team_app_in_progress_not_paid_not_approved'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'team_app_in_progress',
      'order_status' => FALSE,
      'ticket_state_after' => 'team_app_in_progress',
      'transition' => '',
      'additional' => [],
    ];
    $data['team_team_app_in_progress_paid_not_approved'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'team_app_in_progress',
      'order_status' => TRUE,
      'ticket_state_after' => 'team_app_in_progress',
      'transition' => '',
      'additional' => [],
    ];
    $data['team_team_app_in_progress_not_paid_approved'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'team_app_in_progress',
      'order_status' => FALSE,
      'ticket_state_after' => 'team_app_in_progress',
      'transition' => '',
      'additional' => [],
      'team_app_approved' => TRUE,
    ];
    $data['team_team_app_in_progress_paid_approved'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'team_app_in_progress',
      'order_status' => TRUE,
      'ticket_state_after' => 'paid_in_full',
      'transition' => 'paid_in_full',
      'additional' => [],
      'team_app_approved' => TRUE,
    ];

    // GROUP 4:  Ticket in paid_in_full status.
    $data['non_team_paid_in_full_not_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'paid_in_full',
      'order_status' => FALSE,
      'ticket_state_after' => 'confirmed',
      'transition' => 'payment_undone',
      'additional' => [],
    ];
    $data['non_team_paid_in_full_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'paid_in_full',
      'order_status' => TRUE,
      'ticket_state_after' => 'paid_in_full',
      'transition' => '',
      'additional' => [],
    ];
    $data['team_paid_in_full_not_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'paid_in_full',
      'order_status' => FALSE,
      'ticket_state_after' => 'team_app_in_progress',
      'transition' => 'team_payment_undone',
      'additional' => [],
    ];
    $data['team_paid_in_full_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'paid_in_full',
      'order_status' => TRUE,
      'ticket_state_after' => 'paid_in_full',
      'transition' => '',
      'additional' => [],
    ];

    // GROUP 5:  Ticket in cancelled status.
    $data['non_team_cancelled_not_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'cancelled',
      'order_status' => FALSE,
      'ticket_state_after' => 'cancelled',
      'transition' => '',
      'additional' => [],
    ];
    $data['non_team_cancelled_paid'] = [
      'is_team' => FALSE,
      'ticket_state_before' => 'cancelled',
      'order_status' => TRUE,
      'ticket_state_after' => 'cancelled',
      'transition' => '',
      'additional' => [],
    ];
    $data['team_cancelled_not_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'cancelled',
      'order_status' => FALSE,
      'ticket_state_after' => 'cancelled',
      'transition' => '',
      'additional' => [],
    ];
    $data['team_cancelled_paid'] = [
      'is_team' => TRUE,
      'ticket_state_before' => 'cancelled',
      'order_status' => TRUE,
      'ticket_state_after' => 'cancelled',
      'transition' => '',
      'additional' => [],
    ];

    return $data;
  }

  /**
   * Test checks order item transitions for the process of placing an order.
   *
   * @dataProvider dataOnCancelTicket
   */
  public function testCancelTicketTransitions($trigger_transition, $is_team, $ticket_state_before, $order_status_paid, $ticket_state_after, $transition = NULL, $additional = []) {
    /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
    $entity_type_manager = $this->container->get('entity_type.manager');
    $order_item_storage = $entity_type_manager->getStorage('commerce_order_item');
    $ticket_storage = $entity_type_manager->getStorage('contacts_ticket');

    $ticket = Ticket::create([
      'type' => 'contacts_ticket',
      'price' => new Price('10', 'USD'),
      'event' => $this->event->id(),
      'mapped_price' => [
        'booking_window' => 'standard',
        'class' => 'standard',
      ],
    ]);
    if ($is_team) {
      $ticket->set('is_team_ticket', TRUE);
      $ticket->set('team', $this->team->id());
    }
    $ticket->save();

    $order_item = OrderItem::create([
      'type' => 'contacts_ticket',
      'state' => $ticket_state_before,
      'unit_price' => new Price('10', $this->store->getDefaultCurrencyCode()),
      'mapped_price' => [
        'booking_window' => 'standard',
        'class' => 'standard',
      ],
    ]);
    $order_item->set('purchased_entity', $ticket->id());
    $order_item->save();

    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = Order::create([
      'type' => 'contacts_booking',
      'store_id' => $this->store,
      'order_items' => [$order_item],
      'state' => 'draft',
      'event' => $this->event->id(),
    ]);
    $order->save();

    if ($order_status_paid) {
      Payment::create([
        'type' => 'payment_default',
        'payment_gateway' => $this->gateway->id(),
        'order_id' => $order->id(),
        'state' => 'completed',
        'amount' => $order->getTotalPrice(),
      ])->save();
    }

    // Clear any previous events.
    $this->triggeredEvents = [];
    $this->triggeredEventsByGroup = [];

    // Start transition.
    $order_item = $order_item_storage->loadUnchanged($order_item->id());
    $order_item->get('state')->first()->applyTransitionById($trigger_transition);
    $order_item->save();

    if (!empty($transition)) {
      $this->checkTransitions($transition, $additional);
    }
    else {
      static::assertTrue(!isset($this->triggeredEventsByGroup['contacts_events_order_items']));
    }

    // Check new ticket state.
    $order_item = $order_item_storage->loadUnchanged($order_item->id());
    static::assertEquals($order_item->get('state')->value, $ticket_state_after);

    if ($is_team) {
      $ticket = $ticket_storage->loadUnchanged($ticket->id());
      static::assertNull($ticket->get('is_team_ticket')->value);
      static::assertNull($ticket->get('team')->value);
    }
  }

  /**
   * Data provider for testCancelTicketTransitions.
   */
  public function dataOnCancelTicket() {
    // GROUP 1:  Ticket in cancel transition.
    $data['non_team_confirmed'] = [
      'trigger_transition' => 'cancel',
      'is_team' => FALSE,
      'ticket_state_before' => 'confirmed',
      'order_status' => FALSE,
      'ticket_state_after' => 'cancelled',
      'transition' => 'cancel',
      'additional' => [],
    ];
    $data['non_team_paid_in_full'] = [
      'trigger_transition' => 'cancel',
      'is_team' => FALSE,
      'ticket_state_before' => 'paid_in_full',
      'order_status' => TRUE,
      'ticket_state_after' => 'cancelled',
      'transition' => 'cancel',
      'additional' => [],
    ];
    $data['team_paid_in_full'] = [
      'trigger_transition' => 'cancel',
      'is_team' => TRUE,
      'ticket_state_before' => 'paid_in_full',
      'order_status' => TRUE,
      'ticket_state_after' => 'cancelled',
      'transition' => 'cancel',
      'additional' => [],
    ];

    // GROUP 2:  Ticket in team_app_back_to_pending transition.
    $data['team_app_in_progress'] = [
      'trigger_transition' => 'team_app_back_to_pending',
      'is_team' => TRUE,
      'ticket_state_before' => 'team_app_in_progress',
      'order_status' => FALSE,
      'ticket_state_after' => 'pending',
      'transition' => 'team_app_back_to_pending',
      'additional' => [],
    ];
    $data['paid_in_full'] = [
      'trigger_transition' => 'team_app_back_to_pending',
      'is_team' => TRUE,
      'ticket_state_before' => 'paid_in_full',
      'order_status' => TRUE,
      'ticket_state_after' => 'pending',
      'transition' => 'team_app_back_to_pending',
      'additional' => [],
    ];

    return $data;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc