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,19 @@
<?php
$txt_str['productsSerialNumbers'] = [
'requireSerialNumber' => 'Požadovat sériové číslo',
'searchProduct' => 'Produkt',
'flapMain' => 'Sériové číslo',
'searchNameCode' => 'Název / Kód produktu',
'filterByProduct' => 'Podle produktu',
'filterBasic' => 'Základní vyhledávání',
'searchVariation' => 'Varianty',
'searchBtn' => 'Hledat',
'delete' => 'Vymazat',
'search' => 'Vyhledávání',
'serialNumber' => 'Sériové číslo',
'searchOrder' => 'Objednávka',
'navigation' => 'Sériové čísla',
'activityEdited' => 'Upravena doprava',
'titleEdit' => 'Upravit sériové číslo',
];

View File

@@ -0,0 +1,18 @@
<?php
$txt_str['productsSerialNumbers'] = [
'requireSerialNumber' => 'Require serial number',
'searchProduct' => 'Search product',
'flapMain' => 'Serial number',
'searchNameCode' => 'Name / code',
'filterByProduct' => 'By product',
'filterBasic' => 'Basic search',
'searchVariation' => 'Variations',
'searchBtn' => 'Search',
'delete' => 'Delete',
'search' => 'Search',
'serialNumber' => 'Serial number',
'searchOrder' => 'Order',
'navigation' => 'Serial numbers',
'titleEdit' => 'Edit serial number',
];

View File

@@ -0,0 +1,103 @@
<?php
namespace KupShop\ProductsSerialNumbersBundle\Admin\lists;
use KupShop\AdminBundle\AdminList\BaseList;
use KupShop\AdminBundle\Query\Invert;
use KupShop\CatalogBundle\Query\Search;
use KupShop\DevelopmentBundle\Query\QueryBuilder;
use KupShop\KupShopBundle\Util\HtmlBuilder\HTML;
use Query\Operator;
class ProductsSerialNumbersList extends BaseList
{
protected $tableDef = [
'id' => 'psn_id',
'fields' => [
'ID' => ['field' => 'psn_id', 'size' => 0.3],
'Sériové číslo' => ['field' => 'psn_serial_number', 'size' => 0.8],
'Tisk' => ['render' => 'renderPrint', 'size' => 0.3],
'Produkt' => ['field' => 'p_title', 'render' => 'renderName', 'size' => 2, 'type' => 'product', 'type_id' => 'p_id'],
'Dodavatel' => ['field' => 'sup_name', 'size' => 1, 'type' => 'suppliers', 'type_id' => 'sup_id'],
'Naskladnění' => ['field' => 'psn_id_stock_in', 'size' => 0.5, 'type' => 'stockIn', 'type_id' => 'psn_id_stock_in'],
'Objednávka' => ['field' => 'o_order_no', 'size' => 0.5, 'type' => 'order', 'type_id' => 'o_id'],
],
];
public function renderName($values, $column)
{
$name = [$values['p_title'], $values['pv_title']];
return join(' - ', array_filter($name));
}
public function getQuery()
{
/** @var QueryBuilder $qb */
$qb = sqlQueryBuilder()->select(
'psn.id psn_id',
'psn.serial_number psn_serial_number',
'psn.id_stock_in psn_id_stock_in',
'p.title p_title',
'p.id p_id',
'pv.title pv_title',
'pv.id pv_id',
'oi.id si_id',
'o.id o_id',
'o.order_no o_order_no',
'sup.name sup_name',
'sup.id sup_id',
)->from('products_serial_numbers', 'psn')
->innerJoin('psn', 'products', 'p', 'p.id = psn.id_product')
->leftJoin('psn', 'products_variations', 'pv', 'pv.id = psn.id_variation')
->leftJoin('psn', 'order_items', 'oi', 'oi.id = psn.id_order_item')
->leftJoin('oi', 'orders', 'o', 'o.id = oi.id_order')
->leftJoin('psn', 'stock_in', 'si', 'si.id = psn.id_stock_in')
->leftJoin('si', 'suppliers', 'sup', 'si.id_supplier = sup.id');
if ($serialNumber = getVal('serialNumber')) {
$qb->andWhere(
Invert::checkInvert(\Query\Operator::equals(['psn.serial_number' => $serialNumber]), getVal('serialNumber_invert'))
);
}
if ($orderId = getVal('idOrder')) {
$searchFields = [
['field' => 'o.id', 'match' => 'both', 'order' => '1'],
['field' => 'o.order_no', 'match' => 'both', 'order' => '1'],
];
$qb->andWhere(Invert::checkInvert(Search::searchFields($orderId, $searchFields), getVal('idOrder_invert')));
}
if ($productId = getVal('idProduct')) {
$qb->andWhere(Operator::equals(['psn.id_product' => $productId]));
if ($variationId = getVal('idVariation')) {
if (intval($variationId) > 0) {
$qb->andWhere(Operator::equals(['psn.id_variation ' => $variationId]));
}
}
}
return $qb;
}
public function renderPrint($values, $column)
{
$href = 'launch.php?s=printCenter.php&type=product&template_type=serialNumber&ID='.$values['p_id'].
'&IDv='.$values['pv_id'].
'&sn='.$values['psn_serial_number'];
return HTML::create('a')
->attr('title', 'Vytisknout')
->attr('href', $href)
->tag('span')
->class('badge')
->tag('i')
->class('glyphicon glyphicon-print')
->end()
->end();
}
}
$main_class = ProductsSerialNumbersList::class;

