<?php
declare(strict_types=1);
namespace Meteor\PromotionGift\Subscribers;
use Meteor\PromotionGift\Checker\LineItemIsFreeGiftInterface;
use Meteor\PromotionGift\Core\Checkout\Promotion\Cart\GiftProcessor;
use Meteor\PromotionGift\Dal\FetchCustomerCountsForPromotionsInterface;
use Meteor\PromotionGift\Dal\UpdatePromotionCountInterface;
use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
use Shopware\Core\Framework\Uuid\Uuid;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class FreeGiftRedemptionUpdater implements EventSubscriberInterface
{
private LineItemIsFreeGiftInterface $lineItemIsFreeGift;
private FetchCustomerCountsForPromotionsInterface $fetchCustomerCountsForPromotions;
private UpdatePromotionCountInterface $updatePromotionCount;
public function __construct(LineItemIsFreeGiftInterface $lineItemIsFreeGift, FetchCustomerCountsForPromotionsInterface $fetchCustomerCountsForPromotions, UpdatePromotionCountInterface $updatePromotionCount)
{
$this->lineItemIsFreeGift = $lineItemIsFreeGift;
$this->fetchCustomerCountsForPromotions = $fetchCustomerCountsForPromotions;
$this->updatePromotionCount = $updatePromotionCount;
}
public static function getSubscribedEvents(): array
{
return [
CheckoutOrderPlacedEvent::class => '__invoke',
];
}
public function __invoke(CheckoutOrderPlacedEvent $event): void
{
$lineItems = $event->getOrder()->getLineItems();
$customer = $event->getOrder()->getOrderCustomer();
if (!$lineItems || !$customer) {
return;
}
$customerId = $customer->getCustomerId();
$promotionIds = [];
foreach ($lineItems as $lineItem) {
if (!($this->lineItemIsFreeGift)($lineItem)) {
continue;
}
$promotionId = $this->fetchPromotionId($lineItem);
if (!$promotionId) {
continue;
}
$promotionIds[] = $promotionId;
}
if (0 === count($promotionIds)) {
return;
}
$promotionsUsedByCustomersCount = ($this->fetchCustomerCountsForPromotions)($promotionIds);
$calculatedPromotionsUsedByCustomer = [];
foreach ($promotionIds as $promotionId) {
$calculatedPromotionsUsedByCustomer[$promotionId] = $this->calculatePromotionUsedByCustomer(
$promotionsUsedByCustomersCount,
$promotionId,
$customerId
);
}
($this->updatePromotionCount)($promotionIds, $calculatedPromotionsUsedByCustomer);
}
private function calculatePromotionUsedByCustomer(array $allCustomerCounts, $promotionId, $customerId): array
{
$promotionUsedByCustomers = $allCustomerCounts[$promotionId] ?? null;
if (null === $promotionUsedByCustomers) {
// Prepare array if code isn't used yet
$allCustomerCounts[$promotionId] = [];
}
$promotionUsedByCurrentCustomer = $promotionUsedByCustomers[$customerId] ?? null;
if (null === $promotionUsedByCurrentCustomer) {
// initiate count if customer hasn't used promotion yet
$promotionUsedByCustomers[$customerId] = 1;
return $promotionUsedByCustomers;
}
// +1 if customer has used this code before
$promotionUsedByCustomers[$customerId] = $promotionUsedByCurrentCustomer + 1;
return $promotionUsedByCustomers;
}
private function fetchPromotionId(OrderLineItemEntity $lineItem): ?string
{
$payload = $lineItem->getPayload();
$payloadPromotionIdKey = $payload[GiftProcessor::PAYLOAD_PROMOTION_ID_KEY] ?? null;
if (null === $payloadPromotionIdKey) {
return null;
}
$promotionId = $payload[GiftProcessor::PAYLOAD_PROMOTION_ID_KEY] ?? null;
if (!Uuid::isValid((string) $promotionId)) {
return null;
}
return (string) $promotionId;
}
}