<?php
declare(strict_types=1);
namespace App\Module\Checkout\Subscriber;
use App\Module\Account\Entity\User;
use App\Module\Account\Repository\CustomerRepository;
use App\Module\Checkout\Provider\DeniosCustomerProviderInterface;
use BestIt\CommercetoolsODM\Exception\ResponseException;
use App\Module\ShortSimpleCheckout\Event\Cart\CartCreateOrderEvent;
use App\Module\ShortSimpleCheckout\Events;
use BestIt\CommercetoolsODM\Exception\APIException;
use Commercetools\Core\Model\Customer\Customer;
use Commercetools\Core\Model\CustomField\CustomFieldObject;
use Commercetools\Core\Model\Type\TypeReference;
use Denios\SharedConstant\Order\OrderCustom;
use Denios\SharedConstant\Types\CustomTypes;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use \App\Module\Shared\Repository\Commercetools\CustomerRepository as sdkCustomerRepository;
/**
* Handling events before the order is created.
*
* @see OrderCreatedSubscriber for events after the order has been created
*
* @author André Varelmann <andre.varelmann@bestit-online.de>
* @package App\Module\Checkout\Subscriber
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class OrderAddressToCustomerSubscriber implements EventSubscriberInterface
{
private CustomerRepository $customerRepository;
private RequestStack $requestStack;
private DeniosCustomerProviderInterface $deniosCustomerProvider;
private sdkCustomerRepository $sdkCustomerRepository;
/**
* @param CustomerRepository $customerRepository
* @param RequestStack $requestStack
* @param DeniosCustomerProviderInterface $deniosCustomerProvider
* @param LoggerInterface $logger
* @param SdkCustomerRepository $sdkCustomerRepository
*/
public function __construct(
CustomerRepository $customerRepository,
RequestStack $requestStack,
DeniosCustomerProviderInterface $deniosCustomerProvider,
LoggerInterface $logger,
SdkCustomerRepository $sdkCustomerRepository,
) {
$this->customerRepository = $customerRepository;
$this->requestStack = $requestStack;
$this->deniosCustomerProvider = $deniosCustomerProvider;
$this->logger = $logger;
$this->sdkCustomerRepository = $sdkCustomerRepository;
}
/**
* @return array
*/
public static function getSubscribedEvents(): array
{
return [
Events::CART_CREATE_ORDER => [
['updateCustomerAddress'],
]
];
}
public function updateCustomerAddress(CartCreateOrderEvent $event): void
{
$cart = $event->getCart();
$customerId = $cart->getCustomerId();
if ($customerId === null) {
return;
}
/** @var Customer|null $customer */
$customer = $this->customerRepository->find($customerId);
if (!$customer instanceof Customer) {
return;
}
$request = $this->requestStack->getMainRequest();
if ($request !== null && $request->request->getInt('savePayment') !== 1) {
$customer->setCustom($this->updateCustomerPaymentType($cart, $customer));
}
$customerCustomData = $customer->getCustom()->getFields()->toArray();
if (array_key_exists('companyNumber', $customerCustomData) && $customerCustomData['companyNumber'] !== null)
{
$customer = $this->sdkCustomerRepository->setDefaultAddressesByIds(
$customer,
$cart->getBillingAddress()->getId() ?? null,
$cart->getShippingAddress()->getId() ?? null
);
} elseif (array_key_exists('businessPartner', $customerCustomData) && $customerCustomData['companyNumber'] !== null) {
$customer->setCustom($this->setCustomerCustomField(
$customer,
'defaultBillingAddressId',
$cart->getBillingAddress()->getId()
));
$customer->setCustom($this->setCustomerCustomField(
$customer,
'defaultShippingAddressId',
$cart->getShippingAddress()->getId()
));
}
$customer = $this->sdkCustomerRepository->updateCustomFields($customer);
$this->customerRepository->getDocumentManager()->getUnitOfWork()->registerAsManaged(
$customer,
$customer->getId(),
$customer->getVersion()
);
}
public function updateCustomerPaymentType ($cart, $customer): CustomFieldObject
{
return $this->setCustomerCustomField(
$customer,
'preferredPaymentType',
$cart->getCustom()->getFields()->getFieldAsString(OrderCustom::PAYMENT_TYPE)
);
}
/**
* @param CartCreateOrderEvent $event
*
* @return void
* @throws ResponseException
* @deprecated
*/
public function onCreateOrder(CartCreateOrderEvent $event): void
{
$deniosCustomer = $this->deniosCustomerProvider->getCustomer();
if (!$deniosCustomer instanceof User) {
return;
}
/** @var Customer|null $customer */
$customer = $this->customerRepository->find($deniosCustomer->getId());
if ($customer !== null) {
$cart = $event->getCart();
$request = $this->requestStack->getMainRequest();
if ($request !== null && $request->request->getInt('savePayment') !== 1) {
$customer->setCustom($this->setCustomerCustomField(
$customer,
'preferredPaymentType',
$cart->getCustom()->getFields()->getFieldAsString(OrderCustom::PAYMENT_TYPE)
));
}
if ($deniosCustomer->getCompanyNumber() !== null) {
$defaultBillingAddress = $customer->getAddresses()->getByKey(
$cart->getBillingAddress()->getKey()
);
if (null !== $defaultBillingAddress) {
$customer->setDefaultBillingAddressId($defaultBillingAddress->getId());
}
$defaultShippingAddress = $customer->getAddresses()->getByKey(
$cart->getShippingAddress()->getKey()
);
if (null !== $defaultShippingAddress) {
$customer->setDefaultShippingAddressId($defaultShippingAddress->getId());
}
} elseif ($deniosCustomer->getBusinessPartner() !== null) {
$customer->setCustom($this->setCustomerCustomField(
$customer,
'defaultBillingAddressId',
$cart->getBillingAddress()->getId()
));
$customer->setCustom($this->setCustomerCustomField(
$customer,
'defaultShippingAddressId',
$cart->getShippingAddress()->getId()
));
}
try {
$this->customerRepository->save($customer, true);
} catch (APIException $e) {
$this->logger->error('broken cart can not set customer data:'.$cart->getId());
}
}
}
/**
* Sets a custom field with a value on the customer
*
* @param Customer $customer
* @param string $key
* @param string $value
*
* @return CustomFieldObject
*/
private function setCustomerCustomField(Customer $customer, string $key, string $value): CustomFieldObject
{
$customs = [];
$custom = $customer->getCustom();
/** @phpstan-ignore-next-line */
if ($custom) {
$customs = $custom->getFields()->toArray();
}
$customs[$key] = $value;
return CustomFieldObject::fromArray([
'type' => TypeReference::ofKey(CustomTypes::CUSTOMER_TYPE),
'fields' => $customs
]);
}
}