commerce-8.x-2.8/modules/order/src/PriceCalculator.php
modules/order/src/PriceCalculator.php
<?php
namespace Drupal\commerce_order;
use Drupal\commerce\Context;
use Drupal\commerce\PurchasableEntityInterface;
use Drupal\commerce_order\Resolver\ChainOrderTypeResolverInterface;
use Drupal\commerce_price\Resolver\ChainPriceResolverInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class PriceCalculator implements PriceCalculatorInterface {
/**
* The adjustment transformer.
*
* @var \Drupal\commerce_order\AdjustmentTransformerInterface
*/
protected $adjustmentTransformer;
/**
* The chain order type resolver.
*
* @var \Drupal\commerce_order\Resolver\ChainOrderTypeResolverInterface
*/
protected $chainOrderTypeResolver;
/**
* The chain price resolver.
*
* @var \Drupal\commerce_price\Resolver\ChainPriceResolverInterface
*/
protected $chainPriceResolver;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The order processors.
*
* @var \Drupal\commerce_order\OrderProcessorInterface[]
*/
protected $processors = [];
/**
* The unsaved orders used for calculations.
*
* @var \Drupal\commerce_order\Entity\OrderInterface[]
*/
protected $orders = [];
/**
* Constructs a new PriceCalculator object.
*
* @param \Drupal\commerce_order\AdjustmentTransformerInterface $adjustment_transformer
* The adjustment transformer.
* @param \Drupal\commerce_order\Resolver\ChainOrderTypeResolverInterface $chain_order_type_resolver
* The chain order type resolver.
* @param \Drupal\commerce_price\Resolver\ChainPriceResolverInterface $chain_price_resolver
* The chain price resolver.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
*/
public function __construct(AdjustmentTransformerInterface $adjustment_transformer, ChainOrderTypeResolverInterface $chain_order_type_resolver, ChainPriceResolverInterface $chain_price_resolver, EntityTypeManagerInterface $entity_type_manager, RequestStack $request_stack) {
$this->adjustmentTransformer = $adjustment_transformer;
$this->chainOrderTypeResolver = $chain_order_type_resolver;
$this->chainPriceResolver = $chain_price_resolver;
$this->entityTypeManager = $entity_type_manager;
$this->requestStack = $request_stack;
}
/**
* {@inheritdoc}
*/
public function addProcessor(OrderProcessorInterface $processor, $adjustment_type) {
$this->processors[$adjustment_type][] = $processor;
}
/**
* {@inheritdoc}
*/
public function getProcessors($adjustment_type) {
if (!isset($this->processors[$adjustment_type])) {
return [];
}
return $this->processors[$adjustment_type];
}
/**
* {@inheritdoc}
*/
public function calculate(PurchasableEntityInterface $purchasable_entity, $quantity, Context $context, array $adjustment_types = []) {
$resolved_price = $this->chainPriceResolver->resolve($purchasable_entity, $quantity, $context);
$processors = [];
foreach ($adjustment_types as $adjustment_type) {
$processors = array_merge($processors, $this->getProcessors($adjustment_type));
}
if (empty($adjustment_types) || empty($processors)) {
return new PriceCalculatorResult($resolved_price, $resolved_price);
}
/** @var \Drupal\commerce_order\OrderItemStorageInterface $order_item_storage */
$order_item_storage = $this->entityTypeManager->getStorage('commerce_order_item');
$order_item = $order_item_storage->createFromPurchasableEntity($purchasable_entity);
$order_item->setUnitPrice($resolved_price);
$order_item->setQuantity($quantity);
$order_type_id = $this->chainOrderTypeResolver->resolve($order_item);
$order = $this->prepareOrder($order_type_id, $context);
$order_item->order_id = $order;
$order->setItems([$order_item]);
// Allow each selected processor to add its adjustments.
foreach ($processors as $processor) {
$processor->process($order);
}
$calculated_price = $order_item->getAdjustedTotalPrice();
$adjustments = $order_item->getAdjustments();
$adjustments = $this->adjustmentTransformer->processAdjustments($adjustments);
return new PriceCalculatorResult($calculated_price, $resolved_price, $adjustments);
}
/**
* Prepares an unsaved order for the given type/context.
*
* @param string $order_type_id
* The order type ID.
* @param \Drupal\commerce\Context $context
* The context.
*
* @return \Drupal\commerce_order\Entity\OrderInterface
* The order.
*/
protected function prepareOrder($order_type_id, Context $context) {
if (!isset($this->orders[$order_type_id])) {
$order_storage = $this->entityTypeManager->getStorage('commerce_order');
$this->orders[$order_type_id] = $order_storage->create([
'type' => $order_type_id,
'ip_address' => $this->requestStack->getCurrentRequest()->getClientIp(),
// Provide a flag that can be used in the order create hook/event
// to identify orders used for price calculation purposes.
'data' => ['provider' => 'order_price_calculator'],
]);
}
$order = $this->orders[$order_type_id];
// Make sure that the order data matches the data passed in the context.
$order->setStoreId($context->getStore()->id());
$order->setCustomerId($context->getCustomer()->id());
$order->setEmail($context->getCustomer()->getEmail());
// Start from a clear set of adjustments each time.
$order->clearAdjustments();
return $order;
}
}
