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

245 lines
9.2 KiB
PHP

<?php
namespace KupShop\WarehouseBundle\Util;
use KupShop\WarehouseBundle\Entity\StoreItem;
use Query\Operator;
class InventoryWorker
{
/**
* @var Logger
*/
private $logger;
/**
* @var StoreItemWorker
*/
private $storeItemWorker;
public function __construct(Logger $logger, StoreItemWorker $storeItemWorker)
{
$this->logger = $logger;
$this->storeItemWorker = $storeItemWorker;
}
protected $inventoryPosition;
/**
* @param int $position
* @param array $products
* @param null $position_code
*
* @return array
*
* @throws \Throwable
*/
public function submitInventory($position, $products, $position_code = null)
{
$result = [];
sqlGetConnection()->transactional(function () use ($position, $products, &$result, $position_code) {
$inventoryDate = new \DateTime();
$inventoryDate->setTimezone(new \DateTimeZone(date_default_timezone_get()));
foreach ($products as $product) {
$ean = $product->ean;
$batchId = $product->id_product_batch ?? null;
$existsProductOnPosition = $this->storeItemWorker->checkProductByEanAndLocation($ean, null, $position_code, $batchId);
// TODO: Tohle je desne pomaly a lockuje to veskery dalsi pohyby ve skladu i kosik / objednavky.
// Mozna by stacilo selectit jen p.in_store a pv.in_store, aby se locknul jen ten jeden sloupecek, ale stejne to asi bude problem.
// Zkusil jsem pridat indexy na EANy a porad to bylo pomaly :-(
// Proc tohle nejde napsat pres id produktu? Ze by se to pustilo az za nasledujicim dotazem a uz jsme vedeli idcka
// sqlQuery('SELECT * FROM products p
// JOIN products_variations pv ON pv.id_product = p.id
// LEFT JOIN products_of_suppliers pos ON p.id=pos.id_product AND (pv.id IS NULL OR pv.id=pos.id_variation)
// WHERE pv.ean=:ean OR p.ean=:ean OR pos.ean=:ean FOR UPDATE', ['ean' => $ean]);
if (!$existsProductOnPosition) {
$eProdOnPosSQL = sqlQueryBuilder()
->select('p.id as id_product, pv.id as id_variation, 0 as pieces')
->from('products', 'p')
->joinVariationsOnProducts()
->leftJoin('pv', 'products_of_suppliers', 'pos', 'p.id=pos.id_product AND (pv.id IS NULL OR pv.id=pos.id_variation)')
->where(Operator::equals(['pv.ean' => $ean, 'p.ean' => $ean, 'pos.ean' => $ean], 'OR'))
->setMaxResults(1);
if (findModule(\Modules::PRODUCTS_BATCHES)) {
$eProdOnPosSQL->addSelect(':batchId as id_product_batch')
->setParameter('batchId', $batchId);
}
$existsProductOnPosition = $eProdOnPosSQL->execute()->fetch();
}
$existsProductOnPosition['over_supply'] = $product->over_supply;
$piecesToStore = intval($product->checked) - $existsProductOnPosition['pieces'];
if ($piecesToStore != 0) {
$storeItem = new StoreItem($existsProductOnPosition);
$this->storeItemWorker->createStoreItem($storeItem,
$piecesToStore,
$position,
['inventory' => true],
false
);
$this->storeIn($existsProductOnPosition, $piecesToStore);
$this->logger->logProductMove($storeItem,
$piecesToStore,
$this->getInventoryPosition(),
$position);
}
$where = [
'id_position' => $position,
'id_product' => $existsProductOnPosition['id_product'],
'id_variation' => $existsProductOnPosition['id_variation'],
];
if (findModule(\Modules::PRODUCTS_BATCHES)) {
$where['id_product_batch'] = $batchId;
}
sqlQueryBuilder()
->update('warehouse_products')
->set('inventory_date', ':inv_datetime')
->setParameter('inv_datetime', $inventoryDate, 'datetime')
->where(Operator::equalsNullable($where))
->execute();
}
sqlQueryBuilder()
->update('warehouse_positions')
->set('inventory_date', ':inv_datetime')
->setParameter('inv_datetime', $inventoryDate, 'datetime')
->where(Operator::equalsNullable([
'id' => $position,
]))
->execute();
$result = [
'result' => true,
'message' => "Inventura pozice {$position_code} provedena",
];
});
return $result;
}
public function getInventoryPosition()
{
if ($this->inventoryPosition) {
return $this->inventoryPosition;
}
return $this->inventoryPosition = sqlQueryBuilder()
->select('id')
->from('warehouse_positions')
->where(Operator::like(['code' => 'INVENTURA']))
->execute()->fetchColumn();
}
public function loadProductsCache()
{
$sqlProducts = sqlQueryBuilder()
->select('p.title as p_title, pv.title as pv_title, COALESCE(pv.ean, p.ean) as ean, COALESCE(pv.code, p.code) as code,
p.id as id_product, pv.id as id_variation, \'\' as checked')
->from('products', 'p')
->joinVariationsOnProducts()
->addSelect(\Query\Product::withProductPhotoId(true))
->groupBy('p.id, pv.id');
$getProductId = function ($prod) {
return $prod['id_product'].($prod['id_variation'] ? '_'.$prod['id_variation'] : '');
};
$productsBatches = [];
if (findModule(\Modules::PRODUCTS_BATCHES)) {
$sqlProducts->addSelect('p.batch_number_require');
$sqlBatches = sqlQueryBuilder()->select('id_product, id_variation, id, code, date_expiry')
->from('products_batches', 'pb')
->execute();
foreach ($sqlBatches as $batch) {
$productsBatches[$getProductId($batch)][] = [
'id' => $batch['id'],
'code' => $batch['code'],
'date_expiry' => $batch['date_expiry'],
];
}
}
foreach ($sqlProducts->execute() as $prod) {
$photo = getImage($prod['id_photo'], null, null, 4, $prod['descr_photo'], strtotime($prod['id_photo_update']));
yield $getProductId($prod) => [
'batches' => $productsBatches[$getProductId($prod)] ?? [],
'image' => $photo ? ['src' => $photo['src'], 'src_big' => $photo['src_big']] : null,
'ean' => formatEAN($prod['ean']),
'over_supply' => false,
] + array_diff_key($prod, ['id_photo' => 0, 'id_photo_update' => 0, 'descr_photo' => 0]);
}
}
public function loadProductsEans()
{
$eans = sqlQueryBuilder()->select('COALESCE(pv.ean, p.ean) ean, p.id as id_product, pv.id as id_variation,
CONCAT_WS("_", p.id, pv.id) as id')
->fromProducts()
->joinVariationsOnProducts()
->where('COALESCE(pv.ean, p.ean) IS NOT NULL')
->execute();
foreach ($eans as $ean) {
yield $ean['ean'] => $ean;
}
}
public function loadProductsSuppliersEans()
{
$suppliersEans = sqlQueryBuilder()->select('ean, id_product, id_variation,
CONCAT_WS("_", id_product, id_variation) as id')
->from('products_of_suppliers')
->where('ean IS NOT NULL')
->execute();
foreach ($suppliersEans as $ean) {
yield $ean['ean'] => $ean;
}
}
public function productBatches($ean)
{
$sqlBatches = sqlQueryBuilder()
->select('pb.id, pb.code, pb.date_expiry')
->fromProducts()
->joinVariationsOnProducts()
->where(Operator::equals(['pv.ean' => $ean, 'p.ean' => $ean], 'OR'))
->innerJoin('pv', 'products_batches', 'pb', 'p.id = pb.id_product AND pv.id <=> pb.id_variation');
$productBatches = [];
foreach ($sqlBatches->execute() as $batch) {
$productBatches[] = [
'id' => $batch['id'],
'code' => $batch['code'],
'date_expiry' => $batch['date_expiry'],
];
}
return $productBatches;
}
/**
* @param array $existsProductOnPosition
* @param int $piecesToStore
*/
public function storeIn($existsProductOnPosition, $piecesToStore)
{
$prod = new \Product($existsProductOnPosition['id_product']);
$prod->storeIn($existsProductOnPosition['id_variation'], $piecesToStore);
}
}