Files
kupshop/bundles/External/FlexiBeeBundle/Util/FlexiBeeUtil.php
2025-08-02 16:30:27 +02:00

294 lines
8.5 KiB
PHP

<?php
declare(strict_types=1);
namespace External\FlexiBeeBundle\Util;
use AbraFlexi\Relation;
use External\FlexiBeeBundle\Synchronizers\BaseSynchronizer;
use KupShop\CatalogBundle\Util\SetsUpdateStore;
use Query\Operator;
class FlexiBeeUtil
{
public function __construct(
private readonly FlexiBeeLocator $synchronizerLocator,
private readonly FlexiBeeLogger $logger,
private readonly SetsUpdateStore $setsUpdateStore,
) {
}
public function getOrderNumber(\Order $order): string
{
return 'WPJ-'.$order->order_no;
}
public function getMapping(string $type, int $flexiId): ?int
{
$id = sqlQueryBuilder()
->select('id_'.$type)
->from('flexi_'.$type.'s')
->where(Operator::equals(['id_flexi' => $flexiId]))
->execute()->fetchOne();
if (!$id) {
return null;
}
return (int) $id;
}
public function getFlexiId(string $type, int $shopId): ?int
{
$flexiId = sqlQueryBuilder()
->select('id_flexi')
->from('flexi_'.$type.'s')
->where(Operator::equals(['id_'.$type => $shopId]))
->execute()->fetchOne();
if (!$flexiId) {
return null;
}
return (int) $flexiId;
}
public function deleteMapping(string $type, int $flexiId): void
{
sqlQueryBuilder()
->delete('flexi_'.$type.'s')
->andWhere(Operator::equals(['id_flexi' => $flexiId]))
->execute();
}
public function createMapping(string $type, int $flexiId, int $shopId): void
{
sqlQueryBuilder()
->insert('flexi_'.$type.'s')
->directValues(
[
'id_flexi' => $flexiId,
'id_'.$type => $shopId,
]
)
->execute();
}
public function createItemMapping(int $flexiId, int $productId, ?int $variationId = null): void
{
sqlQueryBuilder()
->insert('flexi_products')
->directValues(
[
'id_flexi' => $flexiId,
'id_product' => $productId,
'id_variation' => $variationId,
]
)->execute();
}
public function setFlexiOrderData(int $orderId, string $key, $value): void
{
sqlGetConnection()->transactional(function () use ($orderId, $key, $value) {
$data = sqlQueryBuilder()
->select('data')
->from('flexi_orders')
->where(Operator::equalsNullable(['id_order' => $orderId]))
->execute()->fetchOne();
$data = json_decode($data ?: '', true) ?? [];
$data[$key] = $value;
sqlQueryBuilder()
->update('flexi_orders')
->directValues(['data' => json_encode($data)])
->where(Operator::equals(['id_order' => $orderId]))
->execute();
});
}
public function getProductFlexiId(int $productId, ?int $variationId = null): ?int
{
$flexiId = sqlQueryBuilder()
->select('id_flexi')
->from('flexi_products')
->where(
Operator::equalsNullable(
[
'id_product' => $productId,
'id_variation' => $variationId,
]
)
)
->execute()->fetchColumn();
if (!$flexiId) {
return null;
}
return (int) $flexiId;
}
public function getItemMapping(int $flexiId): ?array
{
$data = sqlQueryBuilder()
->select('id_product, id_variation')
->from('flexi_products')
->where(Operator::equals(['id_flexi' => $flexiId]))
->execute()->fetch();
if (!$data) {
return null;
}
return [(int) $data['id_product'], $data['id_variation'] ? (int) $data['id_variation'] : null];
}
public function getProductId(string $code): ?int
{
$id = sqlQueryBuilder()
->select('id')
->from('products')
->where(Operator::equals(['code' => $code]))
->execute()->fetchOne();
if (!$id) {
return null;
}
return (int) $id;
}
public function getVariationId(string $code): ?int
{
$id = sqlQueryBuilder()
->select('id')
->from('products_variations')
->where(Operator::equals(['code' => $code]))
->execute()->fetchOne();
if (!$id) {
return null;
}
return (int) $id;
}
public function getFlexiIdFromRef(string $ref): int
{
$parts = explode('/', $ref);
return (int) end($parts);
}
public function parseFlexiCode($itemPart): ?string
{
if ($itemPart instanceof Relation) {
$itemPart = $itemPart->value;
}
if (is_array($itemPart)) {
$itemPart = reset($itemPart);
}
$code = explode(':', $itemPart);
$code = end($code);
return !empty($code) ? $code : null;
}
public function recalculateStores(): void
{
$getQuantitySubQuery = function (bool $variations = false) {
$alias = 'p';
$productIdColumn = 'id';
if ($variations) {
$alias = 'pv';
$productIdColumn = 'id_product';
}
$qb = sqlQueryBuilder()
->select('COALESCE(SUM(GREATEST(si.quantity, 0)), 0)')
->from('stores_items', 'si')
->where('si.id_product = '.$alias.'.'.$productIdColumn);
if ($variations) {
$qb->andWhere('si.id_variation = pv.id');
} else {
$qb->andWhere('si.id_variation IS NULL');
}
return $qb;
};
$productsSubQuery = $getQuantitySubQuery();
$productsQuantityQb = sqlQueryBuilder()
->update('products', 'p')
->leftJoin('p', 'products_variations', 'pv', 'pv.id_product = p.id')
->set('p.in_store', "({$productsSubQuery->getSQL()})")
->andWhere('pv.id IS NULL AND p.in_store != ('.$productsSubQuery->getSQL().')')
->addQueryBuilderParameters($productsSubQuery);
// ignorujeme sety - protoze ty se prepocitaji zvlast pomoci `setsUpdateStore->updateSetsStore()`
if (findModule(\Modules::PRODUCT_SETS, \Modules::SUB_CALCULATE_STOCK)) {
$productsQuantityQb->leftJoin('p', 'products_sets', 'ps', 'ps.id_product = p.id')
->andWhere('ps.id_product IS NULL');
}
$productsQuantityQb->execute();
$variationsSubQuery = $getQuantitySubQuery(true);
sqlQuery(
'UPDATE products_variations pv
SET pv.in_store = ('.$variationsSubQuery->getSQL().')
WHERE pv.in_store != ('.$variationsSubQuery->getSQL().');', $variationsSubQuery->getParameters(), $variationsSubQuery->getParameterTypes());
\Variations::recalcInStore();
if (findModule(\Modules::PRODUCT_SETS, \Modules::SUB_CALCULATE_STOCK)) {
$this->setsUpdateStore->updateSetsStore();
}
}
public function synchronize(array $types, int $mode = BaseSynchronizer::MODE_NORMAL): void
{
foreach ($types as $type) {
try {
$synchronizer = $this->synchronizerLocator->getServiceByType($type);
$synchronizer->setMode($mode);
$synchronizer->sync();
} catch (\Throwable $e) {
if (isDevelopment()) {
throw $e;
}
$this->logger->exception($e, '[FlexiBee] Během synchronizace se vyskytla chyba!', [
'type' => $type,
'mode' => $mode,
]);
}
}
}
public function findItemByCode(string $code): ?array
{
$result = null;
if ($variationId = $this->getVariationId($code)) {
$productId = sqlQueryBuilder()
->select('id_product')
->from('products_variations')
->andWhere(Operator::equals(['id' => $variationId]))
->execute()->fetchOne();
$result = [(int) $productId, $variationId];
} elseif ($productId = $this->getProductId($code)) {
$result = [$productId, null];
}
return $result;
}
}