<?php declare(strict_types=1);
namespace Compra\EnvironmentalDiscountSW6\Storefront\Subscriber;
use Compra\EnvironmentalDiscountSW6\Core\System\EnvironmentalDiscountService;
use Compra\InvoiceDispatchSW6\Core\System\InvoiceDispatchService;
use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
use Shopware\Core\Checkout\Order\OrderEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Shopware\Core\Framework\Validation\BuildValidationEvent;
use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Finish\CheckoutFinishPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Validator\Constraints\NotBlank;
class FrontendSubscriber implements EventSubscriberInterface
{
/** @var EnvironmentalDiscountService */
protected $environmentalDiscountService;
/** @var InvoiceDispatchService */
protected $invoiceDispatchService;
/** @var Request */
protected $request;
public function __construct(
EnvironmentalDiscountService $environmentalDiscountService,
InvoiceDispatchService $invoiceDispatchService,
RequestStack $requestStack
)
{
$this->environmentalDiscountService = $environmentalDiscountService;
$this->invoiceDispatchService = $invoiceDispatchService;
$this->request = $requestStack->getCurrentRequest();
}
/**
* @return string[]
*/
public static function getSubscribedEvents(): array
{
return [
CheckoutConfirmPageLoadedEvent::class => 'onCheckoutConfirm',
'framework.validation.order.create' => 'onBuildValidation',
CheckoutFinishPageLoadedEvent::class => 'onCheckoutFinishLoaded',
CheckoutOrderPlacedEvent::class => 'onOrderPlacedEvent'
];
}
/**
* Helper function to add validation fields for order create validation.
* Add constraint notBlank on invoice mail address if 'mail' is selected
*
* @param BuildValidationEvent $event
*/
public function onBuildValidation(BuildValidationEvent $event): void
{
if ($event->getDefinition()->getName() !== 'order.create') {
return;
}
// add constraint notBlank on invoice mail address if 'mail' is selected
if ($this->request->get('environmental_discount') === InvoiceDispatchService::INVOICE_DISPATCH_MAIL) {
$event->getDefinition()->add('invoice_mail_address', new NotBlank());
}
}
/**
* Subscribes the CheckoutConfirmPageLoadedEvent to set current invoice dispatch mode/mail + template vars.
* Also checks if should display the environmental discount panel.
* @param CheckoutConfirmPageLoadedEvent $event
*/
public function onCheckoutConfirm(CheckoutConfirmPageLoadedEvent $event)
{
$salesChannelContext = $event->getSalesChannelContext();
$customer = $event->getSalesChannelContext()->getCustomer();
if (!$customer) {
return;
}
$customFields = $customer->getCustomFields();
// get all payment IDs for which the environmental discount is allowed
$invoicePayments = $this->environmentalDiscountService->getPluginConfig('invoicePayment');
// get the configured or default environmental discount amount for the display in storefront
$environmentalDiscount = abs($this->environmentalDiscountService->getPluginConfig('environmentalDiscount') ?? EnvironmentalDiscountService::ENVIRONMENTAL_DISCOUT_PRICE_DEFAULT);
$currentPaymentMethod = $event->getSalesChannelContext()->getPaymentMethod();
$currentPaymentMethodId = $currentPaymentMethod->getId();
$customerInvoiceMailEnabled = false;
$currentOption = $this->environmentalDiscountService->getCurrentOption($customer);
$currentInvoiceMailAddress = $this->environmentalDiscountService->getCurrentInvoiceMailAddress($customer);
$showPanel = false;
if ($customFields && array_key_exists('compra_invoice_mail_enabled', $customFields)) {
$customerInvoiceMailEnabled = $customFields['compra_invoice_mail_enabled'];
}
if (!$customerInvoiceMailEnabled && $invoicePayments && in_array($currentPaymentMethodId, $invoicePayments, true)
&& $currentPaymentMethod->getActive() && in_array($currentPaymentMethodId, $salesChannelContext->getSalesChannel()->getPaymentMethodIds(), true)) {
/*
* Show the environmental discount panel if:
* - current customer invoice dispatch is not already 'mail' AND
* - payments for invoice/environmental discount are set AND
* - current payment method is allowed for environmental discount AND
* - current payment method is active AND
* - current payment method is allowed for the current sales channel
*/
$showPanel = true;
}
/*
* Set the session values.
* Because otherwise, if we only load the checkout/confirm page and customer won't select an invoice dispatch method,
* no change session value ajax call will be performed via JS and therefore no session value will be set.
*/
$this->environmentalDiscountService->setCurrentOption($currentOption);
$this->environmentalDiscountService->setCurrentInvoiceMailAddress($currentInvoiceMailAddress);
$event->getPage()->addExtension('environmental_discount', new ArrayEntity([
'currentOption' => $currentOption,
'currentInvoiceMailAddress' => $currentInvoiceMailAddress,
'showPanel' => $showPanel,
'discount' => $environmentalDiscount
]));
}
/**
* Subscribes the CheckoutFinishPageLoaded to save the invoice dispatch method and mail address after successful order.
* This is a little fallback for plugins that skip the CheckoutOrderPlacedEvent (e.g. PayPal)
*
* @param CheckoutFinishPageLoadedEvent $event
*/
public function onCheckoutFinishLoaded(CheckoutFinishPageLoadedEvent $event): void
{
$order = $event->getPage()->getOrder();
$this->saveInvoiceDispatchAfterOrder($order, $event->getContext());
/*
* ONLY HERE:
* Unset session invoice dispatch mode after successful save of data.
* Don't already unset on CheckoutOrderPlacedEvent because some checkout plugins (e.g. PayPal) skip the CheckoutOrderPlacedEvent.
* Therefore session data could only be unset here.
*/
$this->environmentalDiscountService->unsetCurrentOption();
$this->environmentalDiscountService->unsetCurrentInvoiceMailAddress();
}
/**
* Subscribes the CheckoutOrderPlacedEvent to save the invoice dispatch method and mail address after successful order.
* @param CheckoutOrderPlacedEvent $event
*/
public function onOrderPlacedEvent(CheckoutOrderPlacedEvent $event): void
{
$order = $event->getOrder();
$this->saveInvoiceDispatchAfterOrder($order, $event->getContext());
}
/**
* Helper function to save the invoice dispatch data after successful order.
*
* @param OrderEntity $order
* @param Context $context
*/
protected function saveInvoiceDispatchAfterOrder(OrderEntity $order, Context $context): void
{
$orderCustomer = $order->getOrderCustomer();
if (!$orderCustomer) {
return;
}
$customer = $orderCustomer->getCustomer();
if (!$customer) {
return;
}
$invoiceDispatchMode = $this->environmentalDiscountService->getCurrentOption($customer);
$invoiceMailAddress = $this->environmentalDiscountService->getCurrentInvoiceMailAddress($customer);
$this->invoiceDispatchService->saveInvoiceDispatch($invoiceDispatchMode, $invoiceMailAddress, $customer, $context);
}
}