View File

@@ -0,0 +1,14 @@
<?php
namespace KupShop\ProductsSerialNumbersBundle\Admin;
class productsSerialNumbers extends \Window
{
protected $template = 'window/productsSerialNumbers.tpl';
protected $tableName = 'products_serial_numbers';
protected $nameField = 'serial_number';
}
return productsSerialNumbers::class;

View File

@@ -0,0 +1,64 @@
{extends "[shared]/menu.tpl"}
{block name="menu-items" }
<li class="nav-header"><i class="glyphicon glyphicon-tags"></i><span>{translate_type type=$type}</span></li>
<li class="nav-header smaller"><i class="glyphicon glyphicon-search"></i><span>{'search'|translate}</span></li>
<li class="with_caret "><a href="#" class="opener"><span>{'filterBasic'|translate}</span></a></li>
<li class="pill-content">
<ul class="nav-sub nav-pills">
<form id='search' target="mainFrame" method="get" action="launch.php" class="form-inline">
<input type="hidden" name="type" value="productsSerialNumbers"/><input type="hidden" name="s" value="list.php">
<div class="form-group">
<div class="input-group invert">
<input type="text" class="form-control input-sm" name="serialNumber" maxlength="20" value=""
placeholder="{'serialNumber'|translate}"/>
{inversion field="serialNumber"}
</div>
</div>
<div class="form-group">
<div class="input-group invert">
<input type="text" class="form-control input-sm" name="idOrder" maxlength="20" value=""
placeholder="{'searchOrder'|translate}"/>
{inversion field="idOrder"}
</div>
</div>
<div class="form-group">
<input type="reset" value="{'delete'|translate}" class="btn btn-danger btn-sm"/>
<input type="submit" value="{'searchBtn'|translate}" class="btn btn-primary btn-sm"/>
</div>
</form>
</ul>
</li>
<li class="with_caret"><a href="#" class="opener"><span>{'filterByProduct'|translate}</span></a></li>
<li class="pill-content">
<ul class="nav-sub nav-pills">
<form id='search' target="mainFrame" method="get" action="launch.php" class="form-inline">
<input type="hidden" name="type" value="{$type}"/><input type="hidden" name="s" value="list.php">
<div class="form-group">
<input type="text" class="form-control input-sm" name="idProduct" maxlength="100" value="" onKeyPress="checkInputData('int')"
placeholder="{'searchNameCode'|translate}"/>
</div>
<div class="form-group">
<select name="idVariation" class="input-sm form-control"></select>
<script type="text/javascript">
$(function () {
initAutocompleteVariation('[name=idProduct]', '[name=idVariation]');
});
</script>
</div>
<div class="form-group">
<input type="reset" id="resetBtn" value="{'delete'|translate}" class="btn btn-danger btn-sm"/>
<input type="submit" value="{'searchBtn'|translate}" class="btn btn-primary btn-sm"/>
</div>
</form>
</ul>
</li>
{/block}

View File

