first commit

This commit is contained in:
2025-08-02 16:30:27 +02:00
commit 23646bfcee
14851 changed files with 1750626 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
<?php
declare(strict_types=1);
namespace External\ZNZBundle\Util\Product;
use Query\Operator;
class ZNZPhotoUpdater
{
public function updateMainPhotos(?array $productIds = null): void
{
$this->checkProductMainPhotos($productIds);
$this->updateVariationsMainPhoto($productIds);
}
/**
* Funkce kontroluje hlavni obrazek u variantnich produktu.
*
* - Nastavuje hlavni obrazek na obrazek od prvni varianty, ktera je dostupna (viditelna a skladem).
* - Pokud neni zadny variantni obrazek dostupny, tak se zkusi nastavit obrazek, ktery neni prirazen k variante.
* - Pokud neni ani obrakze primo u produktu, bez prirazeni k variante, tak produkt nema hlavni obrazek.
*/
public function updateVariationsMainPhoto(?array $productIds = null): void
{
// subquery, ktery ziska ID fotky hlavni fotky od prvni viditelny varianty
$subqueryVariationsMainPhoto = sqlQueryBuilder()
->select('MIN(ppr.id_photo) as id_photo, ppr.id_product')
->from('photos_products_relation', 'ppr')
->join('ppr', 'products_variations', 'pv', 'pv.id = ppr.id_variation')
->where('pv.figure = \'Y\' AND pv.in_store > 0')
->groupBy('ppr.id_product');
// subquery, ktery ziska ID aktualni hlavni fotky
$subqueryCurrentMainPhoto = sqlQueryBuilder()
->select('ppr.id_photo, ppr.id_product')
->from('photos_products_relation', 'ppr')
->where('ppr.show_in_lead = \'Y\'');
// subquery, ktery ziska ID prvni fotky ktera je prirazena k produktu a ne k variantam
$subselectProductFirstPhoto = sqlQueryBuilder()
->select('ppr.id_product, ppr.id_photo, ROW_NUMBER() OVER (PARTITION BY ppr.id_product ORDER BY ppr.position ASC) AS rn')
->from('photos_products_relation', 'ppr')
->where('ppr.id_photo NOT IN (SELECT id_photo FROM photos_products_relation WHERE id_variation IS NOT NULL)');
$subqueryProductFirstPhoto = sqlQueryBuilder()
->select('id_photo, id_product')
->from("({$subselectProductFirstPhoto->getSQL()})", 'ranked')
->where('rn = 1');
$qb = sqlQueryBuilder()
->select('pv.id_product, COALESCE(vmp.id_photo, pfp.id_photo) as id_main_photo, cmp.id_photo as id_current_photo')
->from('products_variations', 'pv')
->leftJoinSubQuery('pv', $subqueryVariationsMainPhoto, 'vmp', 'vmp.id_product = pv.id_product')
->leftJoinSubQuery('pv', $subqueryCurrentMainPhoto, 'cmp', 'cmp.id_product = pv.id_product')
->leftJoinSubQuery('pv', $subqueryProductFirstPhoto, 'pfp', 'pfp.id_product = pv.id_product')
->andWhere('cmp.id_photo != COALESCE(vmp.id_photo, pfp.id_photo)')
->groupBy('pv.id_product');
if ($productIds !== null) {
$qb->andWhere(Operator::inIntArray($productIds, 'pv.id_product'));
}
foreach ($qb->execute() as $item) {
sqlGetConnection()->transactional(function () use ($item) {
// odeberu oznaceni hlavni fotky
sqlQueryBuilder()
->update('photos_products_relation')
->directValues(['show_in_lead' => 'N'])
->set('position', 'GREATEST(1, position)')
->andWhere(Operator::equals(['id_product' => $item['id_product'], 'show_in_lead' => 'Y']))
->execute();
// pokud nema hlavni fotku, tak nic nenastavuju
if (!$item['id_main_photo']) {
return;
}
// nastavim novou hlavni fotku
sqlQueryBuilder()
->update('photos_products_relation')
->directValues(['show_in_lead' => 'Y', 'position' => 0])
->andWhere(Operator::equals(['id_product' => $item['id_product'], 'id_photo' => $item['id_main_photo']]))
->andWhere('id_variation IS NULL')
->execute();
});
}
}
/**
* Funkce kontroluje hlavni obrazek u nevariantnich produktu.
*
* - Pokud produkt nema hlavni obrazek, tak se mu nastavi prvni obrazek v poradi.
* - Pokud produkt uz ma hlavni obrazek, tak se nic neprovadi.
*/
public function checkProductMainPhotos(?array $productIds = null): void
{
$qb = sqlQueryBuilder()
->select('ppr.id_product')
->from('photos_products_relation', 'ppr')
->leftJoin('ppr', 'products_variations', 'pv', 'pv.id_product = ppr.id_product')
// zajimaji me pouze nevariantni produkty, protoze o variantni produkty se stara metoda `updateVariationsMainPhoto`
->andWhere('pv.id IS NULL')
->having('MAX(ppr.show_in_lead)=\'N\'')
->groupBy('ppr.id_product');
if ($productIds !== null) {
$qb->andWhere(Operator::inIntArray($productIds, 'id_product'));
}
foreach ($qb->execute() as $item) {
\Photos::checkLeadPhoto('photos_products_relation', 'id_product', $item['id_product']);
}
}
}

