<?php /** @noinspection JsonEncodingApiUsageInspection */
declare(strict_types=1);
namespace EsmComputer\Storefront\Subscriber;
use Shopware\Core\Checkout\Cart\Exception\CustomerNotLoggedInException;
use Shopware\Core\Checkout\Customer\Event\GuestCustomerRegisterEvent;
use Shopware\Core\Checkout\Customer\SalesChannel\AbstractListAddressRoute;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Shopware\Core\Framework\Struct\ArrayStruct;
use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
use Shopware\Core\System\Country\SalesChannel\AbstractCountryRoute;
use Shopware\Core\System\SalesChannel\Event\SalesChannelContextSwitchEvent;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\Salutation\SalesChannel\AbstractSalutationRoute;
use Shopware\Core\System\Salutation\SalutationCollection;
use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Finish\CheckoutFinishPageLoadedEvent;
use Swag\CmsExtensions\Form\Aggregate\FormGroup\FormGroupEntity;
use Swag\CmsExtensions\Form\Aggregate\FormGroupField\FormGroupFieldEntity;
use Swag\CmsExtensions\Form\Event\CustomFormEvent;
use Swag\CmsExtensions\Form\FormEntity;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Session;
use function array_key_exists;
use function hash;
use function json_decode;
use function json_encode;
class CheckoutSubscriber implements EventSubscriberInterface
{
private EntityRepository $formRepository;
private Session $session;
private EventDispatcherInterface $eventDispatcher;
private AbstractCountryRoute $countryRoute;
private AbstractSalutationRoute $salutationRoute;
private AbstractListAddressRoute $addressRoute;
public function __construct(
EntityRepository $formRepository,
Session $session,
EventDispatcherInterface $eventDispatcher,
AbstractCountryRoute $countryRoute,
AbstractSalutationRoute $salutationRoute,
AbstractListAddressRoute $addressRoute
)
{
$this->formRepository = $formRepository;
$this->session = $session;
$this->eventDispatcher = $eventDispatcher;
$this->countryRoute = $countryRoute;
$this->salutationRoute = $salutationRoute;
$this->addressRoute = $addressRoute;
}
public static function getSubscribedEvents(): array
{
return [
CheckoutConfirmPageLoadedEvent::class => 'onCheckoutConfirmPageLoaded',
CheckoutFinishPageLoadedEvent::class => 'onCheckoutFinishPageLoaded',
SalesChannelContextSwitchEvent::class => 'onSalesChannelContextSwitched',
GuestCustomerRegisterEvent::class => 'onGuestCustomerRegisterEvent'
];
}
public function onGuestCustomerRegisterEvent(GuestCustomerRegisterEvent $event): void
{
// Show Shipping after registration in checkout instead of the address accordion
$_SESSION['step'] = '#customerShipping';
$_SESSION['useDefaultPayment'] = true;
}
public function onSalesChannelContextSwitched(SalesChannelContextSwitchEvent $event): void
{
// Show Shipping after shipping or payment changed
if($event->getRequestDataBag()->get('paymentMethodId') || $event->getRequestDataBag()->get('shippingMethodId')) {
$_SESSION['step'] = '#customerShipping';
}
}
public function onCheckoutFinishPageLoaded(CheckoutFinishPageLoadedEvent $event): void
{
$form = $this->loadForm($event->getSalesChannelContext());
$sessionData = $this->session->get('return');
if($form && $sessionData) {
$this->eventDispatcher->dispatch(new CustomFormEvent($event->getSalesChannelContext(), $form, $sessionData), CustomFormEvent::EVENT_NAME);
}
$event->getPage()->addArrayExtension('emailHash', [hash("sha256", $event->getSalesChannelContext()->getCustomer()->getEmail())]);
}
public function onCheckoutConfirmPageLoaded(CheckoutConfirmPageLoadedEvent $event): void
{
$form = $this->loadForm($event->getSalesChannelContext());
if($form) {
$this->session->set('returnMessage', $form->getSuccessMessage());
$event->getPage()->addExtension('swagCmsExtensionsForm', $form);
}
if(array_key_exists('step', $_SESSION) && $_SESSION['step'] && $event->getSalesChannelContext()->getCustomer()) {
// Open payment/shipping accordion if one of them changed
$event->getPage()->addArrayExtension('step', [$_SESSION['step']]);
unset($_SESSION['step']);
}else {
// Load first step as default value
$event->getPage()->addArrayExtension('step', ['#customerData']);
}
//dd($event->getPage(), $event->getSalesChannelContext());
// Keep sorting, do not use active as first item
$paymentMethods = $event->getPage()->getPaymentMethods();
$paymentMethods->sort(fn($a, $b) => $a->getPosition() > $b->getPosition());
$event->getPage()->setPaymentMethods($paymentMethods);
$shippingMethods = $event->getPage()->getShippingMethods();
$shippingMethods->sort(fn($a, $b) => $a->getId() > $b->getId());
$event->getPage()->setShippingMethods($shippingMethods);
$salutations = $this->loadSalutations($event->getSalesChannelContext());
$event->getPage()->addExtension('salutations', $salutations);
$criteria = (new Criteria())->addFilter(new EqualsFilter('active', true))->addAssociation('states');
$countries = $this->countryRoute->load(new Request(), $criteria, $event->getSalesChannelContext())->getCountries();
$countries->sortCountryAndStates();
$event->getPage()->addExtension('countries', $countries);
// Append data to billing/shipping forms
if($customer = $event->getSalesChannelContext()->getCustomer()) {
$shippingAddress = json_decode(json_encode($customer->getActiveShippingAddress()), true);
$shippingAddress['accountType'] = 'private';
$bag = new RequestDataBag();
$bag->set('salutationId', $customer->getSalutationId());
$bag->set('firstName', $customer->getFirstName());
$bag->set('lastName', $customer->getLastName());
$bag->set('email', $customer->getEmail());
$bag->set('billingAddress', $customer->getActiveBillingAddress());
$bag->set('shippingAddress', $shippingAddress);
$bag->set('guest', true);
$event->getPage()->addExtension('data', new ArrayStruct([$bag]));
$criteria = (new Criteria())->addSorting(new FieldSorting('firstName', FieldSorting::ASCENDING));
$event->getPage()->addExtension('addresses', $this->addressRoute->load($criteria, $event->getSalesChannelContext(), $customer)->getAddressCollection());
}
}
private function loadSalutations(SalesChannelContext $salesChannelContext): SalutationCollection
{
return $this->salutationRoute->load(new Request(), $salesChannelContext, new Criteria())->getSalutations();
}
private function loadForm(SalesChannelContext $context): ?FormEntity
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('technicalName', 'Geräterückgabe'));
$criteria->addAssociation('groups.fields');
$criteria->addAssociation('mailTemplate');
$criteria->getAssociation('groups')
->addSorting(new FieldSorting('position'))
->getAssociation('fields')
->addSorting(new FieldSorting('position'));
// Dependency can be empty, if plugin is not installed
if(!$this->formRepository) {
return null;
}
/** @var FormEntity|null $form */
$form = $this->formRepository->search($criteria, $context->getContext())->getEntities()->first();
if(!$form) {
return null;
}
/** @var FormGroupEntity $group */
foreach($form->getGroups() as $group) {
/** @var FormGroupFieldEntity $field */
foreach($group->getFields() as $field) {
if($field->getType() === 'select' && array_key_exists('entity', $field->getConfig()) && $field->getConfig()['entity'] === 'salutation') {
$result = $this->loadSalutations($context);
$options = [];
foreach ($result as $entity) {
$options[$entity->getId()] = $entity->getTranslation('displayName');
}
$translated = $field->getTranslated();
$translated['config']['options'] = $options;
$field->setTranslated($translated);
}
}
}
return $form;
}
}