<?php declare(strict_types=1);
namespace Compra\EnvironmentalDiscountSW6\Core\System;
use Shopware\Core\Checkout\Cart\Cart;
use Shopware\Core\Checkout\Cart\CartPersisterInterface;
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Shopware\Core\Checkout\Cart\Price\AbsolutePriceCalculator;
use Shopware\Core\Checkout\Cart\Price\Struct\AbsolutePriceDefinition;
use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
use Shopware\Core\Checkout\Customer\CustomerEntity;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Contracts\Translation\TranslatorInterface;
class EnvironmentalDiscountService
{
public const PLUGIN_PREFIX = 'CompraEnvironmentalDiscountSW6.config.';
public const ENVIRONMENTAL_DISCOUNT_ORDERNUMBER = "99999";
public const INVOICE_DISPATCH_ALWAYS = 'mail';
public const ENVIRONMENTAL_DISCOUT_PRICE_DEFAULT = -0.4;
/** @var AbsolutePriceCalculator */
protected $calculator;
/** @var SystemConfigService */
protected $systemConfigService;
/** @var CartPersisterInterface */
protected $cartPersister;
/** @var TranslatorInterface */
protected $translator;
/** @var Request */
protected $request;
public function __construct(
AbsolutePriceCalculator $calculator,
SystemConfigService $systemConfigService,
CartPersisterInterface $cartPersister,
TranslatorInterface $translator,
RequestStack $requestStack
)
{
$this->calculator = $calculator;
$this->systemConfigService = $systemConfigService;
$this->cartPersister = $cartPersister;
$this->translator = $translator;
$this->request = $requestStack->getCurrentRequest();
}
/**
* Helper function to update the environmental discount cart line item.
* Checks for customer and invoice dispatch data to decide, whether to add the environmental discount or not.
*
* @param Cart $originalCart
* @param Cart $modifiedCart
* @param SalesChannelContext $context
*/
public function updateEnvironmentalDiscount(Cart $originalCart, Cart $modifiedCart, SalesChannelContext $context): void
{
$invoicePayments = $this->getPluginConfig('invoicePayment');
$customer = $context->getCustomer();
$currentOption = $this->getCurrentOption($customer);
$customerChangedToMail = null;
$customerInvoiceMailEnabled = null;
$currentPaymentMethod = $context->getPaymentMethod();
$currentPaymentMethodId = $currentPaymentMethod->getId();
// remove environmental discount from line items
if ($originalCart->getLineItems()->has(self::ENVIRONMENTAL_DISCOUNT_ORDERNUMBER)) {
$originalCart->getLineItems()->remove(self::ENVIRONMENTAL_DISCOUNT_ORDERNUMBER);
}
if ($modifiedCart->getLineItems()->has(self::ENVIRONMENTAL_DISCOUNT_ORDERNUMBER)) {
$modifiedCart->getLineItems()->remove(self::ENVIRONMENTAL_DISCOUNT_ORDERNUMBER);
}
// don't add any environmental discount if no line items in the cart
if (!$modifiedCart->getLineItems()->first()) {
return;
}
if ($customer) {
$customFields = $customer->getCustomFields();
if ($customFields && array_key_exists('compra_environmental_discount_has_changed_to_mail', $customFields)) {
$customerChangedToMail = $customFields['compra_environmental_discount_has_changed_to_mail'];
}
if ($customFields && array_key_exists('compra_invoice_mail_enabled', $customFields)) {
$customerInvoiceMailEnabled = $customFields['compra_invoice_mail_enabled'];
}
}
if (($currentOption === self::INVOICE_DISPATCH_ALWAYS || ($customerChangedToMail && $customerInvoiceMailEnabled))
&& ($invoicePayments && in_array($currentPaymentMethodId, $invoicePayments, true)
&& $currentPaymentMethod->getActive() && in_array($currentPaymentMethodId, $context->getSalesChannel()->getPaymentMethodIds(), true))) {
/*
* Add the environmental discount if:
* - current selected option from session is 'mail'
* OR
* - customer actively changed invoice dispatch to 'mail' and 'mail' is still enabled 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
*
*/
$this->insertEnvironmentalDiscount($originalCart, $modifiedCart, $context);
}
$this->cartPersister->save($modifiedCart, $context);
}
/**
* Helper function to modify the cart and insert the environmental discount line item.
* The discount amount will be collected from the plugin config (if set) or be the default amount,
* configured as constant from EnvironmentalDiscountService
*
* @param Cart $originalCart
* @param Cart $modifiedCart
* @param SalesChannelContext $context
*/
protected function insertEnvironmentalDiscount(Cart $originalCart, Cart $modifiedCart, SalesChannelContext $context): void
{
// create discount line item with environmental discount ordernumber as identifier
$discountLineItem = $this->createDiscount(self::ENVIRONMENTAL_DISCOUNT_ORDERNUMBER);
// get discount amount: abs * -1 will ensure that this will always return a negative value
$discountAmount = -1 * abs($this->systemConfigService->get(self::PLUGIN_PREFIX . 'environmentalDiscount') ?? self::ENVIRONMENTAL_DISCOUT_PRICE_DEFAULT);
// declare price definition to define how this price is calculated (absolute discount)
$definition = new AbsolutePriceDefinition(
$discountAmount
);
$discountLineItem->setPriceDefinition($definition);
// calculate price
$discountLineItem->setPrice(
$this->calculator->calculate($definition->getPrice(), $originalCart->getLineItems()->getPrices(), $context)
);
// add discount to new cart
$modifiedCart->add($discountLineItem);
}
/**
* Creates and returns a LineItem for the environmental discount.
*
* @param string $name
* @return LineItem
*/
protected function createDiscount(string $name): LineItem
{
$discountLineItem = new LineItem($name, LineItem::CUSTOM_LINE_ITEM_TYPE, null, 1);
// get label for line item by translating the corresponding snippet
$label = $this->translator->trans('compra.environmentalDiscountSW6.discountProductName');
$discountLineItem->setLabel($label);
$discountLineItem->setGood(false);
$discountLineItem->setStackable(false);
$discountLineItem->setRemovable(false);
return $discountLineItem;
}
/**
* Helper function to get the current selected invoice dispatch method.
* If value is set in the session, this will return the session value.
* Otherwise this will return the invoice dispatch method from the customer.
*
* @param CustomerEntity|null $customer
* @return string|null
*/
public function getCurrentOption(CustomerEntity $customer = null): ?string
{
if (!$customer) {
return $this->request->getSession()->get('compra_environmental_discount_current_option');
}
$customerCustomFields = $customer->getCustomFields();
if ($this->request->getSession()->get('compra_environmental_discount_current_option')) {
return $this->request->getSession()->get('compra_environmental_discount_current_option');
}
if (array_key_exists('compra_invoice_mail_enabled', $customerCustomFields)
&& $customerCustomFields['compra_invoice_mail_enabled'] !== null) {
return $customerCustomFields['compra_invoice_mail_enabled'] ? 'mail' : 'post';
}
return 'post';
}
/**
* Helper function to set the current invoice dispatch method in the session.
*
* @param string $option
*/
public function setCurrentOption(string $option): void
{
$this->request->getSession()->set('compra_environmental_discount_current_option', $option);
}
/**
* Helper function to unset the current invoice dispatch method in the session.
*/
public function unsetCurrentOption(): void
{
$this->request->getSession()->remove('compra_environmental_discount_current_option');
}
/**
* Helper function to get the current invoice dispatch mail address.
* If value is set in the session, this will return the session value.
* Otherwise this will return the invoice mail address from the customer.
*
* @param CustomerEntity|null $customer
* @return string|null
*/
public function getCurrentInvoiceMailAddress(CustomerEntity $customer = null): ?string
{
if (!$customer) {
return $this->request->getSession()->get('compra_environmental_discount_current_invoice_mail_address');
}
$customerCustomFields = $customer->getCustomFields();
if ($this->request->getSession()->get('compra_environmental_discount_current_invoice_mail_address')) {
return $this->request->getSession()->get('compra_environmental_discount_current_invoice_mail_address');
}
if (array_key_exists('compra_invoice_mail_address', $customerCustomFields)
&& $customerCustomFields['compra_invoice_mail_address'] !== null) {
return $customerCustomFields['compra_invoice_mail_address'];
}
return $customer->getEmail();
}
/**
* Helper function to set the current invoice dispatch mail address in the session.
*
* @param string $invoiceMailAddress
*/
public function setCurrentInvoiceMailAddress(string $invoiceMailAddress): void
{
$this->request->getSession()->set('compra_environmental_discount_current_invoice_mail_address', $invoiceMailAddress);
}
/**
* Helper function to unset the current invoice dispatch mail address in the session.
*/
public function unsetCurrentInvoiceMailAddress(): void
{
$this->request->getSession()->remove('compra_environmental_discount_current_invoice_mail_address');
}
/**
* Helper function to get a plugin config from this plugin by a given config name.
*
* @param string $name
* @return mixed
*/
public function getPluginConfig(string $name)
{
return $this->systemConfigService->get(self::PLUGIN_PREFIX . $name);
}
}