<?php
namespace Maxia\MaxiaTaxSwitch6\Storefront\Service;
use Maxia\MaxiaTaxSwitch6\Storefront\Events\TaxSwitchEvent;
use Shopware\Core\Checkout\Cart\Price\Struct\CartPrice;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class TaxSwitchService
{
public const TAX_SWITCH_ACTIVE_ATTR = 'maxia-tax-switch-active';
public const IS_NET_ATTR = 'maxia-is-net';
public const STATE_CHANGED_ATTR = 'maxia-net-changed';
public const COOKIE_NAME = 'maxia-is-net';
/**
* @var RequestStack
*/
protected $requestStack;
/**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* @var SystemConfigService
*/
protected $configService;
/**
* @param RequestStack $requestStack
* @param EventDispatcherInterface $eventDispatcher
* @param SystemConfigService $configService
*/
public function __construct(
RequestStack $requestStack,
EventDispatcherInterface $eventDispatcher,
SystemConfigService $configService
) {
$this->requestStack = $requestStack;
$this->eventDispatcher = $eventDispatcher;
$this->configService = $configService;
}
/**
* @param SalesChannelContext $context
* @return SalesChannelContext
*/
public function initializeContext(SalesChannelContext $context)
{
$config = $this->getContext($context);
if (!$config['pluginEnabled'] || !$this->getMainRequest()) {
return $context;
}
$this->getMainRequest()->attributes->set(static::TAX_SWITCH_ACTIVE_ATTR, true);
$isNet = $this->getDisplayNet($context);
if ($isNet === null) {
// initialize setting on first visit
$isNet = $config['preselection'] === 'net';
}
$this->setDisplayNet($context, $isNet);
// set context tax state according to current tax switch setting
$taxState = $isNet ? CartPrice::TAX_STATE_NET : CartPrice::TAX_STATE_GROSS;
$context->setTaxState($taxState);
$context->getContext()->setTaxState($taxState);
$context->getCurrentCustomerGroup()->setDisplayGross(!$isNet);
return $context;
}
/**
* Returns the current tax switch setting.
*
* @param SalesChannelContext $context
* @return bool
*/
public function getDisplayNet(SalesChannelContext $context)
{
$config = $this->getConfig($context);
if (!$config || !$config['pluginEnabled'] || !$this->getMainRequest() || $this->isApiRequest()) {
return null;
}
$value = $this->getUrlParameterValue($context);
if ($value !== null) {
return $value;
}
$attrValue = $this->getMainRequest()->attributes->get(static::IS_NET_ATTR);
$cookieValue = $this->getMainRequest()->cookies->get(static::COOKIE_NAME);
if ($attrValue !== null) {
return (bool)$attrValue;
}
if ($cookieValue !== null) {
return (bool)$cookieValue;
}
if ($this->getSession()) {
$value = $this->getSession()->get(static::IS_NET_ATTR);
if ($value !== null) {
return $value;
}
}
return null;
}
/**
* Updates the tax switch setting.
*
* @param SalesChannelContext $context
* @param bool $displayNet
*/
public function setDisplayNet(SalesChannelContext $context, bool $displayNet)
{
$changed = false;
$valueBefore = $this->getDisplayNet($context);
if ($this->getMainRequest()) {
$this->getMainRequest()->attributes->set(static::IS_NET_ATTR, $displayNet);
if ($valueBefore !== $displayNet) {
$changed = true;
}
if ($this->getSession() && $this->getSession()->get(static::IS_NET_ATTR) !== $displayNet)
{
$this->getSession()->set(static::IS_NET_ATTR, $displayNet);
$changed = true;
}
$cookieValue = $this->getMainRequest()->cookies->get(static::COOKIE_NAME);
if ($cookieValue !== null && (bool)$cookieValue !== $displayNet) {
$this->getMainRequest()->cookies->set(static::COOKIE_NAME, $displayNet);
$changed = true;
}
if ($changed) {
$this->getMainRequest()->attributes->set(static::STATE_CHANGED_ATTR, true);
$this->eventDispatcher->dispatch(new TaxSwitchEvent($displayNet, $context));
}
}
}
/**
* Returns the plugin config as an array, including the current 'is net' state.
*
* @param SalesChannelContext $context
* @return array
*/
public function getConfig(SalesChannelContext $context)
{
return $this->configService->get('MaxiaTaxSwitch6.config', $context->getSalesChannel()->getId());
}
/**
* Returns the plugin config as an array, including the current 'is net' state.
*
* @param SalesChannelContext $context
* @return array
*/
public function getContext(SalesChannelContext $context)
{
return array_merge($this->getConfig($context), [
'isNet' => $this->getDisplayNet($context),
'pluginEnabled' => $this->checkIsActive($context)
]);
}
/**
* Returns the isNet value from URL parameter of the current master request
*
* @return bool|null
*/
public function getUrlParameterValue(SalesChannelContext $context)
{
$config = $this->getConfig($context);
if (!$config || !$config['urlParameterActive'] || !$this->getMainRequest()) {
return null;
}
$value = $this->getMainRequest()->get($config['urlParameterName']);
return $value !== null ? (bool)$value : null;
}
/**
* Checks if the switcher plugin should active in the given sales channel.
*
* @param SalesChannelContext $context
* @return bool
*/
public function checkIsActive(SalesChannelContext $context)
{
$config = $this->getConfig($context);
return isset($config['pluginEnabled']) && $config['pluginEnabled']
&& !$this->isApiRequest()
&& $this->getMainRequest() !== null
&& ($context->getTaxState() !== CartPrice::TAX_STATE_FREE || $config['activateTaxFreeCountries'])
&& (!$config['deactivateLoggedIn'] || $context->getCustomer() === null);
}
/**
* @return \Symfony\Component\HttpFoundation\Request|null
*/
protected function getMainRequest()
{
return method_exists($this->requestStack, 'getMainRequest')
? $this->requestStack->getMainRequest()
: $this->requestStack->getMasterRequest();
}
/**
* @return \Symfony\Component\HttpFoundation\Session\SessionInterface|null
*/
protected function getSession()
{
return ($this->getMainRequest()->hasSession() && $this->getMainRequest()->getSession()->isStarted())
? $this->getMainRequest()->getSession()
: null;
}
/**
* Checks if the current request is a Store-API request.
*
* @return bool
*/
protected function isApiRequest()
{
return $this->getMainRequest() &&
(str_starts_with($this->getMainRequest()->getPathInfo(), '/api/_proxy/store-api/') ||
str_starts_with($this->getMainRequest()->getPathInfo(), '/api/_proxy-order/') ||
str_starts_with($this->getMainRequest()->getPathInfo(), '/store-api/'));
}
}