<?php declare(strict_types=1);
namespace MoorlProductPromo\Subscriber;
use MoorlProductPromo\Core\Service\ProductPromoService;
use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStates;
use Shopware\Core\Checkout\Order\Event\OrderStateMachineStateChangeEvent;
use Shopware\Core\Checkout\Order\OrderStates;
use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
use Shopware\Core\Defaults;
use Shopware\Core\Framework\Api\Context\SalesChannelApiSource;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\System\SalesChannel\Entity\SalesChannelEntityLoadedEvent;
use Shopware\Core\System\StateMachine\Event\StateMachineTransitionEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class StorefrontSubscriber implements EventSubscriberInterface
{
private ProductPromoService $productPromoService;
public function __construct(
ProductPromoService $productPromoService
)
{
$this->productPromoService = $productPromoService;
}
public static function getSubscribedEvents(): array
{
return [
'sales_channel.product.loaded' => 'loaded',
CheckoutOrderPlacedEvent::class => 'onCheckoutOrderPlaced',
StateMachineTransitionEvent::class => 'stateChanged',
OrderStateMachineStateChangeEvent::class => 'orderStateChanged',
'moorl_pp.written' => 'onProductPromoWritten'
];
}
public function onProductPromoWritten(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $result) {
if (!$result->hasPayload('id')) {
continue;
}
$payload = $result->getPayload();
$payload['id'];
$promo = $this->productPromoService->getProductPromotionById($payload['id']);
$this->productPromoService->invalidateProductIds([$promo->getProductId()]);
}
}
public function onCheckoutOrderPlaced(CheckoutOrderPlacedEvent $event) {
$this->productPromoService->setContext($event->getContext());
$this->productPromoService->addPurchased($event->getOrder(), 'orderPlaced');
}
public function orderStateChanged(OrderStateMachineStateChangeEvent $event): void
{
$order = $event->getOrder();
$transactions = $order->getTransactions();
if ($transactions === null) {
return;
}
$transaction = $transactions->last();
if ($transaction === null) {
return;
}
$stateMachineState = $transaction->getStateMachineState();
if ($stateMachineState === null) {
return;
}
if ($stateMachineState->getTechnicalName() === OrderTransactionStates::STATE_PAID) {
$this->productPromoService->setContext($event->getContext());
$this->productPromoService->addPurchased($order, 'orderStatePaid');
}
}
public function stateChanged(StateMachineTransitionEvent $event): void
{
if ($event->getContext()->getVersionId() !== Defaults::LIVE_VERSION) {
return;
}
if ($event->getEntityName() === 'order_transaction' && $event->getToPlace()->getTechnicalName() === OrderTransactionStates::STATE_PAID) {
$this->productPromoService->setContext($event->getContext());
$this->productPromoService->addPurchasedOrderTransactionId($event->getEntityId(), 'orderTransactionStatePaid');
}
if ($event->getEntityName() === 'order' && $event->getToPlace()->getTechnicalName() === OrderStates::STATE_COMPLETED) {
$this->productPromoService->setContext($event->getContext());
$this->productPromoService->addPurchasedOrderId($event->getEntityId(), 'orderStateCompleted');
}
}
public function loaded(SalesChannelEntityLoadedEvent $event): void
{
$this->productPromoService->setSalesChannelContext($event->getSalesChannelContext());
$this->productPromoService->updateProductDiscounts(); // TODO: put in Cronjob
/** @var SalesChannelProductEntity $product */
foreach ($event->getEntities() as $product) {
$this->productPromoService->addExtensionToProduct($product);
}
}
public function onEntityLoaded(EntityLoadedEvent $event): void
{
$source = $event->getContext()->getSource();
if (!$source instanceof SalesChannelApiSource) {
return;
}
foreach ($event->getEntities() as $entity) {
if ($entity->getType() == 'moorl-product-promo') {
$this->productPromoService->setContext($event->getContext());
$this->productPromoService->initProductPromotions();
$entity->setData($this->productPromoService->getProductPromotions());
}
}
}
}