@@ -0,0 +1,111 @@
<style type="text/css" media="all">
@media print {
@page {
margin: 0 !important;
padding: 0;
}
.stitek {
float: none !important;
border: none !important;
}
}
body {
margin: 0;
padding: 0;
}
.stitek {
width: 92mm;
height: 62mm;
float: left;
text-align: center;
box-sizing: border-box;
page-break-after: always;
border: dimgrey dashed 1px;
overflow: hidden;
position: relative;
padding: 2mm;
background-color: white;
}
.stitek > div {
display: table-cell;
}
.stitek > hr {
border-top: 1px solid black;
position: absolute;
top: 8mm;
width: 85mm;
left: 3mm;
}
.barcode {
position: absolute;
right: 0;
left: 0;
bottom: 10mm;
font-size: 16px;
line-height: 16px;
}
.barcode>svg{
max-width:85%;
}
.title {
font-size: 13px;
overflow: hidden;
text-align: left;
height: 25mm;
width: 85mm;
position: absolute;
top: 17mm;
left: 3mm;
}
.product {
top: 7mm;
height: 10mm;
font-weight: bold;
}
.variation {
top: 18mm;
height: 8mm;
}
.title table {
width: 100%;
}
</style>
{get_contexts language=1 assign='context'}
{$languageContext = $context.language}
{$languages = $languageContext->getSupported()}
{foreach $products as $key => $product}
{for $repeat = 1 to $product.pieces}
{block stitek}
<div class="stitek">
{block descr}
<div class="title product">{$product.product_title}</div>
<div class="title variation">{$product.variation_title}</div>
{/block}
{block barcode}
<div class="barcode">
{if !empty($smarty.request.sn)}
{insert_barcode type="C128" code=$smarty.request.sn height=45 width=2}
<br>
Sériové číslo: {$smarty.request.sn}
{/if}
</div>
{/block}
</div>
{/block}
{/for}
{/foreach}

View File

@@ -0,0 +1,47 @@
{extends "[shared]/window.tpl"}
{block tabs}
{windowTab id='flapMain'}
{/block}
{block tabsContent}
<div id="flapMain" class="tab-pane fade active in boxFlex">
<div class="form-group">
<label for="serial_number" class="col-md-2 control-label">
{'serialNumber'|translate}
</label>
<div class="col-md-5">
<input type="text" class="form-control" id="serial_number" maxlength="100" name="data[serial_number]" value="{$body.data.serial_number}"/>
</div>
</div>
{$data = json_decode($body.data.data, true)}
{if $data.orders}
<div class="form-group">
<label for="serial_number" class="col-md-2 control-label">
{'history'|translate:'Reclamations'}
</label>
<div class="col-md-5">
<table class="table table-striped">
<thead>
<tr>
<td>{'id_order'|translate:'Reclamations'}</td>
<td>{'action'|translate:'Returns'}</td>
</tr>
</thead>
<tbody>
{foreach $data.orders as $order}
<tr>
<td><a href="javascript:nw('order', '{$order.id_order}');">{$order.id_order}</a></td>
<td>{$order.action}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
</div>
{/if}
</div>
{/block}

View File

