contacts_events-8.x-1.x-dev/modules/accommodation/src/BookingAccommodationHelper.php

modules/accommodation/src/BookingAccommodationHelper.php
<?php

namespace Drupal\contacts_events_accommodation;

use Drupal\commerce_order\Entity\OrderItemInterface;
use Drupal\contacts_events\PriceCalculator;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;

/**
 * Helper for working with accommodation for a booking.
 */
class BookingAccommodationHelper implements BookingAccommodationHelperInterface {

  /**
   * The order items field items we are working with.
   *
   * @var \Drupal\Core\Field\EntityReferenceFieldItemList
   */
  protected $orderItems;

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

  /**
   * The price calculator service.
   *
   * @var \Drupal\contacts_events\PriceCalculator
   */
  protected $priceCalculator;

  /**
   * The number of confirmed delegates.
   *
   * Keys are:
   * - confirmed: The confirmed count.
   * - total: The total count.
   *
   * @var array
   */
  protected $delegates;

  /**
   * The accommodation totals for this order.
   *
   * Outer keys are accommodation ID. Each value is an array containing:
   * - confirmed: The confirmed count.
   * - total: The total count.
   *
   * @var array
   */
  protected $accommodation;

  /**
   * {@inheritdoc}
   */
  public function __construct(EntityReferenceFieldItemListInterface $items, EntityTypeManagerInterface $entity_type_manager, PriceCalculator $price_calculator) {
    $this->orderItems = $items;
    $this->entityTypeManager = $entity_type_manager;
    $this->priceCalculator = $price_calculator;
  }

  /**
   * {@inheritdoc}
   */
  public function getConfirmedDelegates(): int {
    $this->calculateDelegates();
    return $this->delegates['confirmed'];
  }

  /**
   * {@inheritdoc}
   */
  public function getTotalDelegates(): int {
    $this->calculateDelegates();
    return $this->delegates['total'];
  }

  /**
   * Calculate the delegate counts for the order.
   */
  protected function calculateDelegates(): void {
    if (isset($this->delegates)) {
      return;
    }

    $this->delegates = [
      'confirmed' => 0,
      'total' => 0,
    ];

    /** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */
    // phpcs:ignore Drupal.Arrays.Array.LongLineDeclaration
    $order_items = array_filter($this->orderItems->referencedEntities(), [$this, 'filterDelegateOrderItems']);
    foreach ($order_items as $order_item) {
      // All tickets count towards the total.
      $this->delegates['total']++;

      // Non-pending tickets count as confirmed.
      if ($order_item->get('state')->value !== 'pending') {
        $this->delegates['confirmed']++;
      }
    }
  }

