<?php
declare(strict_types=1);
namespace Zeobv\BundleProducts\Core\Subscriber;
use Throwable;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemCollection;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\EntityWriteResult;
use Shopware\Core\Checkout\Order\OrderDefinition;
use Shopware\Core\Checkout\Order\OrderEntity;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
/**
* Shopware doesn't create order_delivery_positions for child line items by default. This subscriber aims to fix that.
*
* Class OrderDeliveryPositionSubscriber
*
* @package Zeobv\BundleProducts\Core\Subscriber
*/
class OrderDeliveryPositionSubscriber implements EventSubscriberInterface
{
/**
* @var EntityRepositoryInterface
*/
protected $orderRepository;
/**
* @var EntityRepositoryInterface
*/
protected $orderDeliveryPositionRepository;
/**
* @var LoggerInterface
*/
protected $logger;
/**
* OrderDeliveryPositionSubscriber constructor.
*
* @param EntityRepositoryInterface $orderRepository
* @param EntityRepositoryInterface $orderDeliveryPositionRepository
* @param LoggerInterface $logger
*/
public function __construct(
EntityRepositoryInterface $orderRepository,
EntityRepositoryInterface $orderDeliveryPositionRepository,
LoggerInterface $logger
) {
$this->orderRepository = $orderRepository;
$this->orderDeliveryPositionRepository = $orderDeliveryPositionRepository;
$this->logger = $logger;
}
/**
* @return array
*/
public static function getSubscribedEvents(): array
{
return [
'order.written' => 'onOrderWritten'
];
}
/**
* @param EntityWrittenEvent $event
*/
public function onOrderWritten(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $writeResult) {
if ($writeResult->getOperation() !== EntityWriteResult::OPERATION_INSERT || $writeResult->getEntityName() !== OrderDefinition::ENTITY_NAME) {
continue;
}
try {
$orderId = $writeResult->getPrimaryKey();
if (is_array($orderId)) {
$this->logger->error(
'Unexpected primary key received from write result. Skipping order delivery position creation. Json encoded primary key: ' . json_encode(
$writeResult->getPrimaryKey()
)
);
continue;
}
$order = $this->getOrder($orderId, $event->getContext());
if ($order === null) {
continue;
}
$childLineItems = $order->getLineItems()->filter(function (OrderLineItemEntity $lineItem) {
return $lineItem->getParentId() !== null;
});
if ($childLineItems->count() < 1) {
continue;
}
$this->createOrderDeliveryPositionsForOrderLineItems(
$childLineItems,
$order->getDeliveries()->first()->getId(),
$event->getContext()
);
} catch (Throwable $e) {
$this->logger->error($e->getMessage());
}
}
}
/**
* @param string $orderId
* @param Context $context
*
* @return OrderEntity|null
*/
protected function getOrder(string $orderId, Context $context): ?OrderEntity
{
$criteria = new Criteria([$orderId]);
$criteria->addAssociations(['lineItems', 'deliveries']);
return $this->orderRepository->search($criteria, $context)->first();
}
/**
* @param OrderLineItemCollection $orderLineItemCollection
* @param string $orderDeliveryId
* @param Context $context
*
* @return EntityWrittenContainerEvent
*/
protected function createOrderDeliveryPositionsForOrderLineItems(
OrderLineItemCollection $orderLineItemCollection,
string $orderDeliveryId,
Context $context
): EntityWrittenContainerEvent
{
$orderDeliveryPositionsData = $orderLineItemCollection->map(
function (OrderLineItemEntity $orderLineItem) use ($orderDeliveryId) {
return [
'orderId' => $orderLineItem->getOrderId(),
'orderDeliveryId' => $orderDeliveryId,
'orderLineItemId' => $orderLineItem->getId(),
'price' => $orderLineItem->getPrice(),
'unitPrice' => $orderLineItem->getUnitPrice(),
'totalPrice' => $orderLineItem->getTotalPrice(),
'quantity' => $orderLineItem->getQuantity(),
];
}
);
return $this->orderDeliveryPositionRepository->create(array_values($orderDeliveryPositionsData), $context);
}
}