<?php declare(strict_types=1);
/**
* Shopware
* Copyright © 2021
*
* @category Shopware
* @package SwpProductOptionsSix
* @subpackage OrderMailSubscriber.php
*
* @copyright 2021 Iguana-Labs GmbH
* @author Module Factory <info at module-factory.com>
* @license https://www.module-factory.com/eula
*/
namespace Swp\ProductOptionsSix\Subscriber\MailTemplate;
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemCollection;
use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
use Shopware\Core\Checkout\Order\OrderEntity;
use Shopware\Core\Content\MailTemplate\MailTemplateTypes;
use Shopware\Core\Content\MailTemplate\Service\Event\MailBeforeValidateEvent;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Swp\ProductOptionsSix\Core\Checkout\ProductOptions\Cart\ProductOptionsCartDataCollector;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class OrderMailSubscriber implements EventSubscriberInterface
{
/** @var EntityRepository */
private $mailTemplateRepository;
/** @var SystemConfigService */
private $systemConfigService;
/**
* @param EntityRepository $mailTemplateRepository
* @param SystemConfigService $systemConfigService
*/
public function __construct(
EntityRepository $mailTemplateRepository,
SystemConfigService $systemConfigService
) {
$this->mailTemplateRepository = $mailTemplateRepository;
$this->systemConfigService = $systemConfigService;
}
public static function getSubscribedEvents(): array
{
return [
MailBeforeValidateEvent::class => 'prepareOrderMailTemplate'
];
}
/**
* @param MailBeforeValidateEvent $event
*/
public function prepareOrderMailTemplate(MailBeforeValidateEvent $event): void
{
$mailData = $event->getData();
if (!\array_key_exists('templateId', $mailData)) {
return;
}
if ($mailData['templateId'] !== $this->getOrderConfirmationMailTemplateId($event->getContext())) {
return;
}
$order = $event->getTemplateData()['order'];
if ($order === null || !$order instanceof OrderEntity) {
return;
}
if ($this->isCannelActive($order->getSalesChannelId()) !== true) {
return;
}
$orderLineItemCollection = $order->getLineItems();
if ($orderLineItemCollection === null) {
return;
}
$orderLineItemCollection->sortByPosition();
$productWithOptionsLineItems = $orderLineItemCollection->filterByType(
ProductOptionsCartDataCollector::PRODUCT_OPTIONS_LINE_ITEM_TYPE
);
foreach ($productWithOptionsLineItems as $productWithOptionsLineItem) {
$childLineItems = $orderLineItemCollection->filterByProperty('parentId', $productWithOptionsLineItem->getId());
$this->setChildrenLabelAndValues($childLineItems, $orderLineItemCollection);
$productWithOptionsLineItem->setChildren($childLineItems);
}
$orderLineItemCollection = $orderLineItemCollection->filter(static function (OrderLineItemEntity $lineItem) {
return $lineItem->getType() !== ProductOptionsCartDataCollector::PRODUCT_OPTIONS_OPTION_LINE_ITEM_TYPE
&& $lineItem->getType() !== ProductOptionsCartDataCollector::PRODUCT_OPTIONS_OPTION_LINE_ITEM_TYPE_PRODUCT;
});
$orderLineItemCollection->sortByPosition();
$order->setLineItems($this->flattenOrderLineItemCollection($orderLineItemCollection));
}
/**
* @param Context $context
* @return string|null
*/
private function getOrderConfirmationMailTemplateId(Context $context): ?string
{
$criteria = new Criteria();
$criteria->addFilter(
new EqualsAnyFilter('mailTemplateType.technicalName', [
MailTemplateTypes::MAILTYPE_ORDER_CONFIRM,
MailTemplateTypes::MAILTYPE_STATE_ENTER_ORDER_TRANSACTION_STATE_PAID,
MailTemplateTypes::MAILTYPE_STATE_ENTER_ORDER_TRANSACTION_STATE_CANCELLED,
])
);
return $this->mailTemplateRepository->searchIds($criteria, $context)->firstId();
}
/**
* @param OrderLineItemCollection $optionsLineItems,
* @param OrderLineItemCollection $orderLineItemCollection
*/
private function setChildrenLabelAndValues(
OrderLineItemCollection $optionsLineItems,
OrderLineItemCollection $orderLineItemCollection
): void {
foreach ($optionsLineItems as $optionsLineItem) {
$payload = $optionsLineItem->getPayload();
$this->setLabels($optionsLineItem, $payload);
unset($payload['productNumber']);
$optionsLineItem->setPayload($payload);
/** @var OrderLineItemCollection $childLineItems */
$childLineItems = $orderLineItemCollection->filterByProperty('parentId', $optionsLineItem->getId());
if ($childLineItems->count() > 0) {
foreach ($childLineItems as $childLineItem) {
$payload = $childLineItem->getPayload();
if ($childLineItem->getType() === ProductOptionsCartDataCollector::PRODUCT_OPTIONS_OPTION_LINE_ITEM_TYPE_PRODUCT) {
$childLineItem->setLabel(\sprintf('* * %s (%s)', $childLineItem->getLabel(), $payload['productNumber']));
$childLineItem->setQuantity($optionsLineItem->getQuantity() * $childLineItem->getQuantity());
}
unset($payload['productNumber']);
$childLineItem->setPayload($payload);
}
$optionsLineItem->setChildren($childLineItems);
continue;
}
if ($value = $this->extractPayload($optionsLineItem)) {
$optionsLineItem->setLabel(\sprintf('%s (%s)', $optionsLineItem->getLabel(), $value));
}
}
}
/**
* @param OrderLineItemEntity $optionsLineItem
* @param array $payload
* @return void
*/
private function setLabels(
OrderLineItemEntity $optionsLineItem,
array $payload
): void {
if ($optionsLineItem->getType() === LineItem::PRODUCT_LINE_ITEM_TYPE) {
$optionsLineItem->setLabel(\sprintf('* %s (%s)', $optionsLineItem->getLabel(), $payload['productNumber']));
}
if ($optionsLineItem->getType() === ProductOptionsCartDataCollector::PRODUCT_OPTIONS_OPTION_LINE_ITEM_TYPE) {
$group = \array_key_exists('group', $payload) ? $payload['group'] : '';
$optionsLineItem->setLabel(\sprintf('* %s: %s', $group, $optionsLineItem->getLabel()));
}
}
/**
* @param OrderLineItemEntity $optionsLineItem
* @return string|null
*/
private function extractPayload(OrderLineItemEntity $optionsLineItem): ?string
{
$payload = $optionsLineItem->getPayload() ?? [];
$type = $payload['type'] ?? null;
switch($type) {
case 'textfield':
case 'textarea':
$value = $payload['optionText'];
break;
default:
$value = null;
}
return $value;
}
/**
* @param OrderLineItemCollection $orderLineItemCollection
* @return OrderLineItemCollection
*/
private function flattenOrderLineItemCollection(OrderLineItemCollection $orderLineItemCollection): OrderLineItemCollection
{
$newOrderLineItemCollection = new OrderLineItemCollection();
foreach ($orderLineItemCollection->getElements() as $item) {
$newOrderLineItemCollection->add($item);
$children = $item->getChildren();
if ($children !== null) {
$newOrderLineItemCollection->merge($this->flattenOrderLineItemCollection($children));
$item->setChildren(new OrderLineItemCollection());
}
}
return $newOrderLineItemCollection;
}
/**
* @param string $salesChannelId
* @return array|mixed|null
*/
private function isCannelActive(string $salesChannelId)
{
return $this->systemConfigService->get(
'SwpProductOptionsSix.config.channelActive',
$salesChannelId
);
}
}