Commit bcec88fa authored by maxwellkeeble's avatar maxwellkeeble Committed by Pedro Cambra
Browse files

Issue #3218870 by maxwellkeeble: Can't create tickets with product title longer than 50

parent a9fbd9a3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -199,7 +199,7 @@ class OrderEventSubscriber implements EventSubscriberInterface {
            for ($i = $current_quantity; $i < $quantity; $i++) {
              $ticket = CommerceTicket::create(
                [
                  'name' => $this->t('Ticket') . ' ' . $purchased_entity->label(),
                  'name' => substr($this->t('Ticket') . ' ' . $purchased_entity->label(), 0, 50),
                  'bundle' => $ticket_type,
                  'state' => $default_state,
                  'uid' => $order->get('uid'),
+314 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\commerce_ticketing\EventSubscriber;

use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_order\Entity\OrderType;
use Drupal\commerce_order\Event\OrderEvent;
use Drupal\commerce_product\Entity\ProductVariationType;
use Drupal\commerce_ticketing\Entity\CommerceTicket;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\state_machine\Event\WorkflowTransitionEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\Core\Queue\QueueFactory;

class OrderEventSubscriber implements EventSubscriberInterface {

  use StringTranslationTrait;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Lock service.
   *
   * @var \Drupal\Core\Lock\LockBackendInterface
   */
  protected $lock;

  /**
   * Logger.
   *
   * @var \Drupal\Core\Logger\LoggerChannelInterface
   */
  protected $logger;

  /**
   * The commerce_ticketing_send_ticket_receipt_worker queue.
   *
   * @var \Drupal\Core\Queue\QueueInterface
   */
  protected $queue;

  /**
   * Constructs a new TicketNumberSubscriber object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, LockBackendInterface $lock, LoggerChannelInterface $logger, QueueFactory $queue_factory) {
    $this->entityTypeManager = $entity_type_manager;
    $this->lock = $lock;
    $this->logger = $logger;
    $this->queue = $queue_factory->get('commerce_ticketing_send_ticket_receipt_worker');
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      'commerce_order.place.post_transition' => ['onPlaceTransition'],
      'commerce_order.validate.post_transition' => ['onValidateTransition'],
      'commerce_order.fulfill.post_transition' => ['onFulfillTransition'],
      'commerce_order.cancel.post_transition' => ['onCancelTransition'],
      'commerce_order.commerce_order.presave' => ['onOrderPresave', -100],
    ];
  }

  /**
   * Create the order's tickets when the order is placed.
   *
   * @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event
   *   The transition event.
   */
  public function onPlaceTransition(WorkflowTransitionEvent $event) {
    // phpcs:disable
    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = $event->getEntity();
    // phpcs:enable
  }

  /**
   * Create the order's tickets when the order is validated.
   *
   * @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event
   *   The transition event.
   */
  public function onValidateTransition(WorkflowTransitionEvent $event) {
    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = $event->getEntity();
    $this->autoActivateTickets($order);
  }

  /**
   * Create the order's tickets when the order is fulfilled.
   *
   * @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event
   *   The transition event.
   */
  public function onFulfillTransition(WorkflowTransitionEvent $event) {
    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = $event->getEntity();
    $this->autoActivateTickets($order);
  }

  /**
   * Cancels the order's tickets when the order is canceled.
   *
   * @param \Drupal\state_machine\Event\WorkflowTransitionEvent $event
   *   The transition event.
   */
  public function onCancelTransition(WorkflowTransitionEvent $event) {
    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = $event->getEntity();
    $this->cancelTickets($order);
  }

  /**
   * Event listener for order presave event.
   *
   * @param \Drupal\commerce_order\Event\OrderEvent $orderEvent
   *   The order event.
   */
  public function onOrderPresave(OrderEvent $orderEvent) {
    $order = $orderEvent->getOrder();

    // Allow other modules to abort the ticket creation.
    if (!empty($order->ignore_update)) {
      return;
    }

    // Automatically create tickets for all placed orders.
    if ($order->getState()->getId() != 'draft') {
      // Only proceed, if order is paid.
      if ($order->isPaid()) {
        $this->createTickets($order);
        $this->autoActivateTickets($order);

        $order_type_storage = $this->entityTypeManager->getStorage('commerce_order_type');
        /** @var \Drupal\commerce_order\Entity\OrderTypeInterface $order_type */
        $order_type = $order_type_storage->load($order->bundle());
        if ($order_type->getThirdPartySetting('commerce_ticketing', 'send_ticket_mail')) {
          $this->sendTicketMails($order);
        }
      }
    }

  }

  /**
   * Create tickets for all relevant line items.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $order
   */
  private function createTickets(OrderInterface $order) {
    $line_items = $order->getItems();
    $existing_tickets = $order->get('tickets')->referencedEntities();
    $sorted_tickets = [];

    /** @var CommerceTicket $existing_ticket */
    foreach ($existing_tickets as $existing_ticket) {
      if (!empty($item_id = $existing_ticket->getOrderItemId())) {
        $sorted_tickets[] = $item_id;
      }
    }
    $sorted_tickets = array_count_values($sorted_tickets);

    foreach ($line_items as $line_item) {
      $purchased_entity = $line_item->getPurchasedEntity();
      if (!empty($purchased_entity)) {
        /** @var ProductVariationType $variation_type */
        $variation_type = ProductVariationType::load($purchased_entity->bundle());
        /** @var OrderType $order_type */
        $order_type = OrderType::load($order->bundle());
        $ticket_type = $order_type->getThirdPartySetting('commerce_ticketing', 'ticket_type');
        $order_state = $variation_type->getThirdPartySetting('commerce_ticketing', 'order_state');
        $auto_create_ticket = $variation_type->getThirdPartySetting('commerce_ticketing', 'auto_create_ticket');
        $auto_activate_ticket = $variation_type->getThirdPartySetting('commerce_ticketing', 'auto_activate_ticket');

        $default_state = 'created';
        if ($auto_activate_ticket && $order->getState()->getId() == $order_state) {
          $default_state = 'active';
        }

        if (!empty($ticket_type) && $auto_create_ticket) {
          // Create multiple tickets per line item.
          $quantity = $line_item->getQuantity();
          $current_quantity = !empty($sorted_tickets[$line_item->id()]) ? $sorted_tickets[$line_item->id()] : 0;

          if (empty($sorted_tickets[$line_item->id()]) || $current_quantity < $quantity) {

            for ($i = $current_quantity; $i < $quantity; $i++) {
              $ticket = CommerceTicket::create(
                [
                  'name' => $this->t('Ticket') . ' ' . $purchased_entity->label(),
                  'bundle' => $ticket_type,
                  'state' => $default_state,
                  'uid' => $order->get('uid'),
                  'order_id' => $order->id(),
                  'order_item_id' => $line_item->id(),
                ]
              );
              $ticket->save();
            }
          }
        }
      }
    }

    // Update backreference on order.
    $storage = $this->entityTypeManager->getStorage('commerce_ticket');
    $ticket_ids = $storage->getQuery()
      ->condition('order_id', $order->id())
      ->sort('id')
      ->execute();

    $order->set('tickets', $ticket_ids);

  }

  /**
   * Activate tickets.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $order
   *
   */
  private function autoActivateTickets(OrderInterface $order) {
    $existing_tickets = $order->get('tickets')->referencedEntities();
    /** @var \Drupal\commerce_ticketing\CommerceTicketInterface $ticket */
    foreach ($existing_tickets as $ticket) {
      if ($ticket->getPurchasedEntity()) {
        $variation_type = ProductVariationType::load($ticket->getPurchasedEntity()->bundle());
        $order_state = $variation_type->getThirdPartySetting('commerce_ticketing', 'order_state');
        $auto_activate_ticket = $variation_type->getThirdPartySetting('commerce_ticketing', 'auto_activate_ticket');
        if ($auto_activate_ticket && $order->getState()->getId() == $order_state && $ticket->getState()->getId() == 'created') {
          $ticket_state = $ticket->getState();
          $ticket_state_transitions = $ticket_state->getTransitions();
          $ticket_state->applyTransition($ticket_state_transitions['activate']);
          $ticket->save();
        }
      }
    }
  }

  /**
   * Send a ticket mail for each ticket of the order.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $order
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  private function sendTicketMails(OrderInterface $order) {
    $order_item_storage = \Drupal::entityTypeManager()->getStorage('commerce_order_item');
    $tickets = $order->get('tickets')->referencedEntities();

    /** @var \Drupal\commerce_ticketing\CommerceTicketInterface $ticket */
    foreach ($tickets as $ticket) {
      $current_state = $ticket->getState()->getId();
      /** @var \Drupal\commerce_order\Entity\OrderItem $order_item */
      $order_item = $order_item_storage->load($ticket->get('order_item_id')->getValue()[0]['target_id']);

      $is_sent = isset($order_item->getData('ticket_mail_sent')[$ticket->id()]) && $order_item->getData('ticket_mail_sent')[$ticket->id()];
      $is_added_to_queue = isset($order_item->getData('added_to_queue')[$ticket->id()]) && $order_item->getData('added_to_queue')[$ticket->id()];
      $skip_sending = $order_item->getData('skip_ticket_mail');

      // Try to send an email with attachment.
      if ($ticket && $current_state == 'active' && !$is_sent && !$is_added_to_queue && !$skip_sending) {
        $this->queue->createItem($ticket);

        $added_to_queue_order_item_data = $order_item->getData('added_to_queue');
        $added_to_queue_order_item_data[$ticket->id()] = TRUE;
        $order_item->setData('added_to_queue', $added_to_queue_order_item_data);
      }
    }
  }

  /**
   * Cancel all related tickets.
   *
   * @param \Drupal\commerce_order\Entity\OrderInterface $order
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  private function cancelTickets(OrderInterface $order) {
    // Cancel all related tickets
    $storage = $this->entityTypeManager->getStorage('commerce_ticket');
    $ticket_ids = $storage->getQuery()
      ->condition('order_id', $order->id())
      ->sort('id')
      ->execute();

    $tickets = $storage->loadMultiple($ticket_ids);
    foreach ($tickets as $ticket) {
      $ticket_state = $ticket->getState();
      $ticket_state_transitions = $ticket_state->getTransitions();
      if (!empty($ticket_state_transitions['cancel'])) {
        $ticket_state->applyTransition($ticket_state_transitions['cancel']);
        $ticket->save();
      }
    }

  }

}