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

116 lines
4.0 KiB
PHP

<?php
declare(strict_types=1);
namespace KupShop\UnitsBundle\Utils;
use KupShop\CatalogBundle\ProductList\ProductCollection;
use KupShop\ContentBundle\Entity\ProductUnified;
use KupShop\ContentBundle\Entity\Wrapper\ProductUnifiedWrapper;
use KupShop\I18nBundle\Translations\ProductsUnitsTranslation;
use KupShop\I18nBundle\Util\PriceConverter;
use KupShop\KupShopBundle\Context\CurrencyContext;
use KupShop\KupShopBundle\Util\Price\Price;
use KupShop\KupShopBundle\Util\Price\ProductPrice;
use KupShop\KupShopBundle\Wrapper\PriceWrapper;
use Query\Operator;
use Query\Translation;
use Symfony\Contracts\Service\Attribute\Required;
class MeasureUnitUtil
{
protected ?PriceConverter $priceConverter;
protected CurrencyContext $currencyContext;
public function getUnitPrice(ProductUnified|ProductUnifiedWrapper $product, bool $round = false): ?array
{
$productCollection = new ProductCollection([$product->getId() => $product]);
$productCollection->fetchMeasureUnits();
if ($product instanceof ProductUnifiedWrapper) {
$product = $product->getObject();
}
if (empty($product->measureUnits)) {
return null;
}
// Select first variation by default or get data for product
$data = $product->measureUnits[array_key_first($product->measureUnits)] ?? null;
if ($product->getVariationId()) {
$data = $product->measureUnits[$product->getVariationId()] ?? null;
}
if (!$data) {
return null;
}
return $this->calculatePriceUnit($product->getProductPrice(), $data);
}
public function calculatePriceUnit(ProductPrice $productPrice, array $data): ?array
{
$measureQuantity = toDecimal($data['measure_quantity'] ?? null);
$measureUnit = toDecimal($data['recalculate_to'] ?? null);
if (!$measureQuantity->isPositive()) {
return null;
}
if (!$measureUnit->isPositive()) {
return null;
}
$wrapped = PriceWrapper::wrap($productPrice);
$price = $wrapped->field_value_without_vat_no_rounding();
$priceWithoutDiscount = $wrapped->field_value_without_vat_without_discount();
$pricePerUnit = $price->div($measureQuantity->div($measureUnit, 4), 4);
$priceWithoutDiscountPerUnit = $priceWithoutDiscount->div($measureQuantity->div($measureUnit, 4), 4);
$result = [
'price' => new Price($pricePerUnit, $this->currencyContext->getActive(), $productPrice->getVat()),
'recalculate_to' => $data['recalculate_to'],
'unit_name' => $data['short_name'],
];
if ($priceWithoutDiscountPerUnit->comp($pricePerUnit)) {
$result['price_without_discount'] = new Price($priceWithoutDiscountPerUnit, $this->currencyContext->getActive(), $productPrice->getVat());
}
return $result;
}
public function getUnitPriceQueryBuilder(?array $ids = null): \Query\QueryBuilder
{
$qb = sqlQueryBuilder()->select('p.id id_product, pv.id id_variation,
COALESCE(pv.measure_quantity, p.measure_quantity) measure_quantity, pu.recalculate_to, pu.id as id')
->fromProducts()
->joinVariationsOnProducts()
->innerJoin('p', 'products_units', 'pu', 'pu.id = p.measure_unit')
->andWhere(Translation::coalesceTranslatedFields(ProductsUnitsTranslation::class, ['short_name', 'long_name']));
if (findModule(\Modules::PRODUCTS, \Modules::SUB_UNITS_FLOAT)) {
$qb->addSelect('pu.pieces_precision as pieces_precision');
}
if ($ids) {
$qb->andWhere(Operator::inIntArray($ids, 'p.id'));
}
return $qb;
}
#[Required]
public function setPriceConverter(?PriceConverter $priceConverter): void
{
$this->priceConverter = $priceConverter;
}
#[Required]
public function setCurrencyContext(CurrencyContext $currencyContext): void
{
$this->currencyContext = $currencyContext;
}
}