@@ -0,0 +1,32 @@
<?php
namespace KupShop\ProductsSerialNumbersBundle\AdminRegister;
use KupShop\AdminBundle\AdminRegister\AdminRegister;
use KupShop\AdminBundle\AdminRegister\IAdminRegisterDynamic;
use KupShop\AdminBundle\AdminRegister\IAdminRegisterStatic;
class ProductsSerialNumbersAdminRegister extends AdminRegister implements IAdminRegisterDynamic, IAdminRegisterStatic
{
public function getDynamicMenu(): array
{
return [
static::createMenuItem(
'stockMenu',
[
'name' => 'ProductsSerialNumbers',
'title' => translate('navigation', 'productsSerialNumbers'),
'left' => 's=menu.php&type=productsSerialNumbers',
'right' => 's=list.php&type=productsSerialNumbers',
]
),
];
}
public static function getPermissions(): array
{
return [
static::createPermissions('ProductsSerialNumbers', [\Modules::PRODUCTS_SERIAL_NUMBERS], ['PSERNUM']),
];
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace KupShop\ProductsSerialNumbersBundle\EventListener;
use KupShop\OrderingBundle\Event\OrderEvent;
use KupShop\ProductsSerialNumbersBundle\Util\ProductsSerialNumbersUtil;
use Query\Operator;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class OrderEventListener implements EventSubscriberInterface
{
/**
* @var ProductsSerialNumbersUtil
*/
private $productsSerialNumbersUtil;
public function __construct(ProductsSerialNumbersUtil $productsSerialNumbersUtil)
{
$this->productsSerialNumbersUtil = $productsSerialNumbersUtil;
}
public static function getSubscribedEvents()
{
return [
OrderEvent::ORDER_STORNO => [
['stornoProductsSerialNumbers', 200],
],
];
}
public function stornoProductsSerialNumbers(OrderEvent $event)
{
$order = $event->getOrder();
$serialNumbers = sqlQueryBuilder()
->select('psn.*, oi.id_order')
->from('products_serial_numbers', 'psn')->join('psn', 'order_items', 'oi', 'psn.id_order_item = oi.id')
->where(Operator::equals(['oi.id_order' => $order->id]))
->execute()->fetchAll();
$this->productsSerialNumbersUtil->stornoProductsSerialNumbers($serialNumbers, 'storno');
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace KupShop\ProductsSerialNumbersBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ProductsSerialNumbersBundle extends Bundle
{
}

View File

@@ -0,0 +1,7 @@
services:
_defaults:
autowire: true
autoconfigure: true
KupShop\ProductsSerialNumbersBundle\:
resource: ../../{AdminRegister,EventListener,Util}

View File

@@ -0,0 +1,72 @@
<?php
namespace KupShop\ProductsSerialNumbersBundle\Resources\upgrade;
class ProductsSerialNumbersUpgrade extends \UpgradeNew
{
public function check_productsSerialNumber()
{
return $this->checkColumnExists('products', 'serial_number_require');
}
/** Add field 'serial_number_require' to products */
public function upgrade_productsSerialNumber()
{
sqlQuery("alter table products add serial_number_require enum('Y', 'N') default 'N' null;");
$this->upgradeOK();
}
public function check_productsSerialNumbersTable()
{
return $this->checkTableExists('products_serial_numbers');
}
/** Create 'products_serial_numbers' table */
public function upgrade_productsSerialNumbersTable()
{
sqlQuery('create table products_serial_numbers
(
id int auto_increment,
id_product int(11) not null,
id_variation int(11) null,
serial_number varchar(100) not null,
id_order_item int(10) unsigned null,
id_stock_in int(11) null,
constraint products_serial_numbers_pk
primary key (id),
constraint products_serial_numbers_pk_2
unique (id_product, serial_number),
constraint products_serial_numbers_order_items_id_fk
foreign key (id_order_item) references order_items (id)
on update cascade on delete set null,
constraint products_serial_numbers_products_id_fk
foreign key (id_product) references products (id)
on update cascade on delete cascade,
constraint products_serial_numbers_products_variations_id_fk
foreign key (id_variation) references products_variations (id)
on update cascade on delete set null,
constraint products_serial_numbers_stock_in_id_fk
foreign key (id_stock_in) references stock_in (id)
on update cascade on delete set null
);
');
$this->upgradeOK();
}
public function check_CustomData()
{
return $this->checkColumnExists('products_serial_numbers', 'data');
}
/** Add custom data to products_serial_numbers */
public function upgrade_CustomData()
{
sqlQuery('ALTER TABLE products_serial_numbers ADD COLUMN data TEXT NULL');
$this->upgradeOK();
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace KupShop\ProductsSerialNumbersBundle\Util\PrintCenter;
use KupShop\AdminBundle\Util\PrintCenter\PrintLabelsBase;
class SerialNumberLabel extends PrintLabelsBase
{
protected $template = 'printCenter/serialNumberLabel.tpl';
protected $label = 'Sériové číslo';
}

View File

@@ -0,0 +1,24 @@
<?php
namespace KupShop\ProductsSerialNumbersBundle\Util;
use Query\Operator;
class ProductsSerialNumbersUtil
{
public function stornoProductsSerialNumbers($serialNumbers = [], $action = 'storno')
{
foreach ($serialNumbers as $serialNumber) {
$data = json_decode($serialNumber['data'] ?? '', true);
$data['orders'][] = [
'id_order' => $serialNumber['id_order'],
'id_order_item' => $serialNumber['id_order_item'],
'action' => $action,
];
sqlQueryBuilder()->update('products_serial_numbers')
->directValues(['id_order_item' => null, 'data' => json_encode($data)])
->where(Operator::equals(['id' => $serialNumber['id']]))
->execute();
}
}
}