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

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\EntityRepository;
  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. /**
  30.  * @internal
  31.  */
  32. class StockSubscriber implements EventSubscriberInterface
  33. {
  34.     /**
  35.      * Needed for letting the StockUpdater first recalculate availableStock
  36.      */
  37.     private const DELAY 10000;
  38.     private EntityRepository $orderLineItemRepository;
  39.     private MessageBusInterface $messageBus;
  40.     private EntityRepository $salesChannelRepository;
  41.     public function __construct(
  42.         EntityRepository $orderLineItemRepository,
  43.         MessageBusInterface $messageBus,
  44.         EntityRepository $salesChannelRepository
  45.     ) {
  46.         $this->orderLineItemRepository $orderLineItemRepository;
  47.         $this->messageBus $messageBus;
  48.         $this->salesChannelRepository $salesChannelRepository;
  49.     }
  50.     /**
  51.      * Returns a list of custom business events to listen where the product maybe changed
  52.      */
  53.     public static function getSubscribedEvents(): array
  54.     {
  55.         return [
  56.             CheckoutOrderPlacedEvent::class => 'orderPlaced',
  57.             StateMachineTransitionEvent::class => 'stateChanged',
  58.             OrderEvents::ORDER_LINE_ITEM_WRITTEN_EVENT => 'lineItemWritten',
  59.             OrderEvents::ORDER_LINE_ITEM_DELETED_EVENT => 'lineItemWritten',
  60.         ];
  61.     }
  62.     /**
  63.      * If the product of an order item changed, the stocks of the old product and the new product must be updated.
  64.      */
  65.     public function lineItemWritten(EntityWrittenEvent $event): void
  66.     {
  67.         $ids = [];
  68.         foreach ($event->getWriteResults() as $result) {
  69.             if ($result->hasPayload('referencedId') && $result->getProperty('type') === LineItem::PRODUCT_LINE_ITEM_TYPE) {
  70.                 $ids[] = $result->getProperty('referencedId');
  71.             }
  72.             if ($result->getOperation() === EntityWriteResult::OPERATION_INSERT) {
  73.                 continue;
  74.             }
  75.             $changeSet $result->getChangeSet();
  76.             if (!$changeSet) {
  77.                 continue;
  78.             }
  79.             $type $changeSet->getBefore('type');
  80.             if ($type !== LineItem::PRODUCT_LINE_ITEM_TYPE) {
  81.                 continue;
  82.             }
  83.             if (!$changeSet->hasChanged('referenced_id') && !$changeSet->hasChanged('quantity')) {
  84.                 continue;
  85.             }
  86.             $ids[] = $changeSet->getBefore('referenced_id');
  87.             $ids[] = $changeSet->getAfter('referenced_id');
  88.         }
  89.         $this->startSync(\array_unique(\array_filter($ids)), $event->getContext());
  90.     }
  91.     public function stateChanged(StateMachineTransitionEvent $event): void
  92.     {
  93.         $context $event->getContext();
  94.         if ($context->getVersionId() !== Defaults::LIVE_VERSION) {
  95.             return;
  96.         }
  97.         if ($event->getEntityName() !== OrderDefinition::ENTITY_NAME) {
  98.             return;
  99.         }
  100.         $to $event->getToPlace()->getTechnicalName();
  101.         $from $event->getFromPlace()->getTechnicalName();
  102.         if ($to !== OrderStates::STATE_COMPLETED && $from !== OrderStates::STATE_COMPLETED
  103.          && $to !== OrderStates::STATE_CANCELLED && $from !== OrderStates::STATE_CANCELLED) {
  104.             return;
  105.         }
  106.         if ($this->posSalesChannelDoesNotExist($context)) {
  107.             return;
  108.         }
  109.         $criteria = new Criteria();
  110.         $criteria->addFilter(new EqualsFilter('orderId'$event->getEntityId()));
  111.         $criteria->addFilter(new EqualsFilter('type'LineItem::PRODUCT_LINE_ITEM_TYPE));
  112.         /** @var OrderLineItemCollection $lineItems */
  113.         $lineItems $this->orderLineItemRepository->search($criteria$context)->getEntities();
  114.         $ids = [];
  115.         foreach ($lineItems as $lineItem) {
  116.             /* @var OrderLineItemEntity $lineItem */
  117.             $ids[] = $lineItem->getReferencedId();
  118.         }
  119.         $this->startSync($ids$context);
  120.     }
  121.     public function orderPlaced(CheckoutOrderPlacedEvent $event): void
  122.     {
  123.         $ids = [];
  124.         $lineItems $event->getOrder()->getLineItems();
  125.         if ($lineItems === null) {
  126.             return;
  127.         }
  128.         foreach ($lineItems as $lineItem) {
  129.             if ($lineItem->getType() !== LineItem::PRODUCT_LINE_ITEM_TYPE) {
  130.                 continue;
  131.             }
  132.             $ids[] = $lineItem->getReferencedId();
  133.         }
  134.         $this->startSync($ids$event->getContext());
  135.     }
  136.     private function posSalesChannelDoesNotExist(Context $context): bool
  137.     {
  138.         $criteria = new Criteria();
  139.         $criteria->addFilter(new EqualsFilter('typeId'SwagPayPal::SALES_CHANNEL_TYPE_POS));
  140.         $criteria->addFilter(new EqualsFilter('active'true));
  141.         return $this->salesChannelRepository->searchIds($criteria$context)->getTotal() === 0;
  142.     }
  143.     private function startSync(array $productIdsContext $context): void
  144.     {
  145.         if (empty($productIds)) {
  146.             return;
  147.         }
  148.         if ($context->getVersionId() !== Defaults::LIVE_VERSION) {
  149.             return;
  150.         }
  151.         if ($this->posSalesChannelDoesNotExist($context)) {
  152.             return;
  153.         }
  154.         $message = new InventoryUpdateMessage();
  155.         $message->setIds($productIds);
  156.         $envelope = new Envelope($message, [
  157.             new DelayStamp(self::DELAY),
  158.         ]);
  159.         $this->messageBus->dispatch($envelope);
  160.     }
  161. }