You are here

public function CurrencyOrderProcessor::process in Commerce Currency Resolver 8

Processes an order.

Parameters

\Drupal\commerce_order\Entity\OrderInterface $order: The order.

Overrides OrderProcessorInterface::process

File

src/CurrencyOrderProcessor.php, line 51

Class

CurrencyOrderProcessor
Apply currency changes during the order refresh process.

Namespace

Drupal\commerce_currency_resolver

Code

public function process(OrderInterface $order) {

  // Skip processor if we should not refresh currency.
  if (!$this
    ->shouldCurrencyRefresh($order)) {
    return;
  }

  // Get main currency.
  $resolved_currency = $this->currentCurrency
    ->getCurrency();

  // Get order total.
  // Triggered on event order load to ensure that new currency and prices
  // are properly saved.
  // @see \Drupal\commerce_currency_resolver\EventSubscriber\OrderCurrencyRefresh
  if (($total = $order
    ->getTotalPrice()) && $total
    ->getCurrencyCode() !== $resolved_currency) {

    // Get order items.
    $items = $order
      ->getItems();

    // Loop trough all order items and find ones without PurchasableEntity
    // They need to automatically converted.
    foreach ($items as $item) {

      /** @var \Drupal\commerce_order\Entity\OrderItem $item */
      if (!$item
        ->hasPurchasedEntity()) {
        $price = $item
          ->getUnitPrice();

        // Auto calculate price.
        $item
          ->setUnitPrice($this->priceExchanger
          ->priceConversion($price, $resolved_currency));
      }
    }

    // Last part is handling adjustments. We could hit here to
    // recalculateTotalPrice(), so it makes sense to run it last.
    $new_adjustments = [];
    $reset_adjustments = FALSE;

    // Handle custom adjustments.
    if ($adjustments = $order
      ->getAdjustments()) {
      foreach ($adjustments as $adjustment) {
        assert($adjustment instanceof Adjustment);
        $adjustment_currency = $adjustment
          ->getAmount()
          ->getCurrencyCode();

        // We should only dealt with locked adjustment.
        // Any non locked have their order processor implementation
        // probably.
        if ($adjustment
          ->isLocked() && $adjustment_currency !== $resolved_currency) {
          $reset_adjustments = TRUE;
          $adjustment_amount = $adjustment
            ->getAmount();
          $values = $adjustment
            ->toArray();

          // Auto calculate price.
          $values['amount'] = $this->priceExchanger
            ->priceConversion($adjustment_amount, $resolved_currency);
          $new_adjustment = new Adjustment($values);
          $new_adjustments[] = $new_adjustment;
        }
      }

      // We have custom adjustments which need to be recalculated.
      if ($reset_adjustments) {

        // We need clear adjustments like that while using
        // $order->removeAdjustment() will trigger recalculateTotalPrice()
        // which will break everything, while currencies are different.
        $order
          ->set('adjustments', []);
        foreach ($new_adjustments as $new_adjustment) {
          $order
            ->addAdjustment($new_adjustment);
        }
      }
    }

    // Flag for recalculating order. If we had custom adjustments for
    // conversion we already hit recalculateTotalPrice() with
    // $order->addAdjustment($new_adjustment), so no need again.
    if (!$reset_adjustments) {

      // Get new total price.
      $order = $order
        ->recalculateTotalPrice();
    }

    // Use as flag for our submodules order processors.
    $order
      ->setData(CurrencyHelper::CURRENCY_ORDER_REFRESH, TRUE);

    // Save order.
    $order
      ->save();
  }
}