View File

@@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace External\ZNZBundle\Util\Product;
use External\ZNZBundle\Util\ZNZConfiguration;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\PricelistBundle\Context\PricelistContext;
use KupShop\PricelistBundle\Query\Product;
use Query\Operator;
use Query\QueryBuilder;
class ZNZProductRestrictions
{
public function __construct(private ZNZConfiguration $configuration)
{
}
public function getSpec(): ?callable
{
$specs = [];
foreach (get_class_methods($this) as $method) {
if (!str_starts_with($method, 'getSpec_')) {
continue;
}
$specs[] = $this->$method();
}
return Operator::andX($specs);
}
/**
* V pripade B2B modu zobrazujeme jen produkty, u kterych je vyplnena cena v ceniku, ktery maji aktivni.
*
* Neprihlasenum uzivatleum se zobrazuji vsechny produkty, ale prihlasenemu B2B zobrazujeme uz jen jeho sortiment.
*/
private function getSpec_B2BPriceRestriction(): ?callable
{
if (!$this->configuration->isB2BShop()) {
return null;
}
if (!($priceListId = Contexts::get(PriceListContext::class)->getActiveId())) {
return null;
}
return function (QueryBuilder $qb) use ($priceListId) {
$qb->joinVariationsOnProducts();
$qb->andWhere(Product::applyPricelist($priceListId));
$priceField = 'COALESCE(prlv.price, prlp.price)';
return "{$priceField} IS NOT NULL AND {$priceField} > 0";
};
}
}

View File

