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

198 lines
8.2 KiB
PHP

<?php
namespace KupShop\LabelsBundle\Util;
use KupShop\CatalogBundle\Util\ProductsFilterSpecs;
use KupShop\ContentBundle\Entity\Placeholder;
use KupShop\OrderDiscountBundle\Util\DiscountManager;
use KupShop\OrderingBundle\Util\Purchase\PurchaseUtil;
use Query\Operator;
use Symfony\Contracts\Service\Attribute\Required;
class ProductLabelUtil
{
/** @var ProductsFilterSpecs */
private $productsFilterSpecs;
protected array $ignoreTriggers = ['coupon', 'generated_coupon', 'price_range', 'delivery_type', 'user_type'];
public function __construct(
private DiscountManager $discountManager,
private PurchaseUtil $purchaseUtil,
) {
}
public function updateProductLabelRelationsByAutoAssignment($idLabel, array $data)
{
$specs = $this->productsFilterSpecs->getSpecs($data['product_filter']);
$qbSelector = sqlQueryBuilder()
->fromProducts()
->andWhere($specs)
->select('p.id AS id_product, :idLabelParam AS id_label, 1 as generated')
->setParameter('idLabelParam', $idLabel);
if ($data['active_type'] == 'Y' && !empty($data['active_action_days'])) {
switch ($data['active_action_type']) {
case 'from_product_creation':
$qbSelector
->andWhere('DATEDIFF(NOW(), p.date_added) < :in_day_action')
->setParameter('in_day_action', $data['active_action_days']);
break;
case 'from_product_stock_in':
$qbSelector->andWhere('DATEDIFF(NOW(), p.date_stock_in) < :in_day_action')
->setParameter('in_day_action', $data['active_action_days']);
break;
default:
break;
}
}
$selectedProducts = $qbSelector->groupBy('p.id')->execute()->fetchAllAssociative();
$deleted = sqlQueryBuilder()
->delete('product_labels_relation')
->andWhere(Operator::andX(
Operator::equals(['id_label' => $idLabel]),
'generated = 1'
));
if (!empty($selectedProducts)) {
$deleted->andWhere(
Operator::not(Operator::inIntArray(array_column($selectedProducts, 'id_product'), 'id_product'))
);
}
$deleted = $deleted->execute();
if (!empty($selectedProducts)) {
$inserted = sqlQueryBuilder()
->insert('product_labels_relation')
->multiValues($selectedProducts)
->andWhere('generated = 1')
->onDuplicateKeyUpdate(['id_label'])
->execute();
}
return ['deleted' => $deleted, 'inserted' => $inserted ?? 0];
}
public function removeProductLabelRelationsByAutoAssignment($idLabel)
{
return sqlQueryBuilder()
->delete('product_labels_relation')
->andWhere(
Operator::andX(
Operator::equals(['generated' => '1']),
Operator::equals(['id_label' => $idLabel])
)
)
->execute();
}
public function removeProductLabelRelationsByManualAssignment($idLabel)
{
return sqlQueryBuilder()
->delete('product_labels_relation')
->andWhere(
Operator::andX(
Operator::equals(['generated' => '0']),
Operator::equals(['id_label' => $idLabel])
)
)
->execute();
}
public function getLabelPlaceholders(\Product $product, $id_label): array
{
$placeholders = [];
$id_order_discounts = $product->labels[$id_label]['data']['id_order_discount'] ?? null;
if (!$id_order_discounts) {
return $placeholders;
}
$calcDiscount = function () use ($id_order_discounts, &$placeholders, &$product) {
if ($placeholders) {
return $placeholders;
}
$placeholders = [
'KUPON' => '',
'URL_PRIDANI_KUPONU' => '',
'CENA_PO_SLEVE' => '',
'CENA_PO_SLEVE_ZAOKROUHLENO' => '',
'USETRITE' => '',
'SLEVA' => '',
];
$purchaseState = $this->purchaseUtil->getEmptyPurchaseState();
$id_variation = ($product->variationId ?? null) ?: $product->matched_id_variation ?: null;
$productItem = $this->purchaseUtil->createProductPurchaseItem($product->id, $id_variation, 1);
$purchaseState->addProduct($productItem);
$this->purchaseUtil->recalculateTotalPrices($purchaseState);
$this->discountManager->setPurchaseState($purchaseState);
$discountsToCheck = $this->discountManager->getDiscountForCheck($this->ignoreTriggers);
$discountsToCheck = array_intersect_key($discountsToCheck, array_flip($id_order_discounts));
if (empty($discountsToCheck)) {
return $placeholders;
}
$coupon = null;
foreach ($discountsToCheck as $id_order_discount => $discountToCheck) {
$orderDiscount = $this->discountManager->getOrderDiscountById($id_order_discount);
foreach ($orderDiscount->getTriggers() as $trigger) {
if ($trigger['type'] == 'coupon') {
$coupon = reset($trigger['data']['codes']);
if ($coupon) {
$actions = $orderDiscount->getActions();
$this->discountManager->applyActions($purchaseState, $actions);
if ($purchaseState->getUsedDiscounts()) {
break 2;
}
}
}
}
}
if (empty($purchaseState->getUsedDiscounts())) {
return $placeholders;
}
$this->purchaseUtil->recalculateTotalPrices($purchaseState);
$placeholders['KUPON'] = $coupon;
$placeholders['URL_PRIDANI_KUPONU'] = path('kupshop_content_cart_cart_1', ['couponNo' => $coupon, 'AddDiscount' => 1]);
$productPrice = $purchaseState->getProductsTotalPrice()->getPriceWithVat();
$discountPrice = $purchaseState->getDiscountsTotalPrice()->getPriceWithVat()->additiveInverse();
$priceWithDiscounts = $productPrice->sub($discountPrice);
$placeholders['CENA_PO_SLEVE'] = printPrice($priceWithDiscounts, ['ceil' => false, 'decimal' => 'dynamic']);
$placeholders['CENA_PO_SLEVE_ZAOKROUHLENO'] = printPrice($priceWithDiscounts, ['decimal' => 'dynamic']);
$placeholders['USETRITE'] = printPrice($discountPrice, ['ceil' => false, 'decimal' => 'dynamic']);
if (!$productPrice->isZero()) {
$discount = \DecimalConstants::hundred()->sub($priceWithDiscounts->mul(\DecimalConstants::hundred())->div($productPrice));
} else {
$discount = toDecimal(0);
}
$placeholders['SLEVA'] = $discount->printValue(0);
return $placeholders;
};
return [
new Placeholder('KUPON', 'Slevový kód, kterým se aktivuje daná sleva', fn () => $calcDiscount()['KUPON']),
new Placeholder('URL_PRIDANI_KUPONU', 'Interní', fn () => $calcDiscount()['URL_PRIDANI_KUPONU']),
new Placeholder('SLEVA', 'Procentuální sleva, kterou zákazník získá při uplatnění kódu.', fn () => $calcDiscount()['SLEVA']),
new Placeholder('CENA_PO_SLEVE', 'Cena produktu když by zákazník upratnil daný kód.', fn () => $calcDiscount()['CENA_PO_SLEVE']),
new Placeholder('CENA_PO_SLEVE_ZAOKROUHLENO', 'Cena produktu když by zákazník upratnil daný kód.', fn () => $calcDiscount()['CENA_PO_SLEVE_ZAOKROUHLENO']),
new Placeholder('USETRITE', 'Částka, kterou zákazník ušetří při uplatnění poukazu.', fn () => $calcDiscount()['USETRITE']),
];
}
/**
* @required
*/
public function setProductsFilterSpecs(ProductsFilterSpecs $productsFilterSpecs): void
{
$this->productsFilterSpecs = $productsFilterSpecs;
}
}