Files
kupshop/bundles/KupShop/QuantityDiscountBundle/Util/QuantityDiscountPrice.php
2025-08-02 16:30:27 +02:00

141 lines
4.5 KiB
PHP

<?php
/**
* Created by PhpStorm.
* User: ondra
* Date: 23.11.17
* Time: 8:01.
*/
namespace KupShop\QuantityDiscountBundle\Util;
use KupShop\I18nBundle\Util\PriceConverter;
use KupShop\KupShopBundle\Context\CurrencyContext;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\KupShopBundle\Util\Price\Price;
use KupShop\KupShopBundle\Util\Price\ProductPrice;
use KupShop\QuantityDiscountBundle\Context\QuantityDiscountContext;
use KupShop\QuantityDiscountBundle\Query\QuantityDiscount;
use Query\Operator;
use Query\QueryBuilder;
class QuantityDiscountPrice
{
public function __construct(
private QuantityDiscountContext $quantityDiscountContext,
protected ?PriceConverter $priceConverter = null,
) {
}
public function getPrice($idProduct, $pieces, $idVariation = null): Price
{
if ($productPrice = $this->getProductPrice($idProduct, $idVariation)) {
return $this->applyDiscount($productPrice, $idProduct, $pieces, $idVariation);
}
return new Price(toDecimal(0), Contexts::get(CurrencyContext::class)->getDefault(), getVat());
}
public function applyDiscount(ProductPrice $productPrice, $idProduct, $pieces, $idVariation): Price
{
$discountedValue = $this->calculateQuantityDiscountForProductPrice(
$productPrice,
$this->getDiscount($idProduct, toDecimal($pieces), $idVariation)
);
return new Price($discountedValue, $productPrice->getCurrency(), $productPrice->getVat());
}
public function calculateQuantityDiscountPriceForProductPrice(ProductPrice $productPrice, array $discount): Price
{
return new Price(
$this->calculateQuantityDiscountForProductPrice($productPrice, $discount),
$productPrice->getCurrency(),
$productPrice->getVat()
);
}
private function calculateQuantityDiscountForProductPrice(ProductPrice $productPrice, ?array $discount): \Decimal
{
$value = $productPrice->getPriceWithVat(false)
->removeVat($productPrice->getVat());
if (!$discount) {
return $value;
}
if ($discount['discount_type'] == QuantityDiscountUtil::DISCOUNT_TYPE_PERC) {
$value = $value->addDiscount($discount['discount']);
} else {
$discountValue = $this->priceConverter?->convert($discount['discount_type'], $productPrice->getCurrency(), $discount['discount']) ?: toDecimal($discount['discount']);
$value = \Decimal::max($value->sub($discountValue), \DecimalConstants::zero());
}
return $value;
}
private function getProductPrice($idProduct, $idVariation = null): ?ProductPrice
{
if ($product = $this->getProduct($idProduct, $idVariation)) {
return $product->getProductPrice();
}
return null;
}
public function getDiscount(
int $idProduct,
\Decimal $pieces,
?int $variationId = null,
): ?array {
$active = $this->quantityDiscountContext->getActive();
if (!$active) {
return null;
}
$specs = [
Operator::equals(['id_product' => $idProduct]),
QuantityDiscount::byGroup($active),
];
if ($variationId) {
if ($quantityDiscount = $this->getDiscountQueryBuilder($specs,
$pieces)->andWhere(Operator::equals(['id_variation' => $variationId]))->execute()->fetchAssociative()) {
return $quantityDiscount;
}
}
$quantityDiscount = $this->getDiscountQueryBuilder($specs,
$pieces, )->andWhere('id_variation IS NULL')->execute()->fetchAssociative();
return $quantityDiscount ?: null;
}
private function getDiscountQueryBuilder($specs, $pieces): QueryBuilder
{
return sqlQueryBuilder()
->select('discount, discount_type')
->from('products_quantity_discounts')
->where('pieces <= :pieces')
->andWhere(Operator::andX($specs))
->orderBy('pieces', 'DESC')
->setParameter('pieces', $pieces)
->setMaxResults(1);
}
private function getProduct($idProduct, $idVariation = null): ?\Product
{
if ($idVariation !== null) {
$product = new \Variation($idProduct, $idVariation);
} else {
$product = new \Product($idProduct);
}
if (!$product->createFromDB()) {
return null;
}
return $product;
}
}