contacts_events-8.x-1.x-dev/src/OrderItemStateTrait.php

src/OrderItemStateTrait.php
<?php

namespace Drupal\contacts_events;

use Drupal\commerce_order\Entity\OrderItemInterface;
use Drupal\commerce_partial_payments\OrderItemTrackingInterface;
use Drupal\state_machine\Plugin\Workflow\WorkflowState;

/**
 * Trait for common order item state checks and processes.
 */
trait OrderItemStateTrait {

  /**
   * The order item tracking service, if available.
   *
   * @var \Drupal\commerce_partial_payments\OrderItemTrackingInterface|null
   */
  protected $orderItemTracking;

  /**
   * Set the order item tracking service.
   *
   * @param \Drupal\commerce_partial_payments\OrderItemTrackingInterface $tracking
   *   The tracking service.
   *
   * @return $this
   */
  public function setOrderItemTracking(OrderItemTrackingInterface $tracking) {
    $this->orderItemTracking = $tracking;
    return $this;
  }

  /**
   * Check the status of an order item, applying a transition as required.
   *
   * @param \Drupal\commerce_order\Entity\OrderItemInterface $order_item
   *   The order item.
   *
   * @return bool
   *   Whether the state was changed.
   */
  protected function checkOrderItemStatus(OrderItemInterface $order_item): bool {
    if (!$order_item->hasField('state')) {
      return FALSE;
    }

    /** @var \Drupal\state_machine\Plugin\Field\FieldType\StateItemInterface $state */
    $state = $order_item->get('state')->first();

    // Never automatically confirm or un-cancel an order item.
    if (in_array($state->value, ['pending', 'cancelled'])) {
      return FALSE;
    }

    // We can't do anything if the item doesn't have an order.
    $order = $order_item->getOrder();
    if (!$order) {
      return FALSE;
    }

    // Avoid running expensive database queries if there are no possible
    // transitions by checking the transitions first.
    $transitions = $state->getWorkflow()->getAllowedTransitions($state->getOriginalId() ?? $state->getId(), $order_item);

    $paid_transition = $unpaid_transition = FALSE;
    foreach ($transitions as $transition) {
      // Always skip any transition to pending or cancelled.
      // phpcs:ignore Drupal.Arrays.Array.LongLineDeclaration
      if (in_array($transition->getToState()->getId(), ['pending', 'cancelled'])) {
        continue;
      }

      // See if this is a transition to paid in full.
      if ($transition->getToState()->getId() == 'paid_in_full') {
        $paid_transition = $transition->getId();
      }
      // Otherwise, see if it's a transition away from paid in full.
      else {
        $from_states = array_map(function (WorkflowState $state) {
          return $state->getId();
        }, $transition->getFromStates());
        if (in_array('paid_in_full', $from_states)) {
          $unpaid_transition = $transition->getId();
        }
      }

      // If we have both transitions, break.
      if ($paid_transition && $unpaid_transition) {
        break;
      }
    }

    // If we don't have either transition, return now.
    if (!$paid_transition && !$unpaid_transition) {
      return FALSE;
    }

    // Now we need to check whether the item is paid in full.
    $transition = $this->isOrderItemPaidInFull($order_item) ? $paid_transition : $unpaid_transition;

    // If there is no transition, there's nothing to do.
    if (!$transition) {
      return FALSE;
    }

    // Make sure that the sate item is back in its original state before
    // applying the transition.
    if ($state->getOriginalId()) {
      $state->value = $state->getOriginalId();
    }

    // Otherwise apply it and indicate we've made a change.
    $state->applyTransitionById($transition);
    return TRUE;
  }

  /**
   * Check if an order item is paid in full.
   *
   * @param \Drupal\commerce_order\Entity\OrderItemInterface $order_item
   *   The order item.
   *
   * @return bool
   *   Whether the order item is paid in full.
   */
  protected function isOrderItemPaidInFull(OrderItemInterface $order_item): bool {
    // Start simply by seeing if the order itself is paid in full.
    $order_balance = $order_item->getOrder()->getBalance();
    if (!$order_balance || $order_balance->isZero() || $order_balance->isNegative()) {
      return TRUE;
    }
    // If we have order item tracking, we can check the specific item.
    elseif ($this->orderItemTracking) {
      $total = $order_item->getAdjustedTotalPrice();

      // Zero or negative value will always be paid in full.
      if (!$total || $total->isZero() || $total->isNegative()) {
        return TRUE;
      }
      // Otherwise, look up the tracked amount.
      else {
        $tracking = $this->orderItemTracking->getTrackedAmountsForItem($order_item->id());
        return $tracking && $tracking->greaterThanOrEqual($total);
      }
    }

    // Otherwise, we must assume it's not paid in full.
    return FALSE;
  }

}

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

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