<?php
declare(strict_types=1);
namespace Lnb\Shopware6\LnbCustomFields\Subscriber;
use Lnb\Shopware6\LnbSubscription\Entity\SubscriptionOrder\SubscriptionOrderEntity;
use Lnb\Shopware6\LnbSubscription\Event\SubscriptionBeforeRenewEvent;
use Lnb\Shopware6\LnbSubscription\Event\SubscriptionCancelledEvent;
use Lnb\Shopware6\LnbSubscription\Event\SubscriptionCreatedEvent;
use Lnb\Shopware6\LnbSubscription\Installation\Installer\StateMachineInstaller;
use Shopware\Core\Checkout\Order\OrderEntity;
use Shopware\Core\Checkout\Order\OrderEvents;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\EntityWriteResult;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class SubscriptionStateSubscriber implements EventSubscriberInterface
{
protected ContainerInterface $container;
public function __construct(
ContainerInterface $container
) {
$this->container = $container;
}
public static function getSubscribedEvents()
{
return [
SubscriptionCreatedEvent::class => ['onSubscriptionCreated'],
SubscriptionCancelledEvent::class => ['onSubscriptionCancelled'],
OrderEvents::ORDER_WRITTEN_EVENT => [['onOrderCreated', 0]],
];
}
public function onSubscriptionCreated(SubscriptionCreatedEvent $event)
{
$context = $event->getContext();
$subscriptionId = $event->getSubscriptionId();
$subscription = $this->getSubscription($subscriptionId, $context);
$this->updateCustomerActiveSubscriptionsCount($subscription->getCustomerId(), $context);
}
public function onSubscriptionCancelled(SubscriptionCancelledEvent $event)
{
$context = $event->getContext();
$subscriptionId = $event->getLnbSubscriptionOrder()->getId();
$subscription = $this->getSubscription($subscriptionId, $context);
$this->updateCustomerActiveSubscriptionsCount($subscription->getCustomerId(), $context);
$this->updateAllSubscriptionChildren($subscriptionId, $context);
}
public function onOrderCreated(EntityWrittenEvent $event)
{
$context = $event->getContext();
foreach ($event->getWriteResults() as $writeResult) {
// return if the operation is not insert
if ($writeResult->getOperation() !== EntityWriteResult::OPERATION_INSERT) {
return;
}
$orderId = $writeResult->getPrimaryKey();
$order = $this->getOrder($context, $orderId);
foreach ($order->getLineItems() as $lineItem) {
$product = $lineItem->getProduct();
if ($product) { // it can be discount...
$payload = $lineItem->getPayload();
if (!empty($payload['LnbSubscription']))
{
$this->setOrderCustomField($order->getId(), 'lnb_custom_fields_parent_subscription_canceled', false, $context);
}
}
}
}
}
private function getSubscription(string $subscriptionId, Context $context): SubscriptionOrderEntity
{
$criteria = new Criteria([$subscriptionId]);
$subscriptionOrderRepository = $this->container->get('lnb_subscription_order.repository');
return $subscriptionOrderRepository->search($criteria, $context)->first();
}
private function updateCustomerActiveSubscriptionsCount(string $customerId, Context $context): void
{
$criteria = new Criteria();
$criteria
->addFilter(new EqualsFilter('customerId', $customerId))
->addFilter(new NotFilter('AND', [new EqualsFilter('stateId', StateMachineInstaller::STATE_CANCELLED_ID)]));
$subscriptionOrderRepository = $this->container->get('lnb_subscription_order.repository');
$activeSubscriptionCount = $subscriptionOrderRepository->search($criteria, $context)->count();
$customerRepository = $this->container->get('customer.repository');
$customerRepository->update([
[
'id' => $customerId,
'customFields' => [
'lnb_custom_fields_active_subscription_count' => $activeSubscriptionCount
],
]
], $context);
}
private function updateAllSubscriptionChildren(string $subscriptionId, Context $context): void
{
$criteria = new Criteria();
$criteria
->addAssociation('lineItems')
->addFilter(new EqualsFilter('lineItems.customFields.LnbSubscription.lnbSubscriptionOrderId', $subscriptionId));
$orderRepository = $this->container->get('order.repository');
$orders = $orderRepository->search($criteria, $context)->getElements();
foreach ($orders as $order) {
$this->setOrderCustomField($order->getId(), 'lnb_custom_fields_parent_subscription_canceled', true, $context);
}
}
private function setOrderCustomField(string $orderId, string $fieldName, mixed $fieldValue ,Context $context)
{
$orderRepository = $this->container->get('order.repository');
$orderRepository->update([
[
'id' => $orderId,
'customFields' => [
$fieldName => $fieldValue
],
]
], $context);
}
private function getOrder(Context $context, string $orderId): OrderEntity
{
/** @var EntityRepository $orderRepository */
$orderRepository = $this->container->get('order.repository');
$criteria = new Criteria([$orderId]);
$criteria->addAssociation('lineItems');
$criteria->addAssociation('lineItems.product');
$criteria->addAssociation('orderCustomer.customer');
return $orderRepository->search($criteria, $context)->first();
}
}