  /**
   * Filter delegate order items eligible for accommodation.
   *
   * @param \Drupal\commerce_order\Entity\OrderItemInterface $order_item
   *   The order item.
   *
   * @return bool
   *   Whether the delegate is eligible for accommodation.
   */
  protected function filterDelegateOrderItems(OrderItemInterface $order_item): bool {
    if ($order_item->bundle() != 'contacts_ticket') {
      return FALSE;
    }

    // Cancelled tickets don't count for anything.
    if ($order_item->get('state')->value == 'cancelled') {
      return FALSE;
    }

    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function getConfirmedAccommodation(int $id): int {
    $this->calculateAccommodation();
    return $this->accommodation[$id]['confirmed'] ?? 0;
  }

  /**
   * {@inheritdoc}
   */
  public function getTotalAccommodation(int $id): int {
    $this->calculateAccommodation();
    return $this->accommodation[$id]['total'] ?? 0;
  }

  /**
   * {@inheritdoc}
   */
  public function getAllAccommodation(): array {
    $this->calculateAccommodation();
    return $this->accommodation;
  }

  /**
   * Calculate the accommodation counts for the order.
   */
  protected function calculateAccommodation(): void {
    if (isset($this->accommodation)) {
      return;
    }

    $this->accommodation = [];

    $event_id = $this->orderItems->getEntity()->get('event')->target_id;

    /** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */
    foreach ($this->orderItems->referencedEntities() as $order_item) {
      if (substr($order_item->bundle(), 0, 9) == 'ce_accom_') {
        $accommodation = $order_item->getPurchasedEntity();

        // Make sure it's for the right event. If something has somehow caused
        // the accommodation to be associated with the wrong event we don't
        // want it to count towards the totals.
        if ($accommodation->get('event')->target_id != $event_id) {
          continue;
        }

        $accommodation_id = $order_item->getPurchasedEntityId();
        if (!isset($this->accommodation[$accommodation_id])) {
          $this->accommodation[$accommodation_id] = [
            'total' => 0,
            'confirmed' => 0,
          ];
        }

        switch ($order_item->get('state')->value) {
          case 'confirmed':
          case 'paid_in_full':
            $this->accommodation[$accommodation_id]['confirmed'] += $order_item->getQuantity();

          case 'pending':
            $this->accommodation[$accommodation_id]['total'] += $order_item->getQuantity();
            break;
        }
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function getMaxAllowedAccommodation(AccommodationInterface $accommodation): ?int {
    $min_delegates = $accommodation->getMinDelegates();
    if ($min_delegates) {
      $max_allowed = ceil($this->getTotalDelegates() / $min_delegates);
    }
    elseif (!isset($min_delegates)) {
      $max_allowed = 10;
    }
    else {
      $max_allowed = $this->getTotalDelegates();
    }

    return max($max_allowed, $this->getTotalAccommodation($accommodation->id()));
  }

  /**
   * {@inheritdoc}
   */
  public function updateUnconfirmedItems(array $quantities) {
    $this->calculateAccommodation();
    $modified = [];

    foreach ($quantities as $id => $quantity) {
      $diff = $quantity - $this->getTotalAccommodation((int) $id);
      if ($diff !== 0) {
        $item = $this->getUnconfirmedItem($id);
        $item->setQuantity((int) $item->getQuantity() + $diff);
        if (!$item->isNew()) {
          $modified[$id] = $item;
        }
      }
    }

    // Remove any zero quantity order items. Do this in reverse to avoid re-keys
    // changing our deltas.
    /** @var \Drupal\commerce_order\Entity\OrderItemInterface[] $items */
    $items = array_reverse($this->orderItems->referencedEntities(), TRUE);
    foreach ($items as $delta => $item) {
      if ((int) $item->getQuantity() === 0) {
        $this->orderItems->removeItem($delta);
      }
    }

    return $modified;
  }

  /**
   * Get an order item for unconfirmed accommodation of the given ID.
   *
   * @param int $accommodation_id
   *   The accommodation ID.
   *
   * @return \Drupal\commerce_order\Entity\OrderItemInterface
   *   The unconfirmed order item for the accommodation.
   */
  protected function getUnconfirmedItem(int $accommodation_id) {
    /** @var \Drupal\contacts_events_accommodation\AccommodationInterface $accommodation */
    $accommodation = $this->entityTypeManager
      ->getStorage('c_events_accommodation')
      ->load($accommodation_id);

    // See if we already have a suitable order item.
    /** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */
    foreach ($this->orderItems->referencedEntities() as $order_item) {
      if ($order_item->bundle() == $accommodation->getOrderItemTypeId()) {
        if ($order_item->getPurchasedEntityId() == $accommodation_id && $order_item->get('state')->value == 'pending') {
          return $order_item;
        }
      }
    }

    // Otherwise create a new one and append it.
    /** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */
    $order_item = $this->entityTypeManager
      ->getStorage('commerce_order_item')
      ->createFromPurchasableEntity($accommodation);
    $order_item->setQuantity(0);

    $this->priceCalculator->calculatePrice($order_item);

    $this->orderItems->appendItem($order_item);

    return $order_item;
  }

}

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

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