public function PriceSplitter::split in Commerce Core 8.2
Splits the given amount across order items.
Parameters
\Drupal\commerce_order\Entity\OrderInterface $order: The order.
\Drupal\commerce_price\Price $amount: The amount.
string $percentage: The percentage used to calculate the amount, as a decimal. For example, '0.2' for 20%. When missing, calculated by comparing the amount to the order subtotal.
Return value
\Drupal\commerce_price\Price[] An array of amounts keyed by order item ID.
Overrides PriceSplitterInterface::split
File
- modules/
order/ src/ PriceSplitter.php, line 43
Class
Namespace
Drupal\commerce_orderCode
public function split(OrderInterface $order, Price $amount, $percentage = NULL) {
if (!$order
->getItems()) {
return [];
}
if (!$percentage) {
// The percentage is intentionally not rounded, for maximum precision.
$percentage = Calculator::divide($amount
->getNumber(), $order
->getSubtotalPrice()
->getNumber());
}
// Calculate the initial per-order-item amounts using the percentage.
// Round down to ensure that their sum isn't larger than the full amount.
$amounts = [];
foreach ($order
->getItems() as $order_item) {
if (!$order_item
->getTotalPrice()
->isZero()) {
$individual_amount = $order_item
->getTotalPrice()
->multiply($percentage);
$individual_amount = $this->rounder
->round($individual_amount, PHP_ROUND_HALF_DOWN);
// Due to rounding it is possible for the last calculated
// per-order-item amount to be larger than the total remaining amount.
if ($individual_amount
->greaterThan($amount)) {
$individual_amount = $amount;
}
$amounts[$order_item
->id()] = $individual_amount;
$amount = $amount
->subtract($individual_amount);
}
}
// The individual amounts don't add up to the full amount, distribute
// the reminder among them.
if (!$amount
->isZero()) {
/** @var \Drupal\commerce_price\Entity\CurrencyInterface $currency */
$currency = $this->currencyStorage
->load($amount
->getCurrencyCode());
$precision = $currency
->getFractionDigits();
// Use the smallest rounded currency amount (e.g. '0.01' for USD).
$smallest_number = Calculator::divide('1', pow(10, $precision), $precision);
$smallest_amount = new Price($smallest_number, $amount
->getCurrencyCode());
while (!$amount
->isZero()) {
foreach ($amounts as $order_item_id => $individual_amount) {
$amounts[$order_item_id] = $individual_amount
->add($smallest_amount);
$amount = $amount
->subtract($smallest_amount);
if ($amount
->isZero()) {
break 2;
}
}
}
}
return $amounts;
}