Files
kupshop/bundles/KupShop/FeedsBundle/Utils/DeliveryWrapper.php
2025-08-02 16:30:27 +02:00

292 lines
8.7 KiB
PHP

<?php
namespace KupShop\FeedsBundle\Utils;
use KupShop\FeedGeneratorBundle\Expressions\ExpressionObjectTrait;
use KupShop\FeedGeneratorBundle\Expressions\IExpressionObject;
use KupShop\FeedGeneratorBundle\Utils\IObjectInfo;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Price\Price;
use KupShop\KupShopBundle\Util\Price\PriceCalculator;
use KupShop\KupShopBundle\Wrapper\PriceWrapper;
use KupShop\OrderingBundle\Entity\Purchase\ProductPurchaseItem;
use KupShop\OrderingBundle\Entity\Purchase\PurchaseState;
use KupShop\OrderingBundle\Exception\DeliveryException;
use KupShop\OrderingBundle\Util\Purchase\PurchaseUtil;
class DeliveryWrapper implements IExpressionObject, IObjectInfo, \ArrayAccess
{
use ExpressionObjectTrait;
/** @var \Delivery */
private $delivery;
/** @var PriceWrapper */
private $price;
/** @var PriceWrapper */
private $priceWithCOD;
/** @var PriceWrapper */
private $freeDeliveryPriceWithCOD;
/** @var Price */
private $dtPriceDontCountinFrom;
/** @var Price */
private $dtPriceDontCountinFromCOD;
/** @var \Product */
private $product;
private static ?PurchaseUtil $purchaseUtil = null;
public function __construct(\Delivery $delivery)
{
$this->delivery = $delivery;
}
/**
* This method should only be used from \KupShop\FeedsBundle\Wrapper\DeliveryWrapper.
*
* @private
*/
public function setProduct(\Product $product)
{
$this->product = $product;
}
/**
* @private
*/
public function processDeliveryType(\DeliveryType $deliveryType)
{
$payment = $deliveryType->getPayment();
if (isset($payment) && $payment->getPayMethod() === \Payment::METHOD_COD) {
$this->setMinimalPrice($this->priceWithCOD, $deliveryType->getPrice());
// minimal payment price (COD only)
$this->setMinimalPrice($this->freeDeliveryPriceWithCOD, $deliveryType->price_payment);
}
if (isset($payment) && in_array($payment->getPayMethod(), [\Payment::METHOD_TRANSFER, \Payment::METHOD_ONLINE])) {
$this->setMinimalPrice($this->price, $deliveryType->getPrice());
}
// set minimal priceDontCountinFrom from delivery type
if ($dtPriceDontCountinFrom = $deliveryType->getPriceDontCountinFrom()) {
if (isset($payment) && $payment->getPayMethod() === \Payment::METHOD_COD) {
if (!isset($this->dtPriceDontCountinFromCOD)
|| $dtPriceDontCountinFrom->getPriceWithVat()->lowerThan($this->dtPriceDontCountinFromCOD->getPriceWithVat())) {
$this->dtPriceDontCountinFromCOD = $dtPriceDontCountinFrom;
}
} else {
if (!isset($this->dtPriceDontCountinFrom)
|| $dtPriceDontCountinFrom->getPriceWithVat()->lowerThan($this->dtPriceDontCountinFrom->getPriceWithVat())) {
$this->dtPriceDontCountinFrom = $dtPriceDontCountinFrom;
}
}
}
}
private function setMinimalPrice(?PriceWrapper &$currentPrice = null, ?Price $newPrice = null)
{
if (!isset($newPrice)) {
return;
}
if (!isset($currentPrice) || $newPrice->getPriceWithVat()->lowerThan($currentPrice->field_value_with_vat())) {
$currentPrice = PriceWrapper::wrap($newPrice);
}
}
/**
* @private
*/
public function getDelivery(): \Delivery
{
return $this->delivery;
}
/**
* @private
*/
public function getFinalPrice(\Product $product): ?\Decimal
{
if (isset($this->dtPriceDontCountinFrom)
&& PriceCalculator::firstLower($this->dtPriceDontCountinFrom, $product->getProductPrice())
) {
return \Decimal::fromInteger(0);
}
$hasFreeDelivery = isset($product->campaign_codes['Z']) || (
$this->delivery->getPriceDontCountinFromDelivery()
&& PriceCalculator::firstLower($this->delivery->getPriceDontCountinFromDelivery(), $product->getProductPrice())
);
if ($hasFreeDelivery) {
return \Decimal::fromInteger(0);
} elseif (isset($this->price)) {
return $this->price->field_value_with_vat();
} elseif ($this->priceWithCOD) {
return $this->priceWithCOD->field_value_with_vat();
} else {
return null;
}
}
/**
* @private
*/
public function hasCOD(): bool
{
return isset($this->priceWithCOD);
}
/**
* @private
*/
public function getFinalPriceWithCOD(\Product $product): ?\Decimal
{
if (isset($this->dtPriceDontCountinFromCOD)
&& PriceCalculator::firstLower($this->dtPriceDontCountinFromCOD, $product->getProductPrice())
) {
return \Decimal::fromInteger(0);
}
$hasFreeDelivery = isset($product->campaign_codes['Z']) || (
$this->delivery->getPriceDontCountinFromDelivery()
&& PriceCalculator::firstLower($this->delivery->getPriceDontCountinFromDelivery(), $product->getProductPrice())
);
if ($hasFreeDelivery) {
return isset($this->freeDeliveryPriceWithCOD) ? $this->freeDeliveryPriceWithCOD->field_value_with_vat() : \Decimal::fromInteger(0);
} elseif (isset($this->priceWithCOD)) {
return $this->priceWithCOD->field_value_with_vat();
} else {
return null;
}
}
/**
* @return \Decimal|null
*
* @private
*/
public function getPriceDontCountinFrom()
{
if ($this->dtPriceDontCountinFrom) {
return $this->dtPriceDontCountinFrom->getPriceWithVat();
}
if ($this->delivery->getPriceDontCountinFromDelivery()) {
return $this->delivery->getPriceDontCountinFromDelivery()->getPriceWithVat();
}
return null;
}
/**
* Spustí kontrolu restrikcí pro aktuální produkt a vrací `true` / `false`. Pokud vrátí `true`, tak byla
* kontrola restrikcí úspěšná a produkt je možné danou dopravou poslat.
*/
public function checkRestrictions(): bool
{
try {
$this->delivery->checkSoftRestrictions(
$this->getProductPurchaseState()
);
} catch (DeliveryException $e) {
return false;
}
return true;
}
/** Název dopravy.
*/
public function field_name(): string
{
return $this->delivery->name ?? '';
}
/** Umožnuje doprava dobírku.
*/
public function field_cod(): bool
{
return $this->hasCOD();
}
/** Cena dopravy.
*/
public function field_final_price(): ?float
{
$price = $this->getFinalPrice($this->product);
return isset($price) ? $price->asFloat() : null;
}
/** Cena dopravy včetně dobírky.
*/
public function field_final_price_with_cod(): ?float
{
if ($this->hasCOD()) {
$price = $this->getFinalPriceWithCOD($this->product);
} else {
$price = $this->getFinalPrice($this->product);
}
return isset($price) ? $price->asFloat() : null;
}
/**
* Částka od které se nemá započítávat cena dopravy.
*
* Nemusí být definována.
*
* @return float|null
*/
public function field_price_dont_countin_from()
{
return $this->getPriceDontCountinFrom() ? $this->getPriceDontCountinFrom()->asFloat() : $this->getPriceDontCountinFrom();
}
/** Heureka DELIVERY_ID */
public function field_heureka_id(): string
{
return $this->delivery->getHeurekaDeliveryID() ?? '';
}
/** Zbozi DELIVERY_ID */
public function field_zbozi_id(): string
{
return $this->delivery->getZboziDeliveryID() ?? '';
}
/** Státy, pro které je doprava povolena */
public function field_countries(): array
{
return $this->delivery->getSupportedCountries();
}
/**
* @private
*/
private function getProductPurchaseState(): PurchaseState
{
if (!static::$purchaseUtil) {
static::$purchaseUtil = ServiceContainer::getService(PurchaseUtil::class);
}
if (!isset($this->product->feedPurchaseState)) {
$productPurchaseItem = new ProductPurchaseItem($this->product->id, $this->product->variationId ?? null, 1, $this->product->getProductPrice(), null);
$productPurchaseItem->setProduct($this->product);
$purchaseState = new PurchaseState([$productPurchaseItem]);
$this->product->feedPurchaseState = static::$purchaseUtil->recalculateTotalPrices($purchaseState);
}
return $this->product->feedPurchaseState;
}
}