View source
<?php
namespace Drupal\commerce_stock\EventSubscriber;
use Drupal\commerce\Context;
use Drupal\commerce\PurchasableEntityInterface;
use Drupal\commerce_order\Entity\Order;
use Drupal\commerce_order\Event\OrderEvent;
use Drupal\commerce_order\Event\OrderEvents;
use Drupal\commerce_order\Event\OrderItemEvent;
use Drupal\commerce_stock\ContextCreatorTrait;
use Drupal\commerce_stock\Plugin\Commerce\StockEventType\StockEventTypeInterface;
use Drupal\commerce_stock\Plugin\StockEvents\CoreStockEvents;
use Drupal\commerce_stock\StockEventsManagerInterface;
use Drupal\commerce_stock\StockEventTypeManagerInterface;
use Drupal\commerce_stock\StockLocationInterface;
use Drupal\commerce_stock\StockServiceManagerInterface;
use Drupal\commerce_stock\StockTransactionsInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\state_machine\Event\WorkflowTransitionEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class OrderEventSubscriber implements EventSubscriberInterface {
use ContextCreatorTrait;
use StringTranslationTrait;
protected $stockServiceManager;
protected $eventTypeManager;
protected $eventsManager;
protected $entityTypeManager;
public function __construct(StockServiceManagerInterface $stock_service_manager, StockEventTypeManagerInterface $event_type_manager, StockEventsManagerInterface $events_manager, EntityTypeManagerInterface $entity_type_manager) {
$this->stockServiceManager = $stock_service_manager;
$this->eventTypeManager = $event_type_manager;
$this->eventsManager = $events_manager;
$this->entityTypeManager = $entity_type_manager;
}
public function onOrderPlace(WorkflowTransitionEvent $event) {
$eventType = $this
->getEventType('commerce_stock_order_place');
$order = $event
->getEntity();
foreach ($order
->getItems() as $item) {
$entity = $item
->getPurchasedEntity();
if (!$entity) {
continue;
}
$service = $this->stockServiceManager
->getService($entity);
$checker = $service
->getStockChecker();
if ($checker
->getIsAlwaysInStock($entity)) {
continue;
}
$quantity = -1 * $item
->getQuantity();
$context = self::createContextFromOrder($order);
$location = $this->stockServiceManager
->getTransactionLocation($context, $entity, $quantity);
$transaction_type = StockTransactionsInterface::STOCK_SALE;
$this
->runTransactionEvent($eventType, $context, $entity, $quantity, $location, $transaction_type, $order);
}
}
public function onOrderUpdate(OrderEvent $event) {
$eventType = $this
->getEventType('commerce_stock_order_update');
$order = $event
->getOrder();
if ($order
->getState()
->getWorkflow()
->getGroup() !== 'commerce_order') {
return;
}
$original_order = $this
->getOriginalEntity($order);
foreach ($order
->getItems() as $item) {
if (!$original_order
->hasItem($item)) {
if ($order && !in_array($order
->getState()->value, [
'draft',
'canceled',
])) {
$entity = $item
->getPurchasedEntity();
if (!$entity) {
continue;
}
$service = $this->stockServiceManager
->getService($entity);
$checker = $service
->getStockChecker();
if ($checker
->getIsAlwaysInStock($entity)) {
continue;
}
$context = self::createContextFromOrder($order);
$location = $this->stockServiceManager
->getTransactionLocation($context, $entity, $item
->getQuantity());
$transaction_type = StockTransactionsInterface::STOCK_SALE;
$quantity = -1 * $item
->getQuantity();
$this
->runTransactionEvent($eventType, $context, $entity, $quantity, $location, $transaction_type, $order);
}
}
}
}
public function onOrderCancel(WorkflowTransitionEvent $event) {
$eventType = $this
->getEventType('commerce_stock_order_cancel');
$order = $event
->getEntity();
$original_order = $this
->getOriginalEntity($order);
if ($original_order && $original_order
->getState()->value === 'draft') {
return;
}
foreach ($order
->getItems() as $item) {
$entity = $item
->getPurchasedEntity();
if (!$entity) {
continue;
}
$service = $this->stockServiceManager
->getService($entity);
$checker = $service
->getStockChecker();
if ($checker
->getIsAlwaysInStock($entity)) {
continue;
}
$quantity = $item
->getQuantity();
$context = self::createContextFromOrder($order);
$location = $this->stockServiceManager
->getTransactionLocation($context, $entity, $quantity);
$transaction_type = StockTransactionsInterface::STOCK_RETURN;
$this
->runTransactionEvent($eventType, $context, $entity, $quantity, $location, $transaction_type, $order);
}
}
public function onOrderDelete(OrderEvent $event) {
$eventType = $this
->getEventType('commerce_stock_order_delete');
$order = $event
->getOrder();
if ($order
->getState()
->getWorkflow()
->getGroup() !== 'commerce_order') {
return;
}
if (in_array($order
->getState()->value, [
'draft',
'canceled',
])) {
return;
}
$items = $order
->getItems();
foreach ($items as $item) {
$entity = $item
->getPurchasedEntity();
if (!$entity) {
continue;
}
$service = $this->stockServiceManager
->getService($entity);
$checker = $service
->getStockChecker();
if ($checker
->getIsAlwaysInStock($entity)) {
continue;
}
$quantity = $item
->getQuantity();
$context = self::createContextFromOrder($order);
$location = $this->stockServiceManager
->getTransactionLocation($context, $entity, $quantity);
$transaction_type = StockTransactionsInterface::STOCK_RETURN;
$this
->runTransactionEvent($eventType, $context, $entity, $quantity, $location, $transaction_type, $order);
}
}
public function onOrderItemUpdate(OrderItemEvent $event) {
$eventType = $this
->getEventType('commerce_stock_order_item_update');
$item = $event
->getOrderItem();
$order = $item
->getOrder();
if ($order && !in_array($order
->getState()->value, [
'draft',
'canceled',
])) {
if ($order
->getState()
->getWorkflow()
->getGroup() !== 'commerce_order') {
return;
}
$original = $this
->getOriginalEntity($item);
$diff = $original
->getQuantity() - $item
->getQuantity();
if ($diff) {
$entity = $item
->getPurchasedEntity();
if (!$entity) {
return;
}
$service = $this->stockServiceManager
->getService($entity);
$checker = $service
->getStockChecker();
if ($checker
->getIsAlwaysInStock($entity)) {
return;
}
$transaction_type = $diff < 0 ? StockTransactionsInterface::STOCK_SALE : StockTransactionsInterface::STOCK_RETURN;
$context = self::createContextFromOrder($order);
$location = $this->stockServiceManager
->getTransactionLocation($context, $entity, $diff);
$this
->runTransactionEvent($eventType, $context, $entity, $diff, $location, $transaction_type, $order);
}
}
}
public function onOrderItemDelete(OrderItemEvent $event) {
$eventType = $this
->getEventType('commerce_stock_order_item_delete');
$item = $event
->getOrderItem();
$order = $item
->getOrder();
if ($order && !in_array($order
->getState()->value, [
'draft',
'canceled',
])) {
if ($order
->getState()
->getWorkflow()
->getGroup() !== 'commerce_order') {
return;
}
$entity = $item
->getPurchasedEntity();
if (!$entity) {
return;
}
$service = $this->stockServiceManager
->getService($entity);
$checker = $service
->getStockChecker();
if ($checker
->getIsAlwaysInStock($entity)) {
return;
}
$context = self::createContextFromOrder($order);
$location = $this->stockServiceManager
->getTransactionLocation($context, $entity, $item
->getQuantity());
$transaction_type = StockTransactionsInterface::STOCK_RETURN;
$this
->runTransactionEvent($eventType, $context, $entity, $item
->getQuantity(), $location, $transaction_type, $order);
}
}
public static function getSubscribedEvents() {
$events = [
'commerce_order.place.post_transition' => [
'onOrderPlace',
-100,
],
'commerce_order.cancel.post_transition' => [
'onOrderCancel',
-100,
],
OrderEvents::ORDER_UPDATE => [
'onOrderUpdate',
-100,
],
OrderEvents::ORDER_PREDELETE => [
'onOrderDelete',
-100,
],
OrderEvents::ORDER_ITEM_UPDATE => [
'onOrderItemUpdate',
-100,
],
OrderEvents::ORDER_ITEM_DELETE => [
'onOrderItemDelete',
-100,
],
];
return $events;
}
private function runTransactionEvent(StockEventTypeInterface $event_type, Context $context, PurchasableEntityInterface $entity, $quantity, StockLocationInterface $location, $transaction_type_id, Order $order) {
$data['message'] = $event_type
->getDefaultMessage();
$metadata = [
'related_oid' => $order
->id(),
'related_uid' => $order
->getCustomerId(),
'data' => $data,
];
$event_type_id = CoreStockEvents::mapStockEventIds($event_type
->getPluginId());
return $this->eventsManager
->createInstance('core_stock_events')
->stockEvent($context, $entity, $event_type_id, $quantity, $location, $transaction_type_id, $metadata);
}
private function getEventType($plugin_id) {
return $this->eventTypeManager
->createInstance($plugin_id);
}
private function getOriginalEntity(EntityInterface $entity) {
$original_entity = NULL;
$original_entity = $entity->original;
if (!$original_entity) {
$id = $entity
->getOriginalId() !== NULL ? $entity
->getOriginalId() : $entity
->id();
$original_entity = $this->entityTypeManager
->getStorage($entity
->getEntityTypeId())
->loadUnchanged($id);
}
return $original_entity;
}
}