@@ -0,0 +1,173 @@
<?php
declare(strict_types=1);
namespace External\ZNZBundle\Util\Product;
use External\ZNZBundle\Util\ZNZUtil;
use KupShop\CatalogBundle\ProductList\ProductCollection;
use KupShop\KupShopBundle\Context\CurrencyContext;
use KupShop\KupShopBundle\Util\Contexts;
use Query\Operator;
use Query\Product;
use Symfony\Contracts\Service\Attribute\Required;
class ZNZProductUtil
{
#[Required]
public ZNZUtil $znzUtil;
public function updateProductsDefaultPrice(): void
{
$defaultPriceListId = sqlQueryBuilder()
->select('zpl.id_pricelist')
->from('znz_pricelists', 'zpl')
->join('zpl', 'pricelists', 'pl', 'pl.id = zpl.id_pricelist')
->andWhere(Operator::equals(['is_default' => 1]))
->andWhere(Operator::equals(['pl.currency' => Contexts::get(CurrencyContext::class)->getDefaultId()]))
->execute()->fetchOne();
if (!$defaultPriceListId) {
return;
}
// aktualizovat vychozi cenu u produktu podle vychoziho ceniku
sqlQueryBuilder()
->update('products', 'p')
->join('p', 'pricelists_products', 'plp', 'plp.id_product = p.id AND plp.id_variation IS NULL AND plp.id_pricelist = :priceListId')
->set('p.price', 'plp.price')
->where('plp.price IS NOT NULL')
->setParameter('priceListId', $defaultPriceListId)
->execute();
// aktualizovat vychozi cenu u varianty podle vychoziho ceniku
sqlQueryBuilder()
->update('products_variations', 'pv')
->join('pv', 'pricelists_products', 'plp', 'plp.id_variation = pv.id AND plp.id_pricelist = :priceListId')
->set('pv.price', 'plp.price')
->where('plp.price IS NOT NULL')
->setParameter('priceListId', $defaultPriceListId)
->execute();
}
public function fetchZNZSuppliersInfo(ProductCollection $products): void
{
if (isset($products->_fetch_znz_suppliers_info)) {
return;
}
if ($products->isEmpty()) {
return;
}
$filterProducts = $this->collectProductsForFilter($products);
$qb = sqlQueryBuilder()
->select('IF(pv.id, CONCAT(p.id, "/", pv.id), p.id) as id, si.id_store, zsi.data')
->from('products', 'p')
->leftJoin('p', 'products_variations', 'pv', 'pv.id_product = p.id')
->leftJoin('pv', 'stores_items', 'si', 'si.id_product = p.id AND si.id_variation <=> pv.id')
->leftJoin('si', 'znz_stores_items', 'zsi', 'zsi.id_stores_item = si.id')
->join('zsi', 'stores', 's', 's.id = si.id_store')
->andWhere(Product::productsAndVariationsIds($filterProducts))
->andWhere(Operator::equals(['s.figure' => 'Y']))
->groupBy('p.id, pv.id');
if ($storeIds = $this->znzUtil->getActiveStoreIds()) {
$qb->andWhere(Operator::inIntArray($storeIds, 'si.id_store'));
}
$data = [];
foreach ($qb->execute() as $item) {
$data[$item['id']][$item['id_store']] = json_decode($item['data'] ?: '', true)['supplier'] ?? [];
}
foreach ($products as $key => $product) {
$product->znz_suppliers_info = $data[$key] ?? [];
}
$products->_fetch_znz_suppliers_info = true;
}
public function fetchZNZMaxCartQuantity(ProductCollection $products): void
{
if (isset($products->_fetch_znz_max_cart_quantity)) {
return;
}
if ($products->isEmpty()) {
return;
}
$filterProducts = $this->collectProductsForFilter($products);
$qb = sqlQueryBuilder()
->select('IF(pv.id, CONCAT(p.id, "/", pv.id), p.id) as id, zpw.max_cart_quantity')
->from('products', 'p')
->leftJoin('p', 'products_variations', 'pv', 'pv.id_product = p.id')
->leftJoin('pv', 'znz_products', 'zp', 'zp.id_product = p.id AND zp.id_variation <=> pv.id')
->leftJoin('zp', 'znz_products_website', 'zpw', 'zpw.id_znz = zp.id_znz')
->andWhere(Product::productsAndVariationsIds($filterProducts))
->andWhere(Operator::equals(['zpw.id_website' => $this->znzUtil->getCurrentWebsite()]))
->groupBy('p.id, pv.id');
foreach ($qb->execute() as $item) {
if (isset($products[$item['id']])) {
$products[$item['id']]->znz_max_cart_quantity = $item['max_cart_quantity'] ? (int) $item['max_cart_quantity'] : null;
}
}
$products->_fetch_znz_max_cart_quantity = true;
}
public function fetchZNZVisibility(ProductCollection $products): void
{
if (isset($products->_fetch_znz_visibility)) {
return;
}
if ($products->isEmpty()) {
return;
}
$filterProducts = $this->collectProductsForFilter($products);
$qb = sqlQueryBuilder()
->select('IF(pv.id, CONCAT(p.id, "/", pv.id), p.id) as id, JSON_VALUE(zp.data, "$.znzFigure") as znz_figure, GROUP_CONCAT(zpw.id_website) as znz_websites')
->from('products', 'p')
->leftJoin('p', 'products_variations', 'pv', 'pv.id_product = p.id')
->leftJoin('pv', 'znz_products', 'zp', 'zp.id_product = p.id AND zp.id_variation <=> pv.id')
->leftJoin('zp', 'znz_products_website', 'zpw', 'zpw.id_znz = zp.id_znz')
->andWhere(Product::productsAndVariationsIds($filterProducts))
->groupBy('p.id, pv.id');
$website = $this->znzUtil->getCurrentWebsite();
foreach ($qb->execute() as $item) {
$websites = explode(',', $item['znz_websites'] ?: '');
$visibility = 'N';
if ($item['znz_figure'] === 'Y' && in_array($website, $websites)) {
$visibility = 'Y';
}
if (isset($products[$item['id']])) {
$products[$item['id']]->znz_visibility = $visibility;
}
}
$products->_fetch_znz_visibility = true;
}
private function collectProductsForFilter(ProductCollection $products): array
{
$filterProducts = [];
foreach ($products as $product) {
$filterProducts[$product->id] = $filterProducts[$product->id] ?? null;
if ($product->variationId ?? false) {
$filterProducts[$product->id][] = $product->variationId;
}
}
return $filterProducts;
}
}

