Loading modules/order/commerce_order.services.yml +10 −6 Original line number Diff line number Diff line services: plugin.manager.commerce_adjustment_type: class: Drupal\commerce_order\AdjustmentTypeManager arguments: ['@module_handler', '@cache.discovery'] commerce_order.chain_order_type_resolver: class: Drupal\commerce_order\Resolver\ChainOrderTypeResolver tags: Loading @@ -10,6 +14,10 @@ services: tags: - { name: commerce_order.order_type_resolver, priority: -100 } commerce_order.adjustment_transformer: class: Drupal\commerce_order\AdjustmentTransformer arguments: ['@plugin.manager.commerce_adjustment_type', '@commerce_price.rounder'] commerce_order.order_assignment: class: Drupal\commerce_order\OrderAssignment arguments: ['@entity_type.manager', '@event_dispatcher'] Loading Loading @@ -49,13 +57,9 @@ services: tags: - { name: 'event_subscriber' } plugin.manager.commerce_adjustment_type: class: Drupal\commerce_order\AdjustmentTypeManager arguments: ['@module_handler', '@cache.discovery'] commerce_order.order_total_summary: class: Drupal\commerce_order\OrderTotalSummary arguments: ['@plugin.manager.commerce_adjustment_type'] arguments: ['@commerce_order.adjustment_transformer'] commerce_order.order_store_resolver: class: Drupal\commerce_order\Resolver\OrderStoreResolver Loading @@ -65,4 +69,4 @@ services: commerce_order.price_calculator: class: Drupal\commerce_order\PriceCalculator arguments: ['@entity_type.manager', '@commerce_price.chain_price_resolver', '@commerce_order.chain_order_type_resolver', '@request_stack'] arguments: ['@commerce_order.adjustment_transformer', '@commerce_order.chain_order_type_resolver', '@commerce_price.chain_price_resolver', '@entity_type.manager', '@request_stack'] modules/order/src/AdjustmentTransformer.php 0 → 100644 +120 −0 Original line number Diff line number Diff line <?php namespace Drupal\commerce_order; use Drupal\commerce_price\RounderInterface; use Drupal\Component\Utility\SortArray; class AdjustmentTransformer implements AdjustmentTransformerInterface { /** * The adjustment type manager. * * @var \Drupal\commerce_order\AdjustmentTypeManager */ protected $adjustmentTypeManager; /** * The rounder. * * @var \Drupal\commerce_price\RounderInterface */ protected $rounder; /** * Constructs a new AdjustmentTransformer object. * * @param \Drupal\commerce_order\AdjustmentTypeManager $adjustment_type_manager * The adjustment type manager. * @param \Drupal\commerce_price\RounderInterface $rounder * The rounder. */ public function __construct(AdjustmentTypeManager $adjustment_type_manager, RounderInterface $rounder) { $this->adjustmentTypeManager = $adjustment_type_manager; $this->rounder = $rounder; } /** * {@inheritdoc} */ public function processAdjustments(array $adjustments) { $adjustments = $this->combineAdjustments($adjustments); $adjustments = $this->sortAdjustments($adjustments); $adjustments = $this->roundAdjustments($adjustments); return $adjustments; } /** * {@inheritdoc} */ public function combineAdjustments(array $adjustments) { $combined_adjustments = []; foreach ($adjustments as $index => $adjustment) { $type = $adjustment->getType(); $source_id = $adjustment->getSourceId(); if (empty($source_id)) { // Adjustments without a source ID are always shown standalone. $key = $index; } else { // Adjustments with the same type and source ID are combined. $key = $type . '_' . $source_id; } if (empty($combined_adjustments[$key])) { $combined_adjustments[$key] = $adjustment; } else { $combined_adjustments[$key] = $combined_adjustments[$key]->add($adjustment); } } // The keys used for combining are irrelevant to the caller. $combined_adjustments = array_values($combined_adjustments); return $combined_adjustments; } /** * {@inheritdoc} */ public function sortAdjustments(array $adjustments) { $types = $this->adjustmentTypeManager->getDefinitions(); $data = []; foreach ($adjustments as $adjustment) { $data[] = [ 'adjustment' => $adjustment, 'weight' => $types[$adjustment->getType()]['weight'], ]; } uasort($data, [SortArray::class, 'sortByWeightElement']); // Re-extract the adjustments from the sorted array. $adjustments = array_column($data, 'adjustment'); return $adjustments; } /** * {@inheritdoc} */ public function roundAdjustments(array $adjustments, $mode = PHP_ROUND_HALF_UP) { foreach ($adjustments as $index => $adjustment) { $adjustments[$index] = $this->roundAdjustment($adjustment, $mode); } return $adjustments; } /** * {@inheritdoc} */ public function roundAdjustment(Adjustment $adjustment, $mode = PHP_ROUND_HALF_UP) { $amount = $this->rounder->round($adjustment->getAmount(), $mode); $adjustment = new Adjustment([ 'amount' => $amount, ] + $adjustment->toArray()); return $adjustment; } } modules/order/src/AdjustmentTransformerInterface.php 0 → 100644 +83 −0 Original line number Diff line number Diff line <?php namespace Drupal\commerce_order; /** * Provides common logic for processing and transforming adjustments. */ interface AdjustmentTransformerInterface { /** * Combines, sorts, and rounds the given adjustments. * * @param \Drupal\commerce_order\Adjustment[] $adjustments * The adjustments. * * @return \Drupal\commerce_order\Adjustment[] * The processed adjustments. */ public function processAdjustments(array $adjustments); /** * Combines adjustments with the same type and source ID. * * For example, all tax adjustments generated by the same tax type * will be combined into a single adjustment, which can then be shown * in total summaries. * * @param \Drupal\commerce_order\Adjustment[] $adjustments * The adjustments. * * @return \Drupal\commerce_order\Adjustment[] * The combined adjustments. */ public function combineAdjustments(array $adjustments); /** * Sorts adjustments by their type's weight. * * For example, tax adjustments will be placed after promotion adjustments, * because the tax adjustment type has a higher weight than the promotion * one, as defined in commerce_order.commerce_adjustment_types.yml. * * @param \Drupal\commerce_order\Adjustment[] $adjustments * The adjustments. * * @return \Drupal\commerce_order\Adjustment[] * The sorted adjustments. */ public function sortAdjustments(array $adjustments); /** * Rounds adjustments to their currency precision. * * For example, USD adjustments will be rounded to 2 decimals. * * @param \Drupal\commerce_order\Adjustment[] $adjustments * The adjustments. * @param int $mode * The rounding mode. One of the following constants: PHP_ROUND_HALF_UP, * PHP_ROUND_HALF_DOWN, PHP_ROUND_HALF_EVEN, PHP_ROUND_HALF_ODD. * * @return \Drupal\commerce_order\Adjustment[] * The rounded adjustments. */ public function roundAdjustments(array $adjustments, $mode = PHP_ROUND_HALF_UP); /** * Rounds an adjustment to its currency precision. * * For example, a USD adjustment will be rounded to 2 decimals. * * @param \Drupal\commerce_order\Adjustment $adjustment * The adjustment. * @param int $mode * The rounding mode. One of the following constants: PHP_ROUND_HALF_UP, * PHP_ROUND_HALF_DOWN, PHP_ROUND_HALF_EVEN, PHP_ROUND_HALF_ODD. * * @return \Drupal\commerce_order\Adjustment * The rounded adjustment. */ public function roundAdjustment(Adjustment $adjustment, $mode = PHP_ROUND_HALF_UP); } modules/order/src/Entity/OrderInterface.php +6 −4 Original line number Diff line number Diff line Loading @@ -233,12 +233,14 @@ interface OrderInterface extends ContentEntityInterface, EntityAdjustableInterfa /** * Collects all adjustments that belong to the order. * * Unlike getAdjustments() which returns only order adjustments, * this method returns both order and order item adjustments. * Unlike getAdjustments() which returns only order adjustments, this * method returns both order and order item adjustments (multiplied * by quantity). * * Important: * The returned order item adjustments are multiplied by quantity, * so that they can be safely added to the order adjustments. * The returned adjustments are unprocessed, and must be processed before use. * * @see \Drupal\commerce_order\AdjustmentTransformerInterface::processAdjustments() * * @return \Drupal\commerce_order\Adjustment[] * The adjustments. Loading modules/order/src/OrderTotalSummary.php +18 −35 Original line number Diff line number Diff line Loading @@ -3,57 +3,40 @@ namespace Drupal\commerce_order; use Drupal\commerce_order\Entity\OrderInterface; use Drupal\Component\Utility\SortArray; class OrderTotalSummary implements OrderTotalSummaryInterface { /** * The adjustment type manager. * The adjustment transformer. * * @var \Drupal\commerce_order\AdjustmentTypeManager * @var \Drupal\commerce_order\AdjustmentTransformerInterface */ protected $adjustmentTypeManager; protected $adjustmentTransformer; /** * {@inheritdoc} * Constructs a new OrderTotalSummary object. * * @param \Drupal\commerce_order\AdjustmentTransformerInterface $adjustment_transformer * The adjustment transformer. */ public function __construct(AdjustmentTypeManager $adjustment_type_manager) { $this->adjustmentTypeManager = $adjustment_type_manager; public function __construct(AdjustmentTransformerInterface $adjustment_transformer) { $this->adjustmentTransformer = $adjustment_transformer; } /** * {@inheritdoc} */ public function buildTotals(OrderInterface $order) { $types = $this->adjustmentTypeManager->getDefinitions(); $adjustments = []; foreach ($order->collectAdjustments() as $adjustment) { $type = $adjustment->getType(); $source_id = $adjustment->getSourceId(); if (empty($source_id)) { // Adjustments without a source ID are always shown standalone. $key = count($adjustments); } else { // Adjustments with the same type and source ID are combined. $key = $type . '_' . $source_id; } if (empty($adjustments[$key])) { $adjustments[$key] = [ 'type' => $type, 'label' => $adjustment->getLabel(), 'total' => $adjustment->getAmount(), 'percentage' => $adjustment->getPercentage(), 'weight' => $types[$type]['weight'], ]; } else { $adjustments[$key]['total'] = $adjustments[$key]['total']->add($adjustment->getAmount()); } $adjustments = $order->collectAdjustments(); $adjustments = $this->adjustmentTransformer->processAdjustments($adjustments); // Convert the adjustments to arrays. $adjustments = array_map(function (Adjustment $adjustment) { return $adjustment->toArray(); }, $adjustments); // Provide the "total" key for backwards compatibility reasons. foreach ($adjustments as $index => $adjustment) { $adjustments[$index]['total'] = $adjustments[$index]['amount']; } // Sort the adjustments by weight. uasort($adjustments, [SortArray::class, 'sortByWeightElement']); return [ 'subtotal' => $order->getSubtotalPrice(), Loading Loading
modules/order/commerce_order.services.yml +10 −6 Original line number Diff line number Diff line services: plugin.manager.commerce_adjustment_type: class: Drupal\commerce_order\AdjustmentTypeManager arguments: ['@module_handler', '@cache.discovery'] commerce_order.chain_order_type_resolver: class: Drupal\commerce_order\Resolver\ChainOrderTypeResolver tags: Loading @@ -10,6 +14,10 @@ services: tags: - { name: commerce_order.order_type_resolver, priority: -100 } commerce_order.adjustment_transformer: class: Drupal\commerce_order\AdjustmentTransformer arguments: ['@plugin.manager.commerce_adjustment_type', '@commerce_price.rounder'] commerce_order.order_assignment: class: Drupal\commerce_order\OrderAssignment arguments: ['@entity_type.manager', '@event_dispatcher'] Loading Loading @@ -49,13 +57,9 @@ services: tags: - { name: 'event_subscriber' } plugin.manager.commerce_adjustment_type: class: Drupal\commerce_order\AdjustmentTypeManager arguments: ['@module_handler', '@cache.discovery'] commerce_order.order_total_summary: class: Drupal\commerce_order\OrderTotalSummary arguments: ['@plugin.manager.commerce_adjustment_type'] arguments: ['@commerce_order.adjustment_transformer'] commerce_order.order_store_resolver: class: Drupal\commerce_order\Resolver\OrderStoreResolver Loading @@ -65,4 +69,4 @@ services: commerce_order.price_calculator: class: Drupal\commerce_order\PriceCalculator arguments: ['@entity_type.manager', '@commerce_price.chain_price_resolver', '@commerce_order.chain_order_type_resolver', '@request_stack'] arguments: ['@commerce_order.adjustment_transformer', '@commerce_order.chain_order_type_resolver', '@commerce_price.chain_price_resolver', '@entity_type.manager', '@request_stack']
modules/order/src/AdjustmentTransformer.php 0 → 100644 +120 −0 Original line number Diff line number Diff line <?php namespace Drupal\commerce_order; use Drupal\commerce_price\RounderInterface; use Drupal\Component\Utility\SortArray; class AdjustmentTransformer implements AdjustmentTransformerInterface { /** * The adjustment type manager. * * @var \Drupal\commerce_order\AdjustmentTypeManager */ protected $adjustmentTypeManager; /** * The rounder. * * @var \Drupal\commerce_price\RounderInterface */ protected $rounder; /** * Constructs a new AdjustmentTransformer object. * * @param \Drupal\commerce_order\AdjustmentTypeManager $adjustment_type_manager * The adjustment type manager. * @param \Drupal\commerce_price\RounderInterface $rounder * The rounder. */ public function __construct(AdjustmentTypeManager $adjustment_type_manager, RounderInterface $rounder) { $this->adjustmentTypeManager = $adjustment_type_manager; $this->rounder = $rounder; } /** * {@inheritdoc} */ public function processAdjustments(array $adjustments) { $adjustments = $this->combineAdjustments($adjustments); $adjustments = $this->sortAdjustments($adjustments); $adjustments = $this->roundAdjustments($adjustments); return $adjustments; } /** * {@inheritdoc} */ public function combineAdjustments(array $adjustments) { $combined_adjustments = []; foreach ($adjustments as $index => $adjustment) { $type = $adjustment->getType(); $source_id = $adjustment->getSourceId(); if (empty($source_id)) { // Adjustments without a source ID are always shown standalone. $key = $index; } else { // Adjustments with the same type and source ID are combined. $key = $type . '_' . $source_id; } if (empty($combined_adjustments[$key])) { $combined_adjustments[$key] = $adjustment; } else { $combined_adjustments[$key] = $combined_adjustments[$key]->add($adjustment); } } // The keys used for combining are irrelevant to the caller. $combined_adjustments = array_values($combined_adjustments); return $combined_adjustments; } /** * {@inheritdoc} */ public function sortAdjustments(array $adjustments) { $types = $this->adjustmentTypeManager->getDefinitions(); $data = []; foreach ($adjustments as $adjustment) { $data[] = [ 'adjustment' => $adjustment, 'weight' => $types[$adjustment->getType()]['weight'], ]; } uasort($data, [SortArray::class, 'sortByWeightElement']); // Re-extract the adjustments from the sorted array. $adjustments = array_column($data, 'adjustment'); return $adjustments; } /** * {@inheritdoc} */ public function roundAdjustments(array $adjustments, $mode = PHP_ROUND_HALF_UP) { foreach ($adjustments as $index => $adjustment) { $adjustments[$index] = $this->roundAdjustment($adjustment, $mode); } return $adjustments; } /** * {@inheritdoc} */ public function roundAdjustment(Adjustment $adjustment, $mode = PHP_ROUND_HALF_UP) { $amount = $this->rounder->round($adjustment->getAmount(), $mode); $adjustment = new Adjustment([ 'amount' => $amount, ] + $adjustment->toArray()); return $adjustment; } }
modules/order/src/AdjustmentTransformerInterface.php 0 → 100644 +83 −0 Original line number Diff line number Diff line <?php namespace Drupal\commerce_order; /** * Provides common logic for processing and transforming adjustments. */ interface AdjustmentTransformerInterface { /** * Combines, sorts, and rounds the given adjustments. * * @param \Drupal\commerce_order\Adjustment[] $adjustments * The adjustments. * * @return \Drupal\commerce_order\Adjustment[] * The processed adjustments. */ public function processAdjustments(array $adjustments); /** * Combines adjustments with the same type and source ID. * * For example, all tax adjustments generated by the same tax type * will be combined into a single adjustment, which can then be shown * in total summaries. * * @param \Drupal\commerce_order\Adjustment[] $adjustments * The adjustments. * * @return \Drupal\commerce_order\Adjustment[] * The combined adjustments. */ public function combineAdjustments(array $adjustments); /** * Sorts adjustments by their type's weight. * * For example, tax adjustments will be placed after promotion adjustments, * because the tax adjustment type has a higher weight than the promotion * one, as defined in commerce_order.commerce_adjustment_types.yml. * * @param \Drupal\commerce_order\Adjustment[] $adjustments * The adjustments. * * @return \Drupal\commerce_order\Adjustment[] * The sorted adjustments. */ public function sortAdjustments(array $adjustments); /** * Rounds adjustments to their currency precision. * * For example, USD adjustments will be rounded to 2 decimals. * * @param \Drupal\commerce_order\Adjustment[] $adjustments * The adjustments. * @param int $mode * The rounding mode. One of the following constants: PHP_ROUND_HALF_UP, * PHP_ROUND_HALF_DOWN, PHP_ROUND_HALF_EVEN, PHP_ROUND_HALF_ODD. * * @return \Drupal\commerce_order\Adjustment[] * The rounded adjustments. */ public function roundAdjustments(array $adjustments, $mode = PHP_ROUND_HALF_UP); /** * Rounds an adjustment to its currency precision. * * For example, a USD adjustment will be rounded to 2 decimals. * * @param \Drupal\commerce_order\Adjustment $adjustment * The adjustment. * @param int $mode * The rounding mode. One of the following constants: PHP_ROUND_HALF_UP, * PHP_ROUND_HALF_DOWN, PHP_ROUND_HALF_EVEN, PHP_ROUND_HALF_ODD. * * @return \Drupal\commerce_order\Adjustment * The rounded adjustment. */ public function roundAdjustment(Adjustment $adjustment, $mode = PHP_ROUND_HALF_UP); }
modules/order/src/Entity/OrderInterface.php +6 −4 Original line number Diff line number Diff line Loading @@ -233,12 +233,14 @@ interface OrderInterface extends ContentEntityInterface, EntityAdjustableInterfa /** * Collects all adjustments that belong to the order. * * Unlike getAdjustments() which returns only order adjustments, * this method returns both order and order item adjustments. * Unlike getAdjustments() which returns only order adjustments, this * method returns both order and order item adjustments (multiplied * by quantity). * * Important: * The returned order item adjustments are multiplied by quantity, * so that they can be safely added to the order adjustments. * The returned adjustments are unprocessed, and must be processed before use. * * @see \Drupal\commerce_order\AdjustmentTransformerInterface::processAdjustments() * * @return \Drupal\commerce_order\Adjustment[] * The adjustments. Loading
modules/order/src/OrderTotalSummary.php +18 −35 Original line number Diff line number Diff line Loading @@ -3,57 +3,40 @@ namespace Drupal\commerce_order; use Drupal\commerce_order\Entity\OrderInterface; use Drupal\Component\Utility\SortArray; class OrderTotalSummary implements OrderTotalSummaryInterface { /** * The adjustment type manager. * The adjustment transformer. * * @var \Drupal\commerce_order\AdjustmentTypeManager * @var \Drupal\commerce_order\AdjustmentTransformerInterface */ protected $adjustmentTypeManager; protected $adjustmentTransformer; /** * {@inheritdoc} * Constructs a new OrderTotalSummary object. * * @param \Drupal\commerce_order\AdjustmentTransformerInterface $adjustment_transformer * The adjustment transformer. */ public function __construct(AdjustmentTypeManager $adjustment_type_manager) { $this->adjustmentTypeManager = $adjustment_type_manager; public function __construct(AdjustmentTransformerInterface $adjustment_transformer) { $this->adjustmentTransformer = $adjustment_transformer; } /** * {@inheritdoc} */ public function buildTotals(OrderInterface $order) { $types = $this->adjustmentTypeManager->getDefinitions(); $adjustments = []; foreach ($order->collectAdjustments() as $adjustment) { $type = $adjustment->getType(); $source_id = $adjustment->getSourceId(); if (empty($source_id)) { // Adjustments without a source ID are always shown standalone. $key = count($adjustments); } else { // Adjustments with the same type and source ID are combined. $key = $type . '_' . $source_id; } if (empty($adjustments[$key])) { $adjustments[$key] = [ 'type' => $type, 'label' => $adjustment->getLabel(), 'total' => $adjustment->getAmount(), 'percentage' => $adjustment->getPercentage(), 'weight' => $types[$type]['weight'], ]; } else { $adjustments[$key]['total'] = $adjustments[$key]['total']->add($adjustment->getAmount()); } $adjustments = $order->collectAdjustments(); $adjustments = $this->adjustmentTransformer->processAdjustments($adjustments); // Convert the adjustments to arrays. $adjustments = array_map(function (Adjustment $adjustment) { return $adjustment->toArray(); }, $adjustments); // Provide the "total" key for backwards compatibility reasons. foreach ($adjustments as $index => $adjustment) { $adjustments[$index]['total'] = $adjustments[$index]['amount']; } // Sort the adjustments by weight. uasort($adjustments, [SortArray::class, 'sortByWeightElement']); return [ 'subtotal' => $order->getSubtotalPrice(), Loading