You are here

protected function Shipping::applyProportional in Commerce Shipping 8.2

Applies each order item's tax rate proportionally.

Logic: 1. Order items are grouped by their tax rates and then summed up. 2. Each group's ratio of the subtotal is calculated. 3. Each group's tax rate is applied to the shipments, multiplied by the ratio and then rounded.

Parameters

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

\Drupal\commerce_order\Adjustment[] $tax_adjustments: The tax adjustments.

1 call to Shipping::applyProportional()
Shipping::apply in src/Plugin/Commerce/TaxType/Shipping.php
Applies the tax type to the given order.

File

src/Plugin/Commerce/TaxType/Shipping.php, line 325

Class

Shipping
Provides the Shipping tax type.

Namespace

Drupal\commerce_shipping\Plugin\Commerce\TaxType

Code

protected function applyProportional(OrderInterface $order, array $tax_adjustments) {
  if (count($tax_adjustments) === 1) {
    $this
      ->applyHighest($order, $tax_adjustments);
    return;
  }

  // Group order items by tax percentage.
  $groups = [];
  foreach ($order
    ->getItems() as $order_item) {
    $order_item_total = $order_item
      ->getTotalPrice();
    $order_item_tax_adjustments = $order_item
      ->getAdjustments([
      'tax',
    ]);
    $order_item_tax_adjustment = reset($order_item_tax_adjustments);
    $percentage = $order_item_tax_adjustment
      ->getPercentage();
    if (!isset($groups[$percentage])) {
      $groups[$percentage] = [
        'order_item_total' => $order_item_total,
        'tax_adjustment' => $order_item_tax_adjustment,
      ];
    }
    else {
      $previous_total = $groups[$percentage]['order_item_total'];
      $previous_adjustment = $groups[$percentage]['tax_adjustment'];
      $groups[$percentage]['order_item_total'] = $previous_total
        ->add($order_item_total);
      $groups[$percentage]['tax_adjustment'] = $previous_adjustment
        ->add($order_item_tax_adjustment);
    }
  }

  // Sort by percentage descending.
  krsort($groups, SORT_NUMERIC);

  // Calculate the ratio of each group.
  $subtotal = $order
    ->getSubtotalPrice()
    ->getNumber();
  foreach ($groups as $percentage => $group) {
    $order_item_total = $group['order_item_total'];

    // If the order item total is zero, the group ratio cannot be
    // properly calculated.
    if ($order_item_total
      ->isZero()) {
      $groups[$percentage]['ratio'] = '0';
      continue;
    }
    $groups[$percentage]['ratio'] = $order_item_total
      ->divide($subtotal)
      ->getNumber();
  }
  foreach ($this
    ->getShipments($order) as $shipment) {
    foreach ($groups as $percentage => $group) {
      $existing_adjustment = $group['tax_adjustment'];
      $display_inclusive = $existing_adjustment
        ->isIncluded();
      $tax_amount = $this
        ->calculateTaxAmount($shipment, $percentage, $display_inclusive);
      $tax_amount = $tax_amount
        ->multiply($group['ratio']);
      $tax_amount = $this->rounder
        ->round($tax_amount);
      $definition = [
        'amount' => $tax_amount,
      ] + $existing_adjustment
        ->toArray();
      $shipment
        ->addAdjustment(new Adjustment($definition));
    }
  }
}