View File

@@ -0,0 +1,309 @@
<?php
declare(strict_types=1);
namespace External\ZNZBundle\Util\Product;
use External\ZNZBundle\Util\ZNZConfiguration;
use External\ZNZBundle\Util\ZNZUtil;
use KupShop\KupShopBundle\Context\ContextManager;
use KupShop\KupShopBundle\Context\LanguageContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\PricelistBundle\Context\PricelistContext;
use Query\Operator;
use Query\QueryBuilder;
class ZNZVisibilityUpdater
{
public function __construct(
private ZNZUtil $znzUtil,
private ContextManager $contextManager,
private ZNZConfiguration $configuration,
) {
}
public function updateVisibility(?array $productIds = null): void
{
$languageContext = Contexts::get(LanguageContext::class);
// viditelnost potrebuji zaktualizovat pro kazdy jazyk zvlast
foreach ($languageContext->getAll() as $lang) {
$this->updateProductsVisibilityByHelios($lang->getId(), $productIds);
}
$this->hideProductsWithZeroPrice();
$this->hideProductsWithoutTitle();
}
public function updateProductsVisibilityByHelios(string $language, ?array $productIds = null): void
{
$languageContext = Contexts::get(LanguageContext::class);
$website = $this->znzUtil->getCurrentWebsite($language);
if ($language === $languageContext->getDefaultId()) {
$this->executeQueryBuilder(
// skryju produkty, ktere nemaji byt videt ve vychozim jazyce
sqlQueryBuilder()
->update('products', 'p')
->leftJoin('p', 'znz_products', 'zp', 'p.id = zp.id_product AND zp.id_variation IS NULL')
->leftJoin('zp', 'znz_products_website', 'zpw', 'zpw.id_znz = zp.id_znz AND zpw.id_website = :website')
->set('p.figure', ':figure')
// pokud je produkt videt a ma byt skryty, nebo neni viditelny pro aktualni website
->andWhere('p.figure = "Y" AND (JSON_VALUE(zp.data, "$.znzFigure") = "N" OR zpw.id_znz IS NULL)')
->addParameters(['figure' => 'N', 'website' => $website]),
$productIds
);
$this->executeQueryBuilder(
// zobrazim produktu, ktere maji byt videt ve vychozim jazyce
sqlQueryBuilder()
->update('products', 'p')
->leftJoin('p', 'znz_products', 'zp', 'p.id = zp.id_product AND zp.id_variation IS NULL')
->leftJoin('zp', 'znz_products_website', 'zpw', 'zpw.id_znz = zp.id_znz AND zpw.id_website = :website')
->set('p.figure', ':figure')
// pokud je skryty a ma byt videt a je viditelny pro aktualni website
->andWhere('p.figure = "N" AND JSON_VALUE(zp.data, "$.znzFigure") = "Y" AND zpw.id_znz IS NOT NULL')
// zobrazuju pouze produkty, ktere nemaji nulovou cenu
->andWhere(static::withNonZeroPrice($language))
->addParameters(['figure' => 'Y', 'website' => $website]),
$productIds
);
} else {
$this->executeQueryBuilder(
// skryju produkty, ktere nemaji byt videt v prekladech
sqlQueryBuilder()
->update('products_translations', 'pt')
->join('pt', 'products', 'p', 'p.id = pt.id_product')
->leftJoin('pt', 'znz_products', 'zp', 'pt.id_product = zp.id_product AND zp.id_variation IS NULL')
->leftJoin('zp', 'znz_products_website', 'zpw', 'zpw.id_znz = zp.id_znz AND zpw.id_website = :website')
->set('pt.figure', ':figure')
// pokud je produkt videt a ma byt skryty, nebo neni viditelny pro aktualni website
->andWhere('COALESCE(pt.figure, "Y") = "Y" AND (JSON_VALUE(zp.data, "$.znzFigure") = "N" OR zpw.id_znz IS NULL)')
->andWhere(Operator::equals(['pt.id_language' => $language]))
->addParameters(['figure' => 'N', 'website' => $website]),
$productIds
);
$this->executeQueryBuilder(
// zobrazim produkty, ktere maji byt videt v prekladech
sqlQueryBuilder()
->update('products_translations', 'pt')
->join('pt', 'products', 'p', 'p.id = pt.id_product')
->leftJoin('pt', 'znz_products', 'zp', 'pt.id_product = zp.id_product AND zp.id_variation IS NULL')
->leftJoin('zp', 'znz_products_website', 'zpw', 'zpw.id_znz = zp.id_znz AND zpw.id_website = :website')
->set('pt.figure', ':figure')
// pokud produkt neni videt a ma byt videt a je viditelny pro aktualni website
->andWhere('COALESCE(pt.figure, "N") = "N" AND JSON_VALUE(zp.data, "$.znzFigure") = "Y" AND zpw.id_znz IS NOT NULL')
->andWhere(Operator::equals(['pt.id_language' => $language]))
// zobrazuju pouze produkty, ktere nemaji nulovou cenu
->andWhere(static::withNonZeroPrice($language))
// zobrazuju pouze produkty, ktere maji vyplneny title
->andWhere(static::withTitle())
->addParameters(['figure' => 'Y', 'website' => $website]),
$productIds
);
}
$this->updateVariationsVisibility($language, $productIds);
}
private function hideProductsWithoutTitle(): void
{
// skryju produkty v prekladech, pokud maji v prekladu nazvu prazdnej string
sqlQueryBuilder()
->update('products_translations', 'pt')
->directValues(['figure' => 'N'])
->andWhere(Operator::not(Operator::equals(['pt.figure' => 'N'])))
->andWhere(Operator::not(static::withTitle()))
->execute();
}
private function hideProductsWithZeroPrice(): void
{
// v b2b modu maji defaultne vsechny produkty 0 cenu, tazke skryvani nedava smysl
if ($this->configuration->isB2BMode() || $this->configuration->isB2BBasicMode()) {
return;
}
// skryju varianty, ktere maji nulovou cenu
sqlQueryBuilder()
->update('products_variations', 'pv')
->join('pv', 'products', 'p', 'p.id = pv.id_product')
->set('pv.figure', ':figure')
->andWhere(Operator::equals(['pv.figure' => 'Y']))
->andWhere('COALESCE(pv.price, p.price) <= 0')
->setParameter('figure', 'N')
->execute();
// skryju produkty, ktere maji nulovou cenu
sqlQueryBuilder()
->update('products', 'p')
// joinuju pouze viditelne varianty, abych pri podmince COALESCE(pv.price, p.price) bral v potaz jen varianty, co jsou videt
->leftJoin('p', 'products_variations', 'pv', 'p.id = pv.id_product AND pv.figure = "Y"')
->set('p.figure', ':figure')
->andWhere(Operator::equals(['p.figure' => 'Y']))
->andWhere('COALESCE(pv.price, p.price) <= 0')
->setParameter('figure', 'N')
->execute();
// pro kazdou mutaci jeste
$languageContext = Contexts::get(LanguageContext::class);
foreach ($languageContext->getAll() as $lang) {
if ($lang->getId() === $languageContext->getDefaultId()) {
continue;
}
$this->contextManager->activateContexts([LanguageContext::class => $lang->getId()], function () use ($lang) {
$priceListContext = Contexts::get(PricelistContext::class);
$priceListContext->clearCache();
$productsQb = sqlQueryBuilder()
->update('products_translations', 'pt')
->join('pt', 'products', 'p', 'pt.id_product = p.id')
->set('pt.figure', ':figure')
->setParameter('figure', 'N')
->andWhere(Operator::equals(['pt.id_language' => $lang->getId()]))
->andWhere('pt.figure IS NULL OR pt.figure = "Y"')
->andWhere(Operator::not(static::withNonZeroPrice($lang->getId())));
$variationsQb = sqlQueryBuilder()
->update('products_variations_translations', 'pvt')
->join('pvt', 'products_variations', 'pv', 'pvt.id_products_variation = pv.id')
->join('pv', 'products', 'p', 'p.id = pv.id_product')
->set('pvt.figure', ':figure')
->setParameter('figure', 'N')
->andWhere(Operator::equals(['pvt.id_language' => $lang->getId()]))
->andWhere('pvt.figure IS NULL OR pvt.figure = "Y"')
->andWhere(Operator::not(static::withNonZeroPrice($lang->getId(), true)));
$productsQb->execute();
$variationsQb->execute();
$priceListContext->forceEmpty();
});
}
}
private function updateVariationsVisibility(string $language, ?array $productIds = null): void
{
$languageContext = Contexts::get(LanguageContext::class);
$website = $this->znzUtil->getCurrentWebsite($language);
if ($language === $languageContext->getDefaultId()) {
$this->executeQueryBuilder(
// skryju varianty, ktere maji byt skryte
sqlQueryBuilder()
->update('products_variations', 'pv')
->join('pv', 'products', 'p', 'pv.id_product = p.id')
->leftJoin('pv', 'znz_products', 'zp', 'pv.id_product = zp.id_product AND zp.id_variation = pv.id')
->leftJoin('zp', 'znz_products_website', 'zpw', 'zpw.id_znz = zp.id_znz AND zpw.id_website = :website')
->set('pv.figure', ':figure')
// pokud produkt neni videt a ma byt videt a je viditelny pro aktualni website
->andWhere('COALESCE(pv.figure, "Y") = "Y" AND (JSON_VALUE(zp.data, "$.znzFigure") = "N" OR zpw.id_znz IS NULL)')
->addParameters(['figure' => 'N', 'website' => $website]),
$productIds
);
$this->executeQueryBuilder(
// zobrazim varianty, ktere maji byt videt
sqlQueryBuilder()
->update('products_variations', 'pv')
->join('pv', 'products', 'p', 'pv.id_product = p.id')
->leftJoin('pv', 'znz_products', 'zp', 'pv.id_product = zp.id_product AND zp.id_variation = pv.id')
->leftJoin('zp', 'znz_products_website', 'zpw', 'zpw.id_znz = zp.id_znz AND zpw.id_website = :website')
->set('pv.figure', ':figure')
// pokud produkt neni videt a ma byt videt a je viditelny pro aktualni website
->andWhere('COALESCE(pv.figure, "N") = "N" AND JSON_VALUE(zp.data, "$.znzFigure") = "Y" AND zpw.id_znz IS NOT NULL')
// zobrazuju pouze varianty, ktere nemaji nulovou cenu
->andWhere(static::withNonZeroPrice($language, true))
->addParameters(['figure' => 'Y', 'website' => $website]),
$productIds
);
} else {
$this->executeQueryBuilder(
// skryju varianty, ktere maji byt skryte v prekladech
sqlQueryBuilder()
->update('products_variations_translations', 'pvt')
->join('pvt', 'products_variations', 'pv', 'pv.id = pvt.id_products_variation')
->join('pv', 'products', 'p', 'pv.id_product = p.id')
->leftJoin('pv', 'znz_products', 'zp', 'pv.id_product = zp.id_product AND zp.id_variation = pv.id')
->leftJoin('zp', 'znz_products_website', 'zpw', 'zpw.id_znz = zp.id_znz AND zpw.id_website = :website')
->set('pvt.figure', ':figure')
// pokud produkt neni videt a ma byt videt a je viditelny pro aktualni website
->andWhere('COALESCE(pvt.figure, "Y") = "Y" AND (JSON_VALUE(zp.data, "$.znzFigure") = "N" OR zpw.id_znz IS NULL)')
->andWhere(Operator::equals(['pvt.id_language' => $language]))
->addParameters(['figure' => 'N', 'website' => $website]),
$productIds
);
$this->executeQueryBuilder(
// zobrazim varianty, ktere maji byt videt v prekladech
sqlQueryBuilder()
->update('products_variations_translations', 'pvt')
->join('pvt', 'products_variations', 'pv', 'pv.id = pvt.id_products_variation')
->join('pv', 'products', 'p', 'pv.id_product = p.id')
->leftJoin('pv', 'znz_products', 'zp', 'pv.id_product = zp.id_product AND zp.id_variation = pv.id')
->leftJoin('zp', 'znz_products_website', 'zpw', 'zpw.id_znz = zp.id_znz AND zpw.id_website = :website')
->set('pvt.figure', ':figure')
// pokud produkt neni videt a ma byt videt a je viditelny pro aktualni website
->andWhere('COALESCE(pvt.figure, "N") = "N" AND JSON_VALUE(zp.data, "$.znzFigure") = "Y" AND zpw.id_znz IS NOT NULL')
->andWhere(Operator::equals(['pvt.id_language' => $language]))
// zobrazuju pouze varianty, ktere nemaji nulovou cenu
->andWhere(static::withNonZeroPrice($language, true))
->addParameters(['figure' => 'Y', 'website' => $website]),
$productIds
);
}
}
private function executeQueryBuilder(QueryBuilder $qb, ?array $productIds = null): void
{
if ($productIds) {
$qb->andWhere(Operator::inIntArray($productIds, 'p.id'));
}
$qb->execute();
}
private static function withTitle(): callable
{
return fn () => "pt.title != ''";
}
private static function withNonZeroPrice(string $language, bool $variations = false): callable
{
$priceListId = ServiceContainer::getService(ContextManager::class)->activateContexts([LanguageContext::class => $language], function () {
$priceListContext = Contexts::get(PricelistContext::class);
$priceListContext->clearCache();
$priceListId = $priceListContext->getActiveId();
$priceListContext->forceEmpty();
return $priceListId;
});
return function (QueryBuilder $qb) use ($priceListId, $variations) {
if ($priceListId) {
if ($variations) {
$qb->leftJoin('p', 'pricelists_products', 'prp', 'prp.id_product = p.id AND prp.id_variation IS NULL AND prp.id_pricelist = :priceListId')
->leftJoin('pv', 'pricelists_products', 'prv', 'prv.id_variation = pv.id AND prv.id_pricelist = :priceListId')
->setParameter('priceListId', $priceListId);
$priceField = 'COALESCE(prv.price, pv.price, prp.price, p.price)';
} else {
$qb->leftJoin('p', 'pricelists_products', 'prp', 'prp.id_product = p.id AND prp.id_variation IS NULL AND prp.id_pricelist = :priceListId')
->setParameter('priceListId', $priceListId);
$priceField = 'COALESCE(prp.price, p.price)';
}
} else {
$priceField = $variations ? 'COALESCE(pv.price, p.price)' : 'p.price';
}
return "{$priceField} > 0";
};
}
}