<?php
declare(strict_types=1);
namespace Bodymed\Webshop\StoreFront\Subscriber;
use Bodymed\Webshop\BusinessEvent\OrderShopOwnerNotification;
use Bodymed\Webshop\Constants;
use Bodymed\Webshop\Core\Checkout\Customer\CustomerPharmacyCooperation\CustomerPharmacyCooperationEntity;
use Bodymed\Webshop\Core\Checkout\Order\NomsOrderSync\NomsOrderSyncService;
use Bodymed\Webshop\Event\BeforePersistOrderCustomFields;
use Bodymed\Webshop\Messenger\Messages\Order\AddOrderToSyncQueue;
use Bodymed\Webshop\Messenger\Messages\Order\OrderPlaced;
use Bodymed\Webshop\Core\Content\BodymedCenter\BodymedCenterEntity;
use Bodymed\Webshop\Messenger\Stamp\OrderIdStamp;
use Bodymed\Webshop\Nessync\Messenger\OrderNotifier;
use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
use Shopware\Core\Checkout\Order\Aggregate\OrderCustomer\OrderCustomerEntity;
use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
use Shopware\Core\Checkout\Order\OrderEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Event\EventData\MailRecipientStruct;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\Messenger\Envelope;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Messenger\MessageBusInterface;
class OrderSubscriber implements EventSubscriberInterface
{
public function __construct(
private MessageBusInterface $bus,
private EntityRepository $orderCustomerRepository,
private EntityRepository $orderAddressRepository,
private EntityRepository $orderRepository,
private EventDispatcherInterface $eventDispatcher,
private SystemConfigService $systemConfigService,
private NomsOrderSyncService $nomsOrderSyncService,
) {
}
public static function getSubscribedEvents(): array
{
return [
CheckoutOrderPlacedEvent::class => [
['completeOrderData', 100],
['addOrderToSyncQueue', -100],
['sendShopOwnerNotification', PHP_INT_MIN]
],
];
}
public function completeOrderData(CheckoutOrderPlacedEvent $event): void
{
$context = $event->getContext();
$order = $event->getOrder();
$orderCustomer = $order->getOrderCustomer();
$orderCustomerCustomFields = $orderCustomer->getCustomer()->getCustomFields();
$this->updateOrderAddress($order, $context);
/* @var $order OrderEntity */
$order = $this->refreshOrder($order->getId(), $context);
/**
* Schreibt in den OrderCustomer die UserServiceId des Kunden
*/
if (isset($orderCustomerCustomFields[Constants::CUSTOMER_ATTRIBUTE_BODYMED_USER_ID])) {
$userServiceId = $orderCustomerCustomFields[Constants::CUSTOMER_ATTRIBUTE_BODYMED_USER_ID];
if (!empty($userServiceId)) {
$orderCustomerCustomFields[Constants::USER_SERVICE_ID_KEY] = $userServiceId;
$this->orderCustomerRepository->update([[
'id' => $orderCustomer->getId(),
'customFields' => $orderCustomerCustomFields,
]], $context);
}
}
$this->extendOrderCustomFields($order, $context);
}
/**
* Schreibt die Email des Kunden in die CustomFields von
* BillingAddress und ShippingAddresses
*
* @see https://madcode.atlassian.net/browse/BODYMED-412
*/
private function updateOrderAddress(OrderEntity $order, Context $context): void
{
$customerEmail = $order->getOrderCustomer()->getCustomer()->getEmail();
$orderAddresses = [];
foreach ($order->getDeliveries() as $delivery) {
$orderAddresses[] = [
'id' => $delivery->getShippingOrderAddress()->getId(),
'customFields' => \array_merge($delivery->getShippingOrderAddress()->getCustomFields() ?? [], [
Constants::ORDER_DELIVERY_NOTIFICATION_EMAIL_ADDRESS_KEY => $customerEmail,
])
];
}
$billingAddress = $this->orderAddressRepository->search(
new Criteria([$order->getBillingAddressId()]),
$context
)->first();
if ($billingAddress) {
$orderAddresses[] = [
'id' => $billingAddress->getId(),
'customFields' => \array_merge($billingAddress->getCustomFields() ?? [], [
Constants::ORDER_DELIVERY_NOTIFICATION_EMAIL_ADDRESS_KEY => $customerEmail,
])
];
}
$this->orderAddressRepository->update($orderAddresses, $context);
}
public function addOrderToSyncQueue(CheckoutOrderPlacedEvent $event): void
{
$context = $event->getContext();
$order = $event->getOrder();
$salesChannelId = $event->getSalesChannelId();
$this->nomsOrderSyncService->createForNewOrder($order->getId(), $context);
}
/**
* Bietet Erweiterungspunkt, um customFields der Order vor dem Speichern zu befüllen
*/
private function extendOrderCustomFields(OrderEntity $order, Context $context): void
{
$this->eventDispatcher->dispatch(new BeforePersistOrderCustomFields(
$order,
$context
));
$this->orderRepository->upsert([
[
'id' => $order->getId(),
'customFields' => $order->getCustomFields(),
],
], $context);
}
private function refreshOrder(string $orderId, Context $context): OrderEntity
{
$criteria = new Criteria([$orderId]);
$criteria
->addAssociation('deliveries.shippingMethod')
->addAssociation('deliveries.shippingOrderAddress.country')
->addAssociation('transactions.paymentMethod')
->addAssociation('lineItems')
->addAssociation('lineItems.children')
->addAssociation('currency')
->addAssociation('addresses.country');
/* @var $orderEntity OrderEntity */
$orderEntity = $this->orderRepository->search($criteria, $context)->first();
$orderEntity->setOrderCustomer(
$this->fetchCustomer($orderEntity->getId(), $context)
);
return $orderEntity;
}
public function sendShopOwnerNotification(CheckoutOrderPlacedEvent $event): void
{
$adminMail = $this->systemConfigService->getString('core.basicInformation.email', $event->getSalesChannelId());
$receivers = [
$adminMail => $event->getOrder()->getOrderCustomer()->getCustomer()->getEmail(),
];
$shopOwnerNotificationEvent = new OrderShopOwnerNotification(
$event->getOrder(),
$event->getContext(),
$event->getSalesChannelId(),
new MailRecipientStruct($receivers),
);
$this->eventDispatcher->dispatch($shopOwnerNotificationEvent);
}
private function fetchCustomer(string $orderId, Context $context): OrderCustomerEntity
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('orderId', $orderId));
$criteria->addAssociation('customer');
$criteria->addAssociation('salutation');
return $this->orderCustomerRepository
->search($criteria, $context)
->first();
}
}