custom/plugins/SwagPayPal/src/Pos/Sync/Inventory/StockSubscriber.php line 71

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. /*
  3.  * (c) shopware AG <info@shopware.com>
  4.  * For the full copyright and license information, please view the LICENSE
  5.  * file that was distributed with this source code.
  6.  */
  7. namespace Swag\PayPal\Pos\Sync\Inventory;
  8. use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
  9. use Shopware\Core\Checkout\Cart\LineItem\LineItem;
  10. use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemCollection;
  11. use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
  12. use Shopware\Core\Checkout\Order\OrderDefinition;
  13. use Shopware\Core\Checkout\Order\OrderEvents;
  14. use Shopware\Core\Checkout\Order\OrderStates;
  15. use Shopware\Core\Defaults;
  16. use Shopware\Core\Framework\Context;
  17. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  18. use Shopware\Core\Framework\DataAbstractionLayer\EntityWriteResult;
  19. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
  20. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  21. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  22. use Shopware\Core\System\StateMachine\Event\StateMachineTransitionEvent;
  23. use Swag\PayPal\Pos\MessageQueue\Message\InventoryUpdateMessage;
  24. use Swag\PayPal\SwagPayPal;
  25. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  26. use Symfony\Component\Messenger\Envelope;
  27. use Symfony\Component\Messenger\MessageBusInterface;
  28. use Symfony\Component\Messenger\Stamp\DelayStamp;
  29. class StockSubscriber implements EventSubscriberInterface
  30. {
  31.     /**
  32.      * Needed for letting the StockUpdater first recalculate availableStock
  33.      */
  34.     private const DELAY 10000;
  35.     private EntityRepositoryInterface $orderLineItemRepository;
  36.     private MessageBusInterface $messageBus;
  37.     private EntityRepositoryInterface $salesChannelRepository;
  38.     public function __construct(
  39.         EntityRepositoryInterface $orderLineItemRepository,
  40.         MessageBusInterface $messageBus,
  41.         EntityRepositoryInterface $salesChannelRepository
  42.     ) {
  43.         $this->orderLineItemRepository $orderLineItemRepository;
  44.         $this->messageBus $messageBus;
  45.         $this->salesChannelRepository $salesChannelRepository;
  46.     }
  47.     /**
  48.      * Returns a list of custom business events to listen where the product maybe changed
  49.      */
  50.     public static function getSubscribedEvents(): array
  51.     {
  52.         return [
  53.             CheckoutOrderPlacedEvent::class => 'orderPlaced',
  54.             StateMachineTransitionEvent::class => 'stateChanged',
  55.             OrderEvents::ORDER_LINE_ITEM_WRITTEN_EVENT => 'lineItemWritten',
  56.             OrderEvents::ORDER_LINE_ITEM_DELETED_EVENT => 'lineItemWritten',
  57.         ];
  58.     }
  59.     /**
  60.      * If the product of an order item changed, the stocks of the old product and the new product must be updated.
  61.      */
  62.     public function lineItemWritten(EntityWrittenEvent $event): void
  63.     {
  64.         $ids = [];
  65.         foreach ($event->getWriteResults() as $result) {
  66.             if ($result->hasPayload('referencedId') && $result->getProperty('type') === LineItem::PRODUCT_LINE_ITEM_TYPE) {
  67.                 $ids[] = $result->getProperty('referencedId');
  68.             }
  69.             if ($result->getOperation() === EntityWriteResult::OPERATION_INSERT) {
  70.                 continue;
  71.             }
  72.             $changeSet $result->getChangeSet();
  73.             if (!$changeSet) {
  74.                 continue;
  75.             }
  76.             $type $changeSet->getBefore('type');
  77.             if ($type !== LineItem::PRODUCT_LINE_ITEM_TYPE) {
  78.                 continue;
  79.             }
  80.             if (!$changeSet->hasChanged('referenced_id') && !$changeSet->hasChanged('quantity')) {
  81.                 continue;
  82.             }
  83.             $ids[] = $changeSet->getBefore('referenced_id');
  84.             $ids[] = $changeSet->getAfter('referenced_id');
  85.         }
  86.         $this->startSync(\array_unique(\array_filter($ids)), $event->getContext());
  87.     }
  88.     public function stateChanged(StateMachineTransitionEvent $event): void
  89.     {
  90.         $context $event->getContext();
  91.         if ($context->getVersionId() !== Defaults::LIVE_VERSION) {
  92.             return;
  93.         }
  94.         if ($event->getEntityName() !== OrderDefinition::ENTITY_NAME) {
  95.             return;
  96.         }
  97.         $to $event->getToPlace()->getTechnicalName();
  98.         $from $event->getFromPlace()->getTechnicalName();
  99.         if ($to !== OrderStates::STATE_COMPLETED && $from !== OrderStates::STATE_COMPLETED
  100.          && $to !== OrderStates::STATE_CANCELLED && $from !== OrderStates::STATE_CANCELLED) {
  101.             return;
  102.         }
  103.         if ($this->posSalesChannelDoesNotExist($context)) {
  104.             return;
  105.         }
  106.         $criteria = new Criteria();
  107.         $criteria->addFilter(new EqualsFilter('orderId'$event->getEntityId()));
  108.         $criteria->addFilter(new EqualsFilter('type'LineItem::PRODUCT_LINE_ITEM_TYPE));
  109.         /** @var OrderLineItemCollection $lineItems */
  110.         $lineItems $this->orderLineItemRepository->search($criteria$context)->getEntities();
  111.         $ids = [];
  112.         foreach ($lineItems as $lineItem) {
  113.             /* @var OrderLineItemEntity $lineItem */
  114.             $ids[] = $lineItem->getReferencedId();
  115.         }
  116.         $this->startSync($ids$context);
  117.     }
  118.     public function orderPlaced(CheckoutOrderPlacedEvent $event): void
  119.     {
  120.         $ids = [];
  121.         $lineItems $event->getOrder()->getLineItems();
  122.         if ($lineItems === null) {
  123.             return;
  124.         }
  125.         foreach ($lineItems as $lineItem) {
  126.             if ($lineItem->getType() !== LineItem::PRODUCT_LINE_ITEM_TYPE) {
  127.                 continue;
  128.             }
  129.             $ids[] = $lineItem->getReferencedId();
  130.         }
  131.         $this->startSync($ids$event->getContext());
  132.     }
  133.     private function posSalesChannelDoesNotExist(Context $context): bool
  134.     {
  135.         $criteria = new Criteria();
  136.         $criteria->addFilter(new EqualsFilter('typeId'SwagPayPal::SALES_CHANNEL_TYPE_POS));
  137.         $criteria->addFilter(new EqualsFilter('active'true));
  138.         return $this->salesChannelRepository->searchIds($criteria$context)->getTotal() === 0;
  139.     }
  140.     private function startSync(array $productIdsContext $context): void
  141.     {
  142.         if (empty($productIds)) {
  143.             return;
  144.         }
  145.         if ($context->getVersionId() !== Defaults::LIVE_VERSION) {
  146.             return;
  147.         }
  148.         if ($this->posSalesChannelDoesNotExist($context)) {
  149.             return;
  150.         }
  151.         $message = new InventoryUpdateMessage();
  152.         $message->setIds($productIds);
  153.         $message->setContext($context);
  154.         $envelope = new Envelope($message, [
  155.             new DelayStamp(self::DELAY),
  156.         ]);
  157.         $this->messageBus->dispatch($envelope);
  158.     }
  159. }