<?php
declare(strict_types=1);
namespace fourtwosix\ProductShippingPrice\Subscriber;
use Shopware\Core\Checkout\Cart\Price\Struct\CartPrice;
use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
use Shopware\Core\Checkout\Cart\Tax\Struct\CalculatedTax;
use Shopware\Core\Checkout\Cart\Price\Struct\CalculatedPrice;
use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Finish\CheckoutFinishPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Offcanvas\OffcanvasCartPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Framework\Struct\ArrayEntity;
class SetShippingPrice implements EventSubscriberInterface
{
private $productRepo;
private $orderRepo;
private $orderDeliveriesRepo;
public function __construct(
$productRepo,
$orderRepo,
$orderDeliveriesRepo
) {
$this->productRepo = $productRepo;
$this->orderRepo = $orderRepo;
$this->orderDeliveriesRepo = $orderDeliveriesRepo;
}
public static function getSubscribedEvents(): array
{
return [
// Visualization hooks
OffcanvasCartPageLoadedEvent::class => 'onDisplayContent',
CheckoutCartPageLoadedEvent::class => 'onDisplayContent',
CheckoutConfirmPageLoadedEvent::class => 'onDisplayContent',
CheckoutFinishPageLoadedEvent::class => 'onDisplayContentFinish',
// True shipping costs set ->> 9999 to set priority higher then mails
CheckoutOrderPlacedEvent::class => ['onOrder', -9999],
];
}
public function onOrder(CheckoutOrderPlacedEvent $event)
{
$order = $event->getOrder();
// Load additional price from products
$totalAdditionalShippingPrice = 0;
$shippingCostByTaxRate = [];
## LOHOFF.IT - USE EXISTING METHOD ##
$totalAdditionalShippingPrice = $this->calculateShippingPriceFromObjectWithLineItems($order);
// On one line item there is only one tax...
foreach ($order->getShippingCosts()->getTaxRules() as $calculatedTax) {
if (!isset($shippingCostByTaxRate[$calculatedTax->getTaxRate()])) {
$shippingCostByTaxRate[$calculatedTax->getTaxRate()] = 0;
}
$shippingCostByTaxRate[$calculatedTax->getTaxRate()] += (
$totalAdditionalShippingPrice *
$calculatedTax->getPercentage() /
100
);
}
// Eventually add the additional price
if ($totalAdditionalShippingPrice > 0) {
$oldShippingCosts = $order->getShippingCosts();
$shippingTotal = $order->getShippingTotal();
$calculatedShippingCosts = $shippingTotal + $totalAdditionalShippingPrice;
$calculatedNetShippingCosts = 0;
$calculatedShippingTaxes = $oldShippingCosts->getCalculatedTaxes();
foreach ($calculatedShippingTaxes as $key => $calculatedTax) {
$taxShippingCost = 0;
if (isset($shippingCostByTaxRate[$calculatedTax->getTaxRate()])) {
$taxShippingCost = $shippingCostByTaxRate[$calculatedTax->getTaxRate()];
}
$taxNetShippingCosts = round($taxShippingCost / (1 + ($calculatedTax->getTaxRate() / 100)), 2);
$calculatedNetShippingCosts += $taxNetShippingCosts;
$increment = new CalculatedTax(
($taxShippingCost - $taxNetShippingCosts),
$calculatedTax->getTaxRate(),
$taxShippingCost
);
$calculatedShippingTaxes->get($key)->increment($increment);
}
$calculatedPriceTaxes = $order->getPrice();
foreach ($calculatedPriceTaxes->getCalculatedTaxes() as $key => $calculatedTax) {
$taxShippingCost = 0;
if (isset($shippingCostByTaxRate[$calculatedTax->getTaxRate()])) {
$taxShippingCost = $shippingCostByTaxRate[$calculatedTax->getTaxRate()];
}
$taxNetShippingCosts = round($taxShippingCost / (1 + ($calculatedTax->getTaxRate() / 100)), 2);
$increment = new CalculatedTax(
($taxShippingCost - $taxNetShippingCosts),
$calculatedTax->getTaxRate(),
$taxShippingCost
);
$calculatedPriceTaxes->getCalculatedTaxes()->get($key)->increment($increment);
}
$order->setShippingCosts(new CalculatedPrice(
$calculatedShippingCosts,
$calculatedShippingCosts,
$calculatedShippingTaxes,
$oldShippingCosts->getTaxRules()
));
$order->setPrice(new CartPrice(
(float)number_format($order->getPrice()->getNetPrice() + $calculatedNetShippingCosts, 2),
$order->getPositionPrice() + $calculatedShippingCosts,
$order->getPositionPrice(),
$calculatedPriceTaxes->getCalculatedTaxes(),
$calculatedPriceTaxes->getTaxRules(),
$calculatedPriceTaxes->getTaxStatus()
));
$newPayload = [
"id" => $order->getId(),
"versionId" => $order->getVersionId(),
"shippingCosts" => $order->getShippingCosts(),
"price" => $order->getPrice()
];
$this->orderRepo->update([
$newPayload
], $event->getContext());
$order->getDeliveries()->first()->setShippingCosts(new CalculatedPrice(
$calculatedShippingCosts,
$calculatedShippingCosts,
$calculatedShippingTaxes,
$oldShippingCosts->getTaxRules()
));
// Let's also update the OrderDeliveries entity
$newPayload = [
"id" => $order->getDeliveries()->first()->getId(),
"versionId" => $order->getDeliveries()->first()->getVersionId(),
"shippingCosts" => $order->getDeliveries()->first()->getShippingCosts()
];
$this->orderDeliveriesRepo->update([
$newPayload
], $event->getContext());
}
}
public function onDisplayContent($event)
{
$cart = $event->getPage()->getCart();
$total_shipping_price = $this->calculateShippingPriceFromObjectWithLineItems($cart);
$extensions = new ArrayEntity();
$extensions['total_shipping_price'] = $total_shipping_price;
$event->getPage()->addExtension("shippingStruct",$extensions);
}
public function onDisplayContentFinish($event)
{
$order = $event->getPage()->getOrder();
$total_shipping_price = $this->calculateShippingPriceFromObjectWithLineItems($order);
$extensions = new ArrayEntity();
$extensions['total_shipping_price'] = $total_shipping_price;
$extensions['total_shipping_price_already_in_total'] = $total_shipping_price;
$event->getPage()->addExtension("shippingStruct",$extensions);
}
private function calculateShippingPriceFromObjectWithLineItems($cartOrOrder) {
$total_additional_shipping_price = 0;
foreach ($cartOrOrder->getLineItems() as $lineItem) {
## LOHOFF.IT - ONLY TRY TO GET CUSTOM FIELD IF LINEITEM IS OF TYPE PRODUCT ##
if (($lineItem->getType() === 'product') && (
isset($lineItem->getPayload()["customFields"]["shipping_price"]) && (
/* @fourtwosix-edit: if the switch doesn't exists, then it's an old product that doesn't have the switch */
!isset($lineItem->getPayload()["customFields"]["shipping_price_deactivate"]) ||
!$lineItem->getPayload()["customFields"]["shipping_price_deactivate"]
)
)) {
$total_additional_shipping_price += (
$lineItem->getPayload()["customFields"]["shipping_price"] *
$lineItem->getQuantity()
);
}
}
return $total_additional_shipping_price;
}
}