<?php
declare(strict_types=1);
namespace Madco\Mykey\Subscriber;
use Bodymed\Webshop\Constants as WebshopConstants;
use Bodymed\Webshop\Core\Checkout\Customer\CustomerPharmacyCooperation\PharmacyCooperationService;
use Bodymed\Webshop\Core\Content\BodymedCenter\BodymedCenterEntity;
use Bodymed\Webshop\Core\Content\CustomerPartnerMap\CustomerPartnerMapEntity;
use Bodymed\Webshop\Event\BeforePersistOrderCustomFields;
use Bodymed\Webshop\StoreFront\Service\CustomerOriginDetector;
use Bodymed\Webshop\StoreFront\Service\CustomerTypeChecker;
use Madco\Mykey\Constants;
use Madco\Mykey\Service\MykeyCustomerService;
use Madco\Mykey\Service\MykeyPersister;
use Madco\Mykey\Struct\CurrentMykeyAffiliate;
use Madco\Mykey\Struct\CurrentMykeyPartner;
use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
use Shopware\Core\Checkout\Customer\CustomerEntity;
use Shopware\Core\Checkout\Order\OrderEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class OrderSubscriber implements EventSubscriberInterface
{
private MykeyCustomerService $mykeyCustomerService;
private EntityRepositoryInterface $orderRepository;
private MykeyPersister $mykeyPersister;
private EntityRepositoryInterface $customerRepository;
private CustomerOriginDetector $customerOriginDetector;
private CustomerTypeChecker $customerTypeChecker;
private EntityRepositoryInterface $customerPharmacyCooperationRepository;
private PharmacyCooperationService $pharmacyCooperationService;
public function __construct(
MykeyCustomerService $mykeyCustomerService,
MykeyPersister $mykeyPersister,
EntityRepositoryInterface $orderRepository,
EntityRepositoryInterface $customerRepository,
CustomerOriginDetector $customerOriginDetector,
CustomerTypeChecker $customerTypeChecker,
PharmacyCooperationService $pharmacyCooperationService
) {
$this->mykeyCustomerService = $mykeyCustomerService;
$this->orderRepository = $orderRepository;
$this->mykeyPersister = $mykeyPersister;
$this->customerRepository = $customerRepository;
$this->customerOriginDetector = $customerOriginDetector;
$this->customerTypeChecker = $customerTypeChecker;
$this->pharmacyCooperationService = $pharmacyCooperationService;
}
public static function getSubscribedEvents(): array
{
return [
CheckoutOrderPlacedEvent::class => [
['completeOrderData', 150],
],
BeforePersistOrderCustomFields::class => 'onBeforePersistOrderCustomFields',
];
}
public function onBeforePersistOrderCustomFields(BeforePersistOrderCustomFields $event): void
{
$order = $event->getOrder();
$context = $event->getContext();
$orderCustomer = $order->getOrderCustomer();
$customerEntity = $this->customerRepository->search(
new Criteria([$orderCustomer->getCustomerId()]),
$context
)->first();
$orderCustomFields = $order->getCustomFields() ?? [];
$customerCustomFields = $customerEntity->getCustomFields();
if (isset($customerCustomFields[WebshopConstants::CUSTOMER_ATTRIBUTE_ORIGIN])) {
$orderCustomFields[WebshopConstants::ORDER_CUSTOM_FIELD_CUSTOMER_ORIGIN] = $customerCustomFields[WebshopConstants::CUSTOMER_ATTRIBUTE_ORIGIN];
}
$order->setCustomFields($orderCustomFields);
}
public function completeOrderData(CheckoutOrderPlacedEvent $event): void
{
$context = $event->getContext();
$order = $event->getOrder();
$orderCustomer = $order->getOrderCustomer();
$customerEntity = $orderCustomer->getCustomer();
$mykeyPartnerData = $context->getExtension(Constants::MYKEY_PARTNER_SESSION_ATTRIBUTE);
$mykeyAffiliateData = $context->getExtension(Constants::MYKEY_AFFILIATE_SESSION_ATTRIBUTE);
$customerOriginReferrer = null;
if ($mykeyPartnerData instanceof CurrentMykeyPartner) {
$this->mykeyPersister->persistPartnerCenter($mykeyPartnerData, $customerEntity, $context);
$customerOriginReferrer = $mykeyPartnerData->getOrigin();
}
if ($mykeyAffiliateData instanceof CurrentMykeyAffiliate && null === $mykeyPartnerData) {
$this->mykeyPersister->persistAffiliateCenter($mykeyAffiliateData, $customerEntity, $context);
$customerOriginReferrer = $mykeyAffiliateData->getOrigin();
}
$this->handleCustomerOrigin($customerEntity, $customerOriginReferrer, $context);
$customerEntity = $this->customerRepository->search(new Criteria([$customerEntity->getId()]), $context)->first();
$partnerMap = $this->mykeyCustomerService->getPartnerMapForCustomer($customerEntity);
if ($partnerMap) {
$this->updateOrderCustomFields($order, $partnerMap, $context);
}
if ($this->customerTypeChecker->isCustomerPartner()) {
$this->addOwnCenterDataToOrder($order, $customerEntity, $context);
}
if ($this->customerTypeChecker->isCustomerPharmacy()) {
$this->addPharmacyCooperationDataToOrder($order, $customerEntity, $context);
}
}
/**
* Schreibt die aktuellen mykey-Daten des Kunden in die Bestellung.
*
* @see https://madcode.atlassian.net/browse/BODYMED-295
*/
private function updateOrderCustomFields(OrderEntity $order, CustomerPartnerMapEntity $partnerMap, Context $context): void
{
$customFieldData = $partnerMap->getOrderData();
$orderData = [
[
'id' => $order->getId(),
'customFields' => \array_merge($order->getCustomFields() ?? [], [
Constants::MYKEY_ORDER_CUSTOM_FIELD_KEY => $customFieldData,
]),
],
];
if ($partnerMap->getAffiliateBodymedCenter()) {
$orderData[0]['customFields'][Constants::MYKEY_ORDER_AFFILIATE_CUSTOMER_NUMBER_FIELD_KEY] = $partnerMap->getAffiliateBodymedCenter()->getCustomerNumber();
}
$this->orderRepository->update($orderData, $context);
}
private function handleCustomerOrigin(
CustomerEntity $customer,
?string $customerOriginReferrer,
Context $context
): void {
$customerOrigin = $this->customerOriginDetector->detect(
$customer,
$customerOriginReferrer
);
$this->customerRepository->upsert([
[
'id' => $customer->getId(),
'customFields' => \array_merge($customer->getCustomFields() ?? [], [
WebshopConstants::CUSTOMER_ATTRIBUTE_ORIGIN => $customerOrigin,
]),
],
], $context);
}
/**
* Schreibt die eigene CustomerNumber eines Partners (BodymedCenter) als "mykey_partner" in die Bestellung,
* damit diese Bestellung in der eigenen Statistik des Partners gelistet wird.
*/
private function addOwnCenterDataToOrder(OrderEntity $order, CustomerEntity $customer, Context $context): void
{
$orderData = [
'id' => $order->getId(),
'customFields' => \array_merge($order->getCustomFields() ?? [], [
Constants::MYKEY_ORDER_AFFILIATE_CUSTOMER_NUMBER_FIELD_KEY => $customer->getCustomerNumber(),
WebshopConstants::ORDER_CUSTOM_FIELD_CUSTOMER_ORIGIN => WebshopConstants::CUSTOMER_ORIGIN_CENTER,
]),
];
$this->orderRepository->update([
$orderData,
], $context);
}
/**
* Schreibt die CustomerNumber des kooperierenden BodymedCenters als "mykey_partner" in die Bestellung,
* damit diese als Kooperationsverkauf gelistet wird.
*/
private function addPharmacyCooperationDataToOrder(OrderEntity $order, CustomerEntity $customer, Context $context): void
{
$cooperationCenter = $this->pharmacyCooperationService->getCooperationCenterForCustomer($customer, $context);
if ($cooperationCenter instanceof BodymedCenterEntity
&& null !== $cooperationCenter->getCustomerNumber()
) {
$orderData = [
'id' => $order->getId(),
'customFields' => \array_merge($order->getCustomFields() ?? [], [
Constants::MYKEY_ORDER_AFFILIATE_CUSTOMER_NUMBER_FIELD_KEY => $cooperationCenter->getCustomerNumber(),
WebshopConstants::ORDER_CUSTOM_FIELD_CUSTOMER_ORIGIN => WebshopConstants::CUSTOMER_ORIGIN_COOPERATION,
WebshopConstants::ORDER_CUSTOM_FIELD_COOP_AFFILIATION => [
'coop_customer_number' => $cooperationCenter->getCustomerNumber(),
'coop_affiliate_id' => $cooperationCenter->getAffiliateId(),
'coop_name' => $cooperationCenter->getName(),
]
]),
];
$this->orderRepository->update([
$orderData,
], $context);
}
}
}