609 lines
25 KiB
PHP
609 lines
25 KiB
PHP
<?php
|
|
|
|
namespace KupShop\CheckAppBundle\Util;
|
|
|
|
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
|
use KupShop\CatalogBundle\Util\Product\ProductPriceWeigher;
|
|
use KupShop\CheckAppBundle\Exception\StockInException;
|
|
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
|
use KupShop\KupShopBundle\Util\EANValidator;
|
|
use KupShop\KupShopBundle\Util\LoggingContext;
|
|
use KupShop\KupShopBundle\Util\StringUtil;
|
|
use KupShop\ProductsBatchesBundle\Util\ProductsBatchesUtil;
|
|
use KupShop\StoresBundle\Utils\StoresInStore;
|
|
use Query\Operator;
|
|
use Symfony\Contracts\Service\Attribute\Required;
|
|
|
|
class StockInWorker
|
|
{
|
|
use \DatabaseCommunication;
|
|
|
|
protected $newStockInId = [];
|
|
|
|
/**
|
|
* @var ProductPriceWeigher
|
|
*/
|
|
protected $productPriceWeigher;
|
|
|
|
protected ?StoresInStore $storesInStore;
|
|
|
|
#[Required]
|
|
public LoggingContext $loggingContext;
|
|
|
|
/**
|
|
* @required
|
|
*/
|
|
public function setProductPriceWeigher(ProductPriceWeigher $productPriceWeigher)
|
|
{
|
|
$this->productPriceWeigher = $productPriceWeigher;
|
|
}
|
|
|
|
#[Required]
|
|
public function setStoresInStore(?StoresInStore $storesInStore)
|
|
{
|
|
$this->storesInStore = $storesInStore;
|
|
}
|
|
|
|
public function getStockIn($id_stock_in)
|
|
{
|
|
return sqlQueryBuilder()->select('code')->from('stock_in')
|
|
->where(Operator::equals(['id' => $id_stock_in]))
|
|
->execute()->fetch();
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*
|
|
* @throws \Exception
|
|
*/
|
|
public function getStockInData($id_stock_in)
|
|
{
|
|
if (strpos($id_stock_in, '_') !== false) {
|
|
$ids = array_reverse(explode('_', $id_stock_in));
|
|
} else {
|
|
$ids = [$id_stock_in];
|
|
}
|
|
|
|
$stockInsItems = [];
|
|
$index = 0;
|
|
|
|
foreach ($ids as $id) {
|
|
$qb = sqlQueryBuilder()
|
|
->select('sii.id as id, CONCAT_WS(" ", p.title, pv.title) as title, SUM(sii.quantity) as quantity, COALESCE(pv.code, p.code) as code,
|
|
COALESCE(pv.ean, p.ean) as ean, sii.id_product, sii.id_variation, COALESCE(pv.note, p.note) as note')
|
|
->from('stock_in_items', 'sii')
|
|
->join('sii', 'stock_in', 'si', "si.id=sii.id_stock_in AND si.id_index='future'")
|
|
->leftJoin('sii', 'products', 'p', 'p.id=sii.id_product')
|
|
->leftJoin('sii', 'products_variations', 'pv', 'pv.id=sii.id_variation')
|
|
->where(Operator::equals(['id_stock_in' => $id]))
|
|
->addSelect(\Query\Product::withOneProductPhotoId(true))
|
|
->groupBy('sii.id_product, sii.id_variation')
|
|
->orderBy('sii.id', 'DESC');
|
|
|
|
if (findModule(\Modules::PRODUCTS_SERIAL_NUMBERS)) {
|
|
$qb->addSelect('p.serial_number_require');
|
|
}
|
|
|
|
if (findModule(\Modules::PRODUCTS_BATCHES)) {
|
|
$qb->addSelect('p.batch_number_require');
|
|
}
|
|
|
|
$items = $qb->execute()->fetchAll();
|
|
|
|
foreach ($items as $key => $item) {
|
|
if (empty($item['id_product'])) {
|
|
continue;
|
|
}
|
|
|
|
$item['quantity'] = (int) $item['quantity'];
|
|
$item['ean'] = formatEAN($item['ean']);
|
|
|
|
if ($item['id_photo']) {
|
|
$item['image'] = getImage($item['id_photo'], null, null, 3)['src'];
|
|
}
|
|
|
|
$item['stock_ins_count'] = sqlQueryBuilder()->select('COUNT(sii.id) as stock_in_count')
|
|
->from('stock_in_items', 'sii')
|
|
->leftJoin('sii', 'stock_in', 'si', 'si.id = sii.id_stock_in')
|
|
->where(
|
|
Operator::equalsNullable(
|
|
[
|
|
'sii.id_product' => $item['id_product'],
|
|
'sii.id_variation' => $item['id_variation'],
|
|
]
|
|
)
|
|
)
|
|
->andWhere('si.id_index != "future"')
|
|
->execute()->fetchColumn();
|
|
|
|
if (findModule(\Modules::PRODUCTS_BATCHES)) {
|
|
$item['batches_numbers'] = sqlQueryBuilder()->select('id, code', 'date_expiry')->from('products_batches', 'pb')
|
|
->where(
|
|
Operator::equalsNullable(
|
|
[
|
|
'pb.id_product' => $item['id_product'],
|
|
'pb.id_variation' => $item['id_variation'],
|
|
]
|
|
)
|
|
)
|
|
->orderBy('date_expiry', 'DESC')->addOrderBy('id', 'DESC')
|
|
->execute()->fetchAll();
|
|
}
|
|
|
|
if (empty($stockInsItems[$item['id_product'].'_'.$item['id_variation']])) {
|
|
$addData = $this->getAdditionalData($item['id_product'], $item['id_variation']);
|
|
|
|
if ($addData) {
|
|
$item = array_merge($item, $addData);
|
|
}
|
|
|
|
$stockInsItems[$item['id_product'].'_'.$item['id_variation']] = $item;
|
|
} else {
|
|
$stockInsItems[$item['id_product'].'_'.$item['id_variation']]['quantity'] += (int) $item['quantity'];
|
|
}
|
|
}
|
|
}
|
|
|
|
$data = $stockInsItems;
|
|
|
|
usort($data, function ($a, $b) {
|
|
return empty($b['ean']) <=> empty($a['ean']);
|
|
});
|
|
|
|
foreach ($data as &$item) {
|
|
$item['index'] = $index++;
|
|
}
|
|
|
|
return array_values($data);
|
|
}
|
|
|
|
protected function getAdditionalData($id_product, $id_variation): array
|
|
{
|
|
$data = sqlQueryBuilder()
|
|
->select('GROUP_CONCAT(pos.ean SEPARATOR ";") as supplier_eans, GROUP_CONCAT(pos.code SEPARATOR ";") as supplier_codes')
|
|
->from('products_of_suppliers', 'pos')
|
|
->where(Operator::equalsNullable(['pos.id_product' => $id_product, 'pos.id_variation' => $id_variation]))
|
|
->groupBy('pos.id_product, pos.id_variation')
|
|
->execute()->fetch();
|
|
|
|
if ($data) {
|
|
$data['supplier_eans'] = explode(';', $data['supplier_eans']);
|
|
$data['supplier_codes'] = explode(';', $data['supplier_codes']);
|
|
} else {
|
|
$data = [];
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*
|
|
* @throws \Exception
|
|
* @throws \Throwable
|
|
*/
|
|
public function submitStockIn($id_stock_in, $items)
|
|
{
|
|
$checkedItems = [];
|
|
|
|
// Jen si to přeindexuju pro lepší práci
|
|
foreach ($items as $item) {
|
|
$checkedItems[$item->id_product.'_'.$item->id_variation] = $item;
|
|
}
|
|
|
|
$stockInIds = array_unique(explode('_', $id_stock_in));
|
|
|
|
sqlGetConnection()->transactional(
|
|
function () use ($stockInIds, $checkedItems) {
|
|
// Lock stock all stock-ins to avoid concurent updates
|
|
$stockIns = sqlQueryBuilder()->select('id', 'number', 'id_index')
|
|
->from('stock_in')
|
|
->where(Operator::inIntArray($stockInIds, 'id'))
|
|
->orderBy('id', 'DESC')
|
|
->forUpdate()
|
|
->execute()->fetchAll();
|
|
|
|
$nonFutures = array_filter($stockIns, function ($stockIn) {return $stockIn['id_index'] != 'future'; });
|
|
if ($nonFutures) {
|
|
throw new StockInException('Naskladnění již proběhlo s čísly faktur: '.join(', ', array_map(f_field('number'), $nonFutures)));
|
|
}
|
|
|
|
foreach ($stockInIds as $stockInId) {
|
|
$number = returnSQLResult('SELECT MAX(number)+1 FROM stock_in WHERE id_index="invoice"');
|
|
if (empty($number)) {
|
|
$number = 1;
|
|
}
|
|
|
|
sqlQueryBuilder()->update('stock_in')
|
|
->set('id_index', ':invoice')
|
|
->set('number', $number)
|
|
->set('date_stock_in', 'NOW()')
|
|
->setParameter('invoice', 'invoice')
|
|
->where(Operator::equals(['id' => $stockInId]))
|
|
->execute();
|
|
|
|
// Načtení položek + kod a dodavatel faktury, aby pri presunu polozky do nove faktury
|
|
// sem vzdy vedel dodavatele i kod puvodni faktury - musi se totiz nejdriv nova faktura vytvorit zejo
|
|
$stockInItems = sqlQueryBuilder()
|
|
->select('sii.*, si.id_supplier, si.code as stock_in_code, si.data')
|
|
->from('stock_in_items', 'sii')
|
|
->leftJoin('sii', 'stock_in', 'si', 'sii.id_stock_in=si.id')
|
|
->where(Operator::equals(['sii.id_stock_in' => $stockInId]))
|
|
->execute()
|
|
->fetchAll();
|
|
|
|
foreach ($stockInItems as $itemRow) {
|
|
$checkedItem = &$checkedItems[$itemRow['id_product'].'_'.$itemRow['id_variation']];
|
|
|
|
// Pokud je v naskladnění položka bez id_produktu, je to nový produkt - ještě nemá založenou kartu,
|
|
// tak mu nastavím checked 0 aby se přesunul do nového budoucího naskladnění
|
|
if (empty($itemRow['id_product'])) {
|
|
if (!$checkedItem) {
|
|
$checkedItems[$itemRow['id_product'].'_'.$itemRow['id_variation']] = new \stdClass();
|
|
}
|
|
|
|
$checkedItem->checked = 0;
|
|
}
|
|
|
|
// Pokud je daný produkt chcked, pokračuju, když není, můžu ho z dané faktury rovnou smazat
|
|
if (!empty($checkedItem->checked)) {
|
|
// Pokud je méně napípnuto než má být, aktualizuju naskladnění a zruším checked položku, tím pádem u
|
|
// dalšího naskladnění už dochází k její odmazávání
|
|
if ($checkedItem->checked < $itemRow['quantity']) {
|
|
sqlQueryBuilder()
|
|
->update('stock_in_items')
|
|
->set('quantity', $checkedItem->checked)
|
|
->where(Operator::equals(['id' => $itemRow['id']]))
|
|
->execute();
|
|
$inStoredPieces = $checkedItem->checked;
|
|
|
|
// Do nove faktury vkladam jen zbytek kusu, proto tu odectu uz napipane
|
|
$itemRow['quantity'] = $itemRow['quantity'] - $checkedItem->checked;
|
|
$this->insertIntoNewStockIn($itemRow);
|
|
|
|
unset($checkedItems[$itemRow['id_product'].'_'.$itemRow['id_variation']]);
|
|
} else {
|
|
// Pokud je napípnuto víc, pouze odečtu a nechám další napípnuté pro další naskladnění
|
|
$checkedItem->checked -= $inStoredPieces = $itemRow['quantity'];
|
|
}
|
|
|
|
if (findModule(\Modules::PRODUCTS_BATCHES) && ($checkedItem->batch_number_require ?? 'N') == 'Y') {
|
|
$productsBatchesUtil = ServiceContainer::getService(ProductsBatchesUtil::class);
|
|
|
|
$batchNumber = null;
|
|
if ($checkedItem->batchNumber->id ?? false) {
|
|
$batchNumber = $productsBatchesUtil->getBatchNumber($checkedItem->batchNumber->id);
|
|
}
|
|
if (!$batchNumber) {
|
|
$batchNumber = $productsBatchesUtil->createBatchNumber([
|
|
'id_product' => $checkedItem->id_product,
|
|
'id_variation' => $checkedItem->id_variation,
|
|
'code' => $checkedItem->batchNumber->code,
|
|
'date_expiry' => $checkedItem->batchNumber->date_expiry,
|
|
]);
|
|
}
|
|
|
|
$itemRow['batchNumber'] = $batchNumber;
|
|
}
|
|
|
|
$itemRow['id_product_batch'] = $itemRow['batchNumber']['id'] ?? null;
|
|
$this->storeIn($itemRow, $inStoredPieces);
|
|
$this->addSerialNumbers($checkedItem, $stockInId, $inStoredPieces);
|
|
|
|
if ($checkedItem->checked == 0) {
|
|
unset($checkedItems[$itemRow['id_product'].'_'.$itemRow['id_variation']]);
|
|
}
|
|
|
|
if (findModule(\Modules::STOCK_IN)) {
|
|
$this->updatePriceBuy($itemRow);
|
|
|
|
if (($checkedItem->quantity ?? 0) > 0) {
|
|
sqlQueryBuilder()
|
|
->update('products')
|
|
->set('date_stock_in', 'NOW()')
|
|
->andWhere(Operator::equals(['id' => $itemRow['id_product']]))
|
|
->execute();
|
|
}
|
|
}
|
|
} else {
|
|
sqlQueryBuilder()
|
|
->delete('stock_in_items')
|
|
->where(Operator::equals(['id' => $itemRow['id']]))
|
|
->execute();
|
|
|
|
$this->insertIntoNewStockIn($itemRow);
|
|
|
|
unset($checkedItems[$itemRow['id_product'].'_'.$itemRow['id_variation']]);
|
|
}
|
|
}
|
|
|
|
// unset kvůli referenci a následnému použití $checkedItem níže
|
|
unset($checkedItem);
|
|
}
|
|
|
|
// Pričtení napípnutých kusů navíc, které nebyly v žádné faktuře,
|
|
// od konce projíždím jednotlivé faktury a přičtu to k první, která má daný produkt
|
|
foreach (array_reverse($stockInIds) as $stockInId) {
|
|
$stockInItems = sqlQueryBuilder()
|
|
->select('sii.*, si.data')
|
|
->from('stock_in_items', 'sii')
|
|
->leftJoin('sii', 'stock_in', 'si', 'sii.id_stock_in=si.id')
|
|
->where(Operator::equals(['sii.id_stock_in' => $stockInId]))
|
|
->execute()
|
|
->fetchAll();
|
|
|
|
foreach ($stockInItems as $stockInItem) {
|
|
if (!empty($checkedItems[$stockInItem['id_product'].'_'.$stockInItem['id_variation']])) {
|
|
$checkedItem = $checkedItems[$stockInItem['id_product'].'_'.$stockInItem['id_variation']];
|
|
|
|
sqlQueryBuilder()
|
|
->update('stock_in_items')
|
|
->set('quantity', "quantity + {$checkedItem->checked}")
|
|
->where(Operator::equals(['id' => $stockInItem['id']]))
|
|
->execute();
|
|
|
|
$this->storeIn($stockInItem, $checkedItem->checked);
|
|
$this->addSerialNumbers($checkedItem, $stockInId, $checkedItem->checked);
|
|
|
|
unset($checkedItems[$stockInItem['id_product'].'_'.$stockInItem['id_variation']]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!empty($checkedItems)) {
|
|
throw new \Exception('!! Něco se pohnojilo a zbyly nějaké kusy, s kterými se nic nestalo !!');
|
|
}
|
|
|
|
foreach ($stockInIds as $stockInId) {
|
|
$this->recalcTotalPrice($stockInId);
|
|
}
|
|
|
|
foreach ($this->newStockInId as $stockInId) {
|
|
$this->recalcTotalPrice($stockInId);
|
|
}
|
|
}
|
|
);
|
|
|
|
return true;
|
|
}
|
|
|
|
public function recalcTotalPrice($stockInId)
|
|
{
|
|
if (findModule(\Modules::STOCK_IN, \Modules::SUB_WEIGHTED_PURCHASE_PRICE)) {
|
|
// recalculate transport price by additional costs
|
|
sqlQuery('UPDATE stock_in s
|
|
SET transport_price = (
|
|
SELECT COALESCE(SUM(si.quantity*si.additional_costs), 0)
|
|
FROM stock_in_items si
|
|
WHERE si.id_stock_in=s.id
|
|
)
|
|
WHERE s.id=:id', ['id' => $stockInId]);
|
|
}
|
|
|
|
sqlQuery('UPDATE stock_in s
|
|
SET total_price=(
|
|
SELECT COALESCE(SUM(si.quantity*si.price), 0)+s.transport_price-s.discount
|
|
FROM stock_in_items si
|
|
WHERE si.id_stock_in=s.id
|
|
)
|
|
WHERE s.id=:id', ['id' => $stockInId]);
|
|
}
|
|
|
|
public function storeIn($itemRow, int $inStoredPieces): void
|
|
{
|
|
$itemRow['product'] = new \Product($itemRow['id_product']);
|
|
$itemRow['quantity'] = $inStoredPieces;
|
|
|
|
$this->productPriceWeigher->updatePurchasePrice($itemRow);
|
|
|
|
// do not storeIn if store is external
|
|
$updateWebStore = true;
|
|
|
|
if (findModule(\Modules::STORES) && ($store_id = json_decode($itemRow['data'] ?? '', true)['id_store'] ?? false)) {
|
|
$updateWebStore = !$this->isExternalStore($store_id);
|
|
$SQLfields = [
|
|
'id_store' => $store_id,
|
|
'id_product' => $itemRow['id_product'],
|
|
'id_variation' => $itemRow['id_variation'],
|
|
'quantity' => $itemRow['quantity'],
|
|
];
|
|
|
|
$this->loggingContext->activateStockIn($itemRow['id_stock_in'], function () use ($SQLfields) {
|
|
$this->storesInStore->updateStoreItem($SQLfields);
|
|
});
|
|
}
|
|
|
|
if ($updateWebStore) {
|
|
$itemRow['product']->storeIn($itemRow['id_variation'], $inStoredPieces);
|
|
}
|
|
}
|
|
|
|
protected function addSerialNumbers(&$item, $stockInId, $pieces)
|
|
{
|
|
if (!findModule(\Modules::PRODUCTS_SERIAL_NUMBERS) || $item->serial_number_require != 'Y') {
|
|
return;
|
|
}
|
|
|
|
if (count($item->serialNumbers) < $pieces) {
|
|
throw new StockInException('!! Chybí sériové čísla !!');
|
|
}
|
|
$serialNumbers = array_slice($item->serialNumbers, 0, $pieces);
|
|
$item->serialNumbers = array_slice($item->serialNumbers, $pieces);
|
|
|
|
try {
|
|
foreach ($serialNumbers as $serialNumber) {
|
|
sqlQueryBuilder()->insert('products_serial_numbers')->directValues(
|
|
[
|
|
'id_product' => $item->id_product,
|
|
'id_variation' => $item->id_variation,
|
|
'serial_number' => $serialNumber,
|
|
'id_stock_in' => $stockInId,
|
|
]
|
|
)->execute();
|
|
}
|
|
} catch (ConstraintViolationException $e) {
|
|
throw new StockInException('!! Duplicitní sériové číslo u produktu !!');
|
|
}
|
|
}
|
|
|
|
protected function insertIntoNewStockIn($stockInItemRow)
|
|
{
|
|
$stockInItemRow['id_stock_in'] = $this->getNewStockInId($stockInItemRow);
|
|
|
|
unset($stockInItemRow['id'], $stockInItemRow['id_supplier'], $stockInItemRow['stock_in_code'], $stockInItemRow['data']);
|
|
|
|
if ($existStockInItem = sqlQueryBuilder()
|
|
->select('*')
|
|
->from('stock_in_items')
|
|
->where(Operator::equalsNullable(
|
|
$stockInItemRow
|
|
))
|
|
->execute()
|
|
->fetch()
|
|
) {
|
|
sqlQueryBuilder()
|
|
->update('stock_in_items')
|
|
->set('quantity', "quantity + {$stockInItemRow['quantity']}")
|
|
->where(Operator::equals(['id' => $existStockInItem['id']]))
|
|
->execute();
|
|
} else {
|
|
sqlQueryBuilder()->insert('stock_in_items')
|
|
->directValues($stockInItemRow)
|
|
->execute();
|
|
}
|
|
}
|
|
|
|
protected function getNewStockInId($stockInItemRow)
|
|
{
|
|
if (!array_key_exists($stockInItemRow['id_supplier'], $this->newStockInId)) {
|
|
$oldStockIn = sqlQueryBuilder()
|
|
->select('*')
|
|
->from('stock_in')
|
|
->where(Operator::equals(['id' => $stockInItemRow['id_stock_in']]))
|
|
->execute()->fetch();
|
|
|
|
$oldStockInData = json_decode($oldStockIn['data'] ?? '', true) ?? [];
|
|
$code = $stockInItemRow['stock_in_code'];
|
|
|
|
foreach (range(1, 5) as $_) {
|
|
$code = StringUtil::duplicateCode($code, '#');
|
|
try {
|
|
$this->insertSQL('stock_in', [
|
|
'id_index' => 'future',
|
|
'code' => $code,
|
|
'date_created' => $oldStockIn['date_created'],
|
|
'id_supplier' => $stockInItemRow['id_supplier'],
|
|
'date_expiration' => $oldStockIn['date_expiration'],
|
|
'date_issued' => $oldStockIn['date_issued'],
|
|
'flags' => 'O',
|
|
'multiplier' => $oldStockIn['multiplier'],
|
|
'payment_method' => $oldStockIn['payment_method'],
|
|
'paid' => $oldStockIn['paid'],
|
|
'note' => $oldStockIn['note'],
|
|
'data' => json_encode(
|
|
array_merge($oldStockInData, [
|
|
'parent_stock_in' => $stockInItemRow['id_stock_in'],
|
|
])
|
|
),
|
|
]);
|
|
break;
|
|
} catch (UniqueConstraintViolationException) {
|
|
// Ignore duplicate code exception, generate new code and try again
|
|
}
|
|
}
|
|
|
|
$this->newStockInId[$stockInItemRow['id_supplier']] = sqlInsertId();
|
|
}
|
|
|
|
return $this->newStockInId[$stockInItemRow['id_supplier']];
|
|
}
|
|
|
|
protected function updatePriceBuy(array $item): void
|
|
{
|
|
if (findModule(\Modules::PRODUCTS, \Modules::SUB_PRICE_BUY)
|
|
&& findModule(\Modules::PRODUCTS, \Modules::SUB_PRICE_BUY) !== 'do_not_update'
|
|
&& !findModule(\Modules::STOCK_IN, \Modules::SUB_WEIGHTED_PURCHASE_PRICE)
|
|
) {
|
|
$qb = sqlQueryBuilder()
|
|
->update(($item['id_variation'] ?? false) ? 'products_variations' : 'products')
|
|
->set('price_buy', $item['price']);
|
|
if ($item['id_variation'] ?? false) {
|
|
$qb->andWhere(Operator::equals(['id' => $item['id_variation']]));
|
|
} else {
|
|
$qb->andWhere(Operator::equals(['id' => $item['id_product']]));
|
|
}
|
|
$qb->execute();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function addEan($stockInItem, $ean)
|
|
{
|
|
$stockInRow = sqlQueryBuilder()->select('id_variation, id_product')
|
|
->from('stock_in_items')
|
|
->where(Operator::equals(['id' => $stockInItem]))
|
|
->execute()
|
|
->fetch();
|
|
|
|
if (\Variations::eanExists($stockInRow['id_variation'], $ean, $stockInRow['id_product'])) {
|
|
$result = 'Tento EAN již existuje !';
|
|
} else {
|
|
$result = true;
|
|
sqlQueryBuilder()->update(empty($stockInRow['id_variation']) ? 'products' : 'products_variations')
|
|
->directValues([
|
|
'ean' => $ean,
|
|
])
|
|
->where(Operator::equals(['id' => empty($stockInRow['id_variation']) ? $stockInRow['id_product'] : $stockInRow['id_variation']]))
|
|
->execute();
|
|
}
|
|
|
|
return [
|
|
'result' => $result === true,
|
|
'msg' => $result,
|
|
'ean' => $ean,
|
|
];
|
|
}
|
|
|
|
public function generateEan($stockInItem)
|
|
{
|
|
$stockInRow = sqlQueryBuilder()->select('id_variation, id_product')
|
|
->from('stock_in_items')
|
|
->where(Operator::equals(['id' => $stockInItem]))
|
|
->execute()
|
|
->fetch();
|
|
|
|
if ($stockInRow['id_variation'] > 0) {
|
|
$ean = '201'.sprintf('%09d', $stockInRow['id_variation']);
|
|
} else {
|
|
$ean = '200'.sprintf('%09d', $stockInRow['id_product']);
|
|
}
|
|
|
|
$ean = $this->ean13_check_digit($ean);
|
|
|
|
sqlQueryBuilder()->update(empty($stockInRow['id_variation']) ? 'products' : 'products_variations')
|
|
->directValues(['ean' => $ean])
|
|
->where(Operator::equals(['id' => empty($stockInRow['id_variation']) ? $stockInRow['id_product'] : $stockInRow['id_variation']]))
|
|
->execute();
|
|
|
|
return [
|
|
'result' => true,
|
|
'msg' => 'Přidáno',
|
|
'ean' => $ean,
|
|
];
|
|
}
|
|
|
|
protected function ean13_check_digit($digits)
|
|
{
|
|
$digits = (string) $digits;
|
|
|
|
return $digits.EANValidator::getEAN13checkDigit($digits);
|
|
}
|
|
|
|
protected function isExternalStore(int $idStore): bool
|
|
{
|
|
return $this->storesInStore->getStores()[$idStore]['type'] == StoresInStore::TYPE_EXTERNAL_STORE;
|
|
}
|
|
}
|