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,135 @@
<?php
namespace Export;
/**
* ExportData is the base class for exporters to specific file formats. See other
* classes below.
*
* php-export-data by Eli Dickinson, http://github.com/elidickinson/php-export-data
*/
abstract class ExportData
{
protected $exportTo; // Set in constructor to one of 'browser', 'file', 'string'
protected $stringData; // stringData so far, used if export string mode
protected $tempFile; // handle to temp file (for export file mode)
protected $tempFilename; // temp file name and path (for export file mode)
public $filename; // file mode: the output file name; browser mode: file name for download; string mode: not used
protected $encoding;
public function __construct($exportTo = 'browser', $filename = 'exportdata')
{
if (!in_array($exportTo, ['browser', 'file', 'string'])) {
throw new Exception("{$exportTo} is not a valid ExportData export type");
}
$this->exportTo = $exportTo;
$this->filename = $filename;
}
public function initialize()
{
global $cfg;
switch ($this->exportTo) {
case 'browser':
$this->sendHttpHeaders();
break;
case 'string':
$this->stringData = '';
break;
case 'file':
$this->tempFilename = tempnam($cfg['Path']['data'], 'exportdata');
$this->tempFile = fopen($this->tempFilename, 'w');
break;
}
$this->write($this->generateHeader());
}
public function addRow($row)
{
$this->write($this->generateRow($row));
}
public function loadOrdersData($order_ids)
{
foreach ($order_ids as $id) {
$this->addRow($this->getOrder($id));
}
}
public function finalize()
{
$this->write($this->generateFooter());
switch ($this->exportTo) {
case 'browser':
flush();
break;
case 'string':
// do nothing
break;
case 'file':
// close temp file and move it to correct location
fclose($this->tempFile);
rename($this->tempFilename, $this->filename);
break;
}
}
public function getString()
{
return $this->stringData;
}
abstract public function sendHttpHeaders();
protected function write($data)
{
if (!empty($data)) {
switch ($this->exportTo) {
case 'browser':
echo $data;
break;
case 'string':
$this->stringData .= $data;
break;
case 'file':
fwrite($this->tempFile, $data);
break;
}
}
}
protected function generateHeader()
{
// can be overridden by subclass to return any data that goes at the top of the exported file
}
protected function generateFooter()
{
// can be overridden by subclass to return any data that goes at the bottom of the exported file
}
// In subclasses generateRow will take $row array and return string of it formatted for export type
abstract protected function generateRow($row);
protected function getOrder($id)
{
$order = new \Order();
$order->createFromDB($id);
$order->fetchItems();
return $order;
}
public function setCoding($encoding)
{
$this->encoding = $encoding;
}
public function encodeData($string)
{
return iconv('utf-8', $this->encoding.'//TRANSLIT', $string);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Export;
/**
* ExportDataCSV - Exports to CSV (comma separated value) format.
*/
class ExportDataCSV extends ExportData
{
public function generateRow($row)
{
foreach ($row as $key => $value) {
// Escape inner quotes and wrap all contents in new quotes.
// Note that we are using \" to escape double quote not ""
$row[$key] = '"'.str_replace('"', '\"', $value).'"';
}
return implode(',', $row)."\n";
}
public function sendHttpHeaders()
{
header('Content-type: text/csv');
header('Content-Disposition: attachment; filename='.basename($this->filename));
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace Export;
use XBase\Record;
use XBase\WritableTable;
/**
* Own class for DBF export.
*/
class ExportDataDBF extends ExportData
{
/**
* @var WritableTable
*/
private $table;
public function initialize()
{
global $cfg;
$this->tempFilename = $cfg['Path']['data'].'export_data.dbf';
$this->table = WritableTable::create($this->tempFilename, $this->columnDefs(), $this->tempFilename);
}
public function finalize()
{
$this->sendHttpHeaders();
$this->table->close();
readfile($this->tempFilename);
exit;
}
/**
* @param $order \Order
*/
public function generateRow($order)
{
$row_pointer = $this->table->appendRecord();
$this->appendToRow($row_pointer, $order);
$this->table->writeRecord();
}
public function sendHttpHeaders()
{
header('Content-Type: application/x-dbase; charset='.$this->encoding);
header('Content-Disposition: attachment; filename="'.$this->filename.'"');
header('Expires: 0');
header('Pragma: no-cache');
}
protected function columnDefs()
{
/* FIXME: dodělat zbytek a přesměrovat DBF z export_sracka sem */
return [
['DATUM_VYST', Record::DBFFIELD_TYPE_DATE], // datum vystavení
// ['DATUM_SPL', DBFFIELD_TYPE_DATE], //prázdné
// ['DOKLAD_1', DBFFIELD_TYPE_CHAR, 12], //aby tam bylo fčíslo objednávky např. f11521
// ['TYP_ZAP', DBFFIELD_TYPE_CHAR, 1], //hodnota P
// ['ZNAK_UCT', DBFFIELD_TYPE_CHAR, 5], //prázdné
// ['SYMBOLY', DBFFIELD_TYPE_CHAR, 20], //včísloobjednávky např. v11521
// ['PAR_ZNAK', DBFFIELD_TYPE_CHAR, 12], //to samé jako DOKLAD_1 např. f11521
// ['BANK_UCET', DBFFIELD_TYPE_CHAR, 44], //prázdné
// ['SPEC_SYMB', DBFFIELD_TYPE_CHAR, 10], //prázdné
// ['POPIS_TEXT', DBFFIELD_TYPE_CHAR, 30], //libovolný text - např. prodej eshop-objednávka 11521
// ['DRUH_UCT', DBFFIELD_TYPE_CHAR, 5], //hodnota PZ
// ['MENA', DBFFIELD_TYPE_CHAR, 3], //buď Kč nebo EUR
// ['CELKEM_KC', DBFFIELD_TYPE_NUMERIC, 8, 2], //celková částka dokladu včetně DPH v Kč
// ['CELKEMCIZI', DBFFIELD_TYPE_NUMERIC, 8, 2], //celková částka dokladu v EUR - prodej na Slovensko?
// ['KURZ', DBFFIELD_TYPE_NUMERIC, 5, 3], //kurz pro přepočet
// ['DATUM_DPH', DBFFIELD_TYPE_DATE], //datum DPH = datum vystavení
// ['TYP_DPH', DBFFIELD_TYPE_CHAR, 5], //hodnota U
// ['ZAKL_DPH_Z', DBFFIELD_TYPE_NUMERIC, 8, 2], //Částka bez daně v základní sazbě
// ['DPH_Z', DBFFIELD_TYPE_NUMERIC, 8, 2], //Daň s azba 21 %
// ['ZAKL_DPH_S', DBFFIELD_TYPE_NUMERIC, 8, 2], //Částka bez daně ve snížené sazbě
// ['DPH_S', DBFFIELD_TYPE_NUMERIC, 8, 2], //Daň s azba 15 %
// ['TYPMIMODPH', DBFFIELD_TYPE_CHAR, 1], //prázdné
// ['CASTKAMIMO', DBFFIELD_TYPE_NUMERIC, 8, 2], //prázdné
// ['STREDISKO', DBFFIELD_TYPE_CHAR, 5], //PRÁZDNÉ
// ['vykon', DBFFIELD_TYPE_CHAR, 5], //prázdné
// ['zakazka', DBFFIELD_TYPE_CHAR, 5], //prázdné
// ['POZNAMKA', DBFFIELD_TYPE_CHAR, 150], //sem naimportovat jméno a příjmění a město kupujícího JAN NOVAK TURNOV
// ['FIRMA', DBFFIELD_TYPE_CHAR, 30], // Firma
// ['JMENO', DBFFIELD_TYPE_CHAR, 30], //Jmeno
// ['PRIJMENI', DBFFIELD_TYPE_CHAR, 30], //Prijmeni
// ['ICO', DBFFIELD_TYPE_CHAR, 15], //ICO
// ['DIC', DBFFIELD_TYPE_CHAR, 20], //DIC
//
// ['ZAKAZNIK', DBFFIELD_TYPE_CHAR, 80], //Prijmeni nebo firma
// ['ULICE', DBFFIELD_TYPE_CHAR, 50], //Adresa
// ['MESTO', DBFFIELD_TYPE_CHAR, 30], //Adresa
// ['PSC', DBFFIELD_TYPE_CHAR, 10], //Adresa
// ['ZEME', DBFFIELD_TYPE_CHAR, 30], //Adresa
//
// ['STAV', DBFFIELD_TYPE_CHAR, 10], // STORNO/PRODEJ
// ['DATUM_SPLAT', DBFFIELD_TYPE_DATE], //datum splatnosti
];
}
/**
* @param $row_pointer Record
* @param $order \Order
*/
protected function appendToRow($row_pointer, $order)
{
/* FIXME: dodělat zbytek a přesměrovat DBF z export_sracka sem */
if ($order->date_handle) {
$row_pointer->setObjectByName('DATUM_VYST', $order->date_handle->format('Ymd')); // datum vystavení
}
// $r->setObjectByName("DATUM_SPL", $row['DBFFIELD_TYPE_DATE']); //prázdné
// $row_pointer->setObjectByName('DOKLAD_1', $order['order_no']); //aby tam bylo fčíslo objednávky např. f11521
// $row_pointer->setObjectByName('TYP_ZAP', 'P'); //hodnota P
// $row_pointer->setObjectByName('ZNAK_UCT', ''); //prázdné
// $row_pointer->setObjectByName('SYMBOLY', $order['id']); //včísloobjednávky např. v11521
// $row_pointer->setObjectByName('PAR_ZNAK', $order['order_no']); //to samé jako DOKLAD_1 např. f11521
// $row_pointer->setObjectByName('BANK_UCET', ''); //prázdné
// $row_pointer->setObjectByName('SPEC_SYMB', ''); //prázdné
// $row_pointer->setObjectByName('POPIS_TEXT', $encode('Objednávka: ').$order['id']); //libovolný text - např. prodej eshop-objednávka 11521
// $row_pointer->setObjectByName('DRUH_UCT', 'PZ'); //hodnota PZ
// $row_pointer->setObjectByName('MENA', $encode('Kč')); //buď Kč nebo EUR
// $row_pointer->setObjectByName('CELKEM_KC', $total_price); //celková částka dokladu včetně DPH v Kč
// $row_pointer->setObjectByName('CELKEMCIZI', 0); //celková částka dokladu v EUR - prodej na Slovensko?
// $row_pointer->setObjectByName('KURZ', 0); //kurz pro přepočet
// $row_pointer->setObjectByName('DATUM_DPH', strtotime($order['date_handle'])); //datum DPH = datum vystavení
// $row_pointer->setObjectByName('TYP_DPH', 'U'); //hodnota U
// $row_pointer->setObjectByName('ZAKL_DPH_Z', $taxes['21']); //Částka bez daně v základní sazbě
// $row_pointer->setObjectByName('DPH_Z', $taxes['21']->mul(toDecimal(0.21))); //Daň sazba 21 %
// $row_pointer->setObjectByName('ZAKL_DPH_S', $taxes['15']); //Částka bez daně ve snížené sazbě
// $row_pointer->setObjectByName('DPH_S', $taxes['15']->mul(toDecimal(0.15))); //Částka bez daně ve snížené sazbě
// $row_pointer->setObjectByName('TYPMIMODPH', ''); //prázdné
// $row_pointer->setObjectByName('CASTKAMIMO', $taxes['0']); //prázdné
// $row_pointer->setObjectByName('STREDISKO', ''); //PRÁZDNÉ
// $row_pointer->setObjectByName('vykon', ''); //prázdné
// $row_pointer->setObjectByName('zakazka', ''); //prázdné
// $row_pointer->setObjectByName('POZNAMKA', "{$order['invoice_name']} {$order['invoice_surname']}, {$order['invoice_city']}"); //sem naimportovat jméno a příjmění a město kupujícího JAN NOVAK TURNOV
// $row_pointer->setObjectByName('FIRMA', $order['invoice_firm']); // Firma
// $row_pointer->setObjectByName('JMENO', $order['invoice_name']); //Jmeno
// $row_pointer->setObjectByName('PRIJMENI', $order['invoice_surname']); //Prijmeni
//
// $row_pointer->setObjectByName('ICO', $order['invoice_ico']); //ICO
// $row_pointer->setObjectByName('DIC', $order['invoice_dic']); //DIC
//
// $row_pointer->setObjectByName('ZAKAZNIK', $order['invoice_firm'] ? $order['invoice_firm'] : "{$order['invoice_name']} {$order['invoice_surname']}"); //Prijmeni nebo firma
// $row_pointer->setObjectByName('ULICE', $order['invoice_street']);
// $row_pointer->setObjectByName('MESTO', $order['invoice_city']);
// $row_pointer->setObjectByName('PSC', $order['invoice_zip']);
// $row_pointer->setObjectByName('ZEME', $order['invoice_country']);
//
// $row_pointer->setObjectByName('STAV', $order['status_storno'] ? 'STORNO' : 'PRODEJ'); // STORNO/PRODEJ
// $row_pointer->setObjectByName('DATUM_SPLAT', strtotime($order['date_due']));
}
}

View File

@@ -0,0 +1,125 @@
<?php
namespace Export;
use XBase\Record;
/**
* Own class for DBF export.
*/
class ExportDataDBFUcto extends ExportDataDBF
{
protected function columnDefs()
{
return [
['Veta', Record::DBFFIELD_TYPE_NUMERIC, 6, 0], // datum vystavení
['DatumVyst', Record::DBFFIELD_TYPE_DATE], // datum vystavení
['DatumSpl', Record::DBFFIELD_TYPE_DATE], // datum splatnosti
['Datum', Record::DBFFIELD_TYPE_DATE], // datum zaplacení - většinou prázdné
['Doklad', Record::DBFFIELD_TYPE_CHAR, 30], // Doklad
['DokladKH', Record::DBFFIELD_TYPE_CHAR, 20],
['TypD', Record::DBFFIELD_TYPE_CHAR, 3],
['Text', Record::DBFFIELD_TYPE_CHAR, 30], // text
['Druh', Record::DBFFIELD_TYPE_CHAR, 3], // klic do ciselniku druhu
['Firma', Record::DBFFIELD_TYPE_CHAR, 5], // cislo firmy v adresari ucta
['Ico', Record::DBFFIELD_TYPE_CHAR, 10], // ico firmy
['Vykon', Record::DBFFIELD_TYPE_CHAR, 5], // klic do ciselniku vykonu
['Plat', Record::DBFFIELD_TYPE_CHAR, 1], // platba: B-banka, H-hotovos
['Celkem', Record::DBFFIELD_TYPE_FLOATING, 11, 2], // celkova castka
['DatumDPH', Record::DBFFIELD_TYPE_DATE], // datum zd. pl
['DatumKH', Record::DBFFIELD_TYPE_DATE],
['BezDaneZ', Record::DBFFIELD_TYPE_FLOATING, 11, 2], // dph
['DphZ', Record::DBFFIELD_TYPE_FLOATING, 11, 2], // dph
['BezDaneS', Record::DBFFIELD_TYPE_FLOATING, 11, 2], // dph
['DphS', Record::DBFFIELD_TYPE_FLOATING, 11, 2], // dph
['BezDaneS2', Record::DBFFIELD_TYPE_FLOATING, 11, 2], // dph
['DphS2', Record::DBFFIELD_TYPE_FLOATING, 11, 2], // dph
['BezDaneO', Record::DBFFIELD_TYPE_FLOATING, 11, 2], // dph
['Zaloha', Record::DBFFIELD_TYPE_FLOATING, 11, 2], // dph
['Prikaz', Record::DBFFIELD_TYPE_LOGICAL], // nevyplnovat, vyber pro prikaz k uhrade
['DatumPrik', Record::DBFFIELD_TYPE_DATE], // nevyplnovat, datum pro prikaz k uhrade
['Pozn', Record::DBFFIELD_TYPE_MEMO], // poznámka (memo)
['Ozn', Record::DBFFIELD_TYPE_LOGICAL], // označené věty
['Měna2', Record::DBFFIELD_TYPE_CHAR, 3], // Měna2
['Kč2', Record::DBFFIELD_TYPE_FLOATING, 11, 2], // Kč2
['Naz0', Record::DBFFIELD_TYPE_CHAR, 30], // označené věty
['Dic0', Record::DBFFIELD_TYPE_CHAR, 14], // označené věty
];
}
/**
* @param $row_pointer Record
* @param $order \Order
*/
protected function appendToRow($row_pointer, $order)
{
// $row_pointer->setObjectByName('Veta', '');
$row_pointer->setObjectByName('DatumVyst', $order->date_handle ? strtotime($order->date_handle->format('Ymd')) : '');
// $row_pointer->setObjectByName('DatumPrik', '');
/* TODO: dořešit due_days, nejlíp na order */
$row_pointer->setObjectByName('DatumSpl', ($order->date_handle) ? strtotime($order->date_handle->modify('+14 days')->format('Ymd')) : '');
// $row_pointer->setObjectByName('Datum', '');
$row_pointer->setObjectByName('Doklad', 'f/'.$order->order_no);
$row_pointer->setObjectByName('DokladKH', $order->order_no);
$row_pointer->setObjectByName('TypD', ' ');
$row_pointer->setObjectByName('Text', $this->encodeData($order->invoice_firm ? $order->invoice_firm : $order->invoice_name.' '.$order->invoice_surname));
$row_pointer->setObjectByName('Druh', 'PZ ');
$row_pointer->setObjectByName('Firma', ' ');
$row_pointer->setObjectByName('Ico', strtoupper($order->invoice_ico));
$row_pointer->setObjectByName('Vykon', ' ');
$pay_type = $order->getDeliveryType()->getPayment();
if ($pay_type && $pay_type->getPayMethod() == \Payment::METHOD_CASH) {
$pay_type = 'H';
} else {
$pay_type = 'B';
}
$row_pointer->setObjectByName('Plat', $this->encodeData($pay_type));
$row_pointer->setObjectByName('Celkem', !$order->status_storno ? $order->total_price->printFloatValue(2) : 0);
/* TODO: datum zd. plneni */
$row_pointer->setObjectByName('DatumDPH', $order->date_handle ? strtotime($order->date_handle->format('Ymd')) : '');
// $row_pointer->setObjectByName('DatumKH', '');
if (!empty($order->vats[21]) && !$order->status_storno) {
$row_pointer->setObjectByName('BezDaneZ', $order->vats[21]['total_price_without_vat']->printFloatValue(2));
$row_pointer->setObjectByName('DphZ', $order->vats[21]['tax']['value_vat']->printFloatValue(2));
} else {
$row_pointer->setObjectByName('BezDaneZ', 0);
$row_pointer->setObjectByName('DphZ', 0);
}
// if (!empty($order->vats[15])) {
// $row_pointer->setObjectByName('BezDaneS', $order->vats[15]['total_price_without_vat']->printFloatValue(2));
// $row_pointer->setObjectByName('DphS', $order->vats[15]['tax']['value_vat']->printFloatValue(2));
// } else {
// $row_pointer->setObjectByName('BezDaneS', 0);
// $row_pointer->setObjectByName('DphS', 0);
// }
// $row_pointer->setObjectByName('BezDaneS2', 0);
// $row_pointer->setObjectByName('DphS2', 0);
// $row_pointer->setObjectByName('BezDaneO', 0);
// $row_pointer->setObjectByName('Zaloha', 0);
$row_pointer->setObjectByName('Prikaz', false);
// $row_pointer->setObjectByName('DatumPrik', 0);
// $row_pointer->setObjectByName('Pozn', '');
$row_pointer->setObjectByName('Ozn', false);
$row_pointer->setObjectByName('Měna2', ' ');
// $row_pointer->setObjectByName('Kč2', $order->currency_rate);
$row_pointer->setObjectByName('Naz0', ' ');
$row_pointer->setObjectByName('Dic0', strtoupper($order->invoice_dic));
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace Export;
/**
* ExportDataExcel exports data into an XML format (spreadsheetML) that can be
* read by MS Excel 2003 and newer as well as OpenOffice.
*
* Creates a workbook with a single worksheet (title specified by
* $title).
*
* Note that using .XML is the "correct" file extension for these files, but it
* generally isn't associated with Excel. Using .XLS is tempting, but Excel 2007 will
* throw a scary warning that the extension doesn't match the file type.
*
* Based on Excel XML code from Excel_XML (http://github.com/oliverschwarz/php-excel)
* by Oliver Schwarz
*/
class ExportDataExcel extends ExportData
{
public const XmlHeader = "<?xml version=\"1.0\" encoding=\"%s\"?\>\n<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\" xmlns:x=\"urn:schemas-microsoft-com:office:excel\" xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\" xmlns:html=\"http://www.w3.org/TR/REC-html40\">";
public const XmlFooter = '</Workbook>';
public $encoding = 'UTF-8'; // encoding type to specify in file.
// Note that you're on your own for making sure your data is actually encoded to this encoding
public $title = 'Sheet1'; // title for Worksheet
public function generateHeader()
{
// workbook header
$output = stripslashes(sprintf(self::XmlHeader, $this->encoding))."\n";
// Set up styles
$output .= "<Styles>\n";
$output .= "<Style ss:ID=\"sDT\"><NumberFormat ss:Format=\"Short Date\"/></Style>\n";
$output .= "</Styles>\n";
// worksheet header
$output .= sprintf("<Worksheet ss:Name=\"%s\">\n <Table>\n", htmlentities($this->title));
return $output;
}
public function generateFooter()
{
$output = '';
// worksheet footer
$output .= " </Table>\n</Worksheet>\n";
// workbook footer
$output .= self::XmlFooter;
return $output;
}
public function generateRow($row)
{
$output = '';
$output .= " <Row>\n";
foreach ($row as $k => $v) {
$output .= $this->generateCell($v);
}
$output .= " </Row>\n";
return $output;
}
private function generateCell($item)
{
$output = '';
$style = '';
// Tell Excel to treat as a number. Note that Excel only stores roughly 15 digits, so keep
// as text if number is longer than that.
if (preg_match("/^-?\d+(?:[.,]\d+)?$/", $item) && (strlen($item) < 15)) {
$type = 'Number';
}
// Sniff for valid dates; should look something like 2010-07-14 or 7/14/2010 etc. Can
// also have an optional time after the date.
//
// Note we want to be very strict in what we consider a date. There is the possibility
// of really screwing up the data if we try to reformat a string that was not actually
// intended to represent a date.
elseif (preg_match("/^(\d{1,2}|\d{4})[\/\-]\d{1,2}[\/\-](\d{1,2}|\d{4})([^\d].+)?$/", $item)
&& ($timestamp = strtotime($item))
&& ($timestamp > 0)
&& ($timestamp < strtotime('+500 years'))) {
$type = 'DateTime';
$item = strftime('%Y-%m-%dT%H:%M:%S', $timestamp);
$style = 'sDT'; // defined in header; tells excel to format date for display
} else {
$type = 'String';
}
$item = str_replace('&#039;', '&apos;', htmlspecialchars($item, ENT_QUOTES));
$output .= ' ';
$output .= $style ? "<Cell ss:StyleID=\"{$style}\">" : '<Cell>';
$output .= sprintf('<Data ss:Type="%s">%s</Data>', $type, $item);
$output .= "</Cell>\n";
return $output;
}
public function sendHttpHeaders()
{
header('Content-Type: application/vnd.ms-excel; charset='.$this->encoding);
header('Content-Disposition: inline; filename="'.basename($this->filename).'"');
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Export;
/**
* ExportDataTSV - Exports to TSV (tab separated value) format.
*/
class ExportDataTSV extends ExportData
{
public function generateRow($row)
{
foreach ($row as $key => $value) {
// Escape inner quotes and wrap all contents in new quotes.
// Note that we are using \" to escape double quote not ""
$row[$key] = '"'.str_replace('"', '\"', $value).'"';
}
return implode("\t", $row)."\n";
}
public function sendHttpHeaders()
{
header('Content-type: text/tab-separated-values');
header('Content-Disposition: attachment; filename='.basename($this->filename));
}
}

View File

@@ -0,0 +1,412 @@
<?php
use KupShop\AdminBundle\AdminRegister\AdminRegisterLocator;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
class AdminBarMenu
{
protected $customMenuItems = [];
protected $menu = [
[
'name' => 'administration',
'submenu' => [
[
'name' => 'leadpage',
'left' => 'blank', 'right' => 's=board.php',
],
[
'name' => 'shopStore',
'left' => 's=menu.php&type=shopStore', 'right' => 's=board.php&type=shopStore',
],
[
'name' => 'newWindow',
'script' => 'newWindow();',
],
[
'name' => 'logout',
'script' => 'logout(0)',
],
[
'name' => 'adminEdit',
'script' => "nw('adminEdit')",
],
[
'name' => 'htmlComponents',
/* 'left' => 's=menu.php&type=htmlComponents', */ 'right' => 's=board.php&type=htmlComponents',
],
[
'name' => 'chooseLanguage',
'submenu' => [
[
'name' => 'czech',
'href' => 'admin-change-language/czech',
],
[
'name' => 'english',
'href' => 'admin-change-language/english',
],
],
],
],
],
[
'name' => 'productsMenu',
'left' => 's=menu.php&type=products', 'right' => 's=list.php&type=products',
'submenu' => [
[
'name' => 'products',
'left' => 's=menu.php&type=products', 'right' => 's=list.php&type=products',
],
[
'name' => 'productsMassModification',
'left' => 'blank', 'right' => 's=list.php&type=productsMassModification',
],
[
'name' => 'parameters',
'left' => 's=menu.php&type=parameters', 'right' => 's=list.php&type=parameters',
],
[
'name' => 'productsVarLabels',
'left' => 's=menu.php&type=productsVarLabels', 'right' => 's=list.php&type=productsVarLabels',
],
[
'name' => 'sections',
'left' => 's=menu.php&type=sections', 'right' => 's=list.php&type=sections',
],
[
'name' => 'producers',
'left' => 's=menu.php&type=producers', 'right' => 's=list.php&type=producers',
],
[
'name' => 'templatesMenu',
'submenu' => [
[
'name' => 'templates',
'left' => 's=menu.php&type=templates', 'right' => 's=list.php&type=templates',
],
[
'name' => 'templatesCategories',
'left' => 's=menu.php&type=templatesCategories', 'right' => 's=list.php&type=templatesCategories',
],
],
],
[
'name' => 'reviews',
'left' => 's=menu.php&type=reviews', 'right' => 's=list.php&type=reviews&type_list=ShowNotConfirmed',
],
[
'name' => 'productsRelatedTypes',
'left' => 's=menu.php&type=productsRelatedTypes', 'right' => 's=list.php&type=productsRelatedTypes',
],
],
],
[
'name' => 'ordersMenu',
'left' => 's=menu.php&type=orders', 'right' => 's=list.php&type=orders',
'submenu' => [
[
'name' => 'orders',
'left' => 's=menu.php&type=orders', 'right' => 's=list.php&type=orders',
],
[
'name' => 'users',
'left' => 's=menu.php&type=users', 'right' => 's=list.php&type=users',
],
[
'name' => 'usersGroups',
'left' => 's=menu.php&type=usersGroups', 'right' => 's=list.php&type=usersGroups',
],
[
'name' => 'ordersMassProcess',
'left' => 's=menu.php&type=ordersMassProcess', 'right' => 's=list.php&type=ordersMassProcess',
],
[
'name' => 'old_pos',
'script' => "nw('old_pos')",
],
[
'name' => 'orderPayment',
'left' => 's=menu.php&type=orderPayment', 'right' => null,
],
],
],
[
'name' => 'stockMenu',
'submenu' => [
[
'name' => 'stockIn',
'left' => 's=menu.php&type=stockIn', 'right' => 's=list.php&type=stockIn',
],
[
'name' => 'suppliers',
'left' => 's=menu.php&type=suppliers', 'right' => 's=list.php&type=suppliers',
],
[
'name' => 'stockInMissing',
'left' => 's=menu.php&type=stockInMissing', 'right' => 's=list.php&type=stockInMissing&fromNav=1',
],
[
'name' => 'productsOfSuppliers',
'left' => 's=menu.php&type=productsOfSuppliers', 'right' => 's=list.php&type=productsOfSuppliers',
],
[
'name' => 'ordersOfSuppliers',
'left' => 's=menu.php&type=ordersOfSuppliers', 'right' => 's=list.php&type=ordersOfSuppliers',
],
[
'name' => 'inventory',
'left' => 's=menu.php&type=inventory', 'right' => 's=list.php&type=inventory',
],
[
'name' => 'productsPrices',
'left' => 's=menu.php&type=productsPrices', 'right' => 's=list.php&type=productsPrices',
],
],
],
[
'name' => 'contentMenu',
'submenu' => [
[
'name' => 'menu',
'left' => 's=menu.php&type=menu', 'right' => 's=list.php&type=menu',
],
[
'name' => 'sliders',
'left' => 's=menu.php&type=sliders', 'right' => 's=list.php&type=sliders',
],
[
'name' => 'articlesMenu',
'submenu' => [
[
'name' => 'articles',
'left' => 's=menu.php&type=articles', 'right' => 's=list.php&type=articles',
],
[
'name' => 'artsections',
'left' => 's=menu.php&type=artsections', 'right' => 's=list.php&type=artsections',
],
[
'name' => 'artauthors',
'left' => 's=menu.php&type=artauthors', 'right' => 's=list.php&type=artauthors',
],
[
'name' => 'articlesTags',
'left' => 's=menu.php&type=articlesTags', 'right' => 's=list.php&type=articlesTags',
],
],
],
[
'name' => 'sellers',
'left' => 's=menu.php&type=sellers', 'right' => 's=list.php&type=sellers',
],
[
'name' => 'photos',
'left' => 's=menu.php&type=photos', 'right' => 's=list.php&type=photos',
],
[
'name' => 'fileBrowser',
'script' => 'nw(\'kcfinder\', \'all\')',
],
/*[
'name' => 'fileBrowser',
'submenu' => [
[
'name' => 'browseImages',
'script' => 'nw(\'kcfinder\')',
],
[
'name' => 'browseFiles',
'script' => 'nw(\'kcfinder\', \'other\')',
],
],
],*/
],
],
[
'name' => 'toolsMenu',
'submenu' => [
[
'name' => 'dbbackup',
'left' => 's=menu.php&type=dbbackup', 'right' => 's=list.php&type=dbbackup',
],
[
'name' => 'stats',
'left' => 'blank', 'right' => 's=board.php&type=stats',
],
[
'name' => 'export',
'submenu' => [
[
'name' => 'export_products',
'left' => 's=menu.php&type=export', 'right' => 's=board.php&type=export_products',
],
[
'name' => 'export_selling_products',
'left' => 's=menu.php&type=export', 'right' => 's=board.php&type=export_selling_products',
],
[
'name' => 'export_orders',
'left' => 's=menu.php&type=export', 'right' => 's=board.php&type=export_orders',
],
[
'name' => 'export_users',
'left' => 's=menu.php&type=export', 'right' => 's=board.php&type=export_users',
],
],
],
[
'name' => 'import',
'submenu' => [
[
'name' => 'import-generic',
'right' => 's=import.generic.php',
],
[
'name' => 'import_automatic',
'left' => 's=menu.php&type=automatic_import', 'right' => 's=list.php&type=automatic_import',
],
[
'name' => 'import-xml_feed',
'script' => "nw('import.xml_feed')",
],
[
'name' => 'import-xml_feed_new',
'script' => "nw('import.xml_feed_new')",
],
],
],
[
'name' => 'cleaning',
'script' => "nw('cleaning')",
],
],
],
[
'name' => 'settingsMenu',
'submenu' => [
[
'name' => 'admins',
'left' => 's=menu.php&type=admins', 'right' => 's=list.php&type=admins',
],
[
'name' => 'settings',
'script' => "nw('settings')",
],
[
'name' => 'emails',
'script' => "nw('emails')",
],
[
'name' => 'delivery',
'submenu' => [
[
'name' => 'delivery_type',
'left' => 's=menu.php&type=delivery', 'right' => 's=list.php&type=delivery',
],
[
'name' => 'deliveryDelivery',
'left' => 's=menu.php&type=deliveryDelivery', 'right' => 's=list.php&type=deliveryDelivery',
],
[
'name' => 'deliveryPayment',
'left' => 's=menu.php&type=deliveryPayment', 'right' => 's=list.php&type=deliveryPayment',
],
],
],
[
'name' => 'vats',
'left' => 's=menu.php&type=vats', 'right' => 's=list.php&type=vats',
],
[
'name' => 'priceLevels',
'left' => 's=menu.php&type=pricelevels', 'right' => 's=list.php&type=pricelevels',
],
[
'name' => 'fulltext',
'script' => "nw('fulltext')",
],
],
],
];
public function getMenu(): array
{
$userRights = new UserRights();
/** @var \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher */
$dispatcher = ServiceContainer::getService('event_dispatcher');
$event = new \KupShop\KupShopBundle\Event\CreateMenuEvent($this, $userRights);
$dispatcher->dispatch($event, \KupShop\KupShopBundle\Event\CreateMenuEvent::COMPLETING_TREE);
$adminRegisterLocator = ServiceContainer::getService(AdminRegisterLocator::class);
foreach ($adminRegisterLocator->getMenu() as $menu => $items) {
foreach ($items as $item) {
$this->addItem($menu, $item);
}
}
$this->sortMenu($this->menu);
return $this->menu;
}
private function sortMenu(&$menu)
{
foreach ($menu as $pos => &$item) {
if (is_array($item) && array_key_exists('submenu', $item)) {
$this->sortMenu($item['submenu']);
}
if (is_array($item) && array_key_exists('position', $item)) {
$menuItem = [$menu[$pos]];
unset($menu[$pos]);
array_splice($menu, $item['position'], 0, $menuItem);
}
}
}
public function addItem($menuName, $item, &$menu = null, $index = 0)
{
if (!$menu) {
$menu = &$this->menu;
}
// / new
$menuNames = $this->getMenuNames($menuName);
$maxIndex = count($menuNames) - 1;
foreach ($menu as &$menuItem) {
if ($menuItem['name'] == $menuNames[$index]) {
if ($index == $maxIndex) {
$menuItem['submenu'][] = $item;
return true;
} else {
$result = $this->addItem($menuName, $item, $menuItem['submenu'], ++$index);
if ($result) {
return true;
}
}
}
}
// create root menu item if $menuItem was not found
$menu[] = $item;
return false;
}
public function getMenuNames($menuName)
{
$names = explode('/', $menuName);
return $names;
}
public function setMenu(array $menu)
{
$this->menu = $menu;
}
}

View File

@@ -0,0 +1,31 @@
<?php
trait AdminListSortable
{
public function saveList($item, $table, $columns = 'position', $extra_where = '', $id_column = 'id')
{
if ($item['direction'] == 'down') {
$item['position']++;
}
if (is_array($columns)) {
$column = reset($columns);
} else {
$column = $columns;
}
$columns = join(', ', (array) $columns);
sqlQuery("UPDATE {$table} SET {$column}={$column}+1 WHERE {$column} >= {$item['position']}{$extra_where}");
sqlQuery("UPDATE {$table} SET {$column}={$item['position']} WHERE {$id_column}={$item['id']}{$extra_where}");
$this->saveAllPositions($column, $columns, $extra_where, $table);
}
public function saveAllPositions($column, $columns, mixed $extraWhere, ?string $table = null): void
{
$table ??= $this->tableName;
sqlQuery("SELECT @i := -1; UPDATE {$table} SET {$column} = (select @i := @i + 1) WHERE 1{$extraWhere} ORDER BY {$columns}");
}
}

View File

@@ -0,0 +1,95 @@
<?php
/**
* Created by PhpStorm.
* User: hanz
* Date: 29.4.14
* Time: 14:49s.
*/
class Base
{
protected $smarty;
protected $template;
public function init_smarty()
{
$this->smarty = createSmarty(true, true);
}
public function getTemplate()
{
if (empty($this->template)) {
throw new Exception('Empty template name');
}
return $this->template;
}
public function setTemplate($name)
{
$this->template = $name;
}
public static function getClassName()
{
$className = explode('\\', get_called_class());
return end($className);
}
public function display()
{
$this->smarty->display($this->getTemplate());
}
public function handle()
{
$acn = getVal('acn');
if ($acn) {
$action = 'handle'.ucfirst($acn);
if (method_exists($this, $action)) {
call_user_func([$this, $action]);
}
}
}
public function run()
{
// Process POSTEd values
$this->handle();
// Collect template variables
$vars = $this->collectVariables();
// Init templating system
$this->init_smarty();
// Assign template variables to template
$this->assign_($vars);
// Render template
$this->display();
}
protected function collectVariables()
{
return $this->get_vars();
}
protected function get_vars()
{
return [
'view' => $this,
];
}
public function getPageHandler()
{
return getVal('s');
}
public function assign_($array)
{
$this->smarty->assign($array);
}
}

View File

@@ -0,0 +1,271 @@
<?php
class BaseAdminPhotos extends Frame
{
use DatabaseCommunication;
protected $template = 'adminPhotos.tpl';
protected $relation_table_name;
protected $photo_type;
protected $tablefield;
protected $photo_nametype;
protected $photo_admin_name;
protected $copy_from;
public function get_vars()
{
$vars = parent::get_vars();
$pageVars = getVal('body', $vars, []);
$acn = $this->getAction();
$ID = $this->getID();
$pageVars['acn'] = $acn;
$pageVars['s'] = getVal('s');
$SQL = sqlQuery("SELECT ph.id, ph.descr,ph.source, ph.image_2, MAX(php.show_in_lead) as show_in_lead, ph.date,
MAX(php.position) as position, ph.data as data, ph.date_update
FROM photos AS ph, {$this->relation_table_name} AS php
WHERE ph.id=php.id_photo AND php.{$this->tablefield}=:id
GROUP BY ph.id
ORDER BY position ASC", ['id' => $ID]); // , php.date_added ASC;
$photos = [];
foreach ($SQL as $row) {
$row['IDph'] = $row['id'];
$row['img'] = getImage($row['id'], $row['image_2'], $row['source'], $this->photo_type, $row['descr'], strtotime($row['date_update']));
$row['width'] = ($row['img']['width'] <= 200) ? $row['img']['width'] : 200;
$this->unserializeCustomData($row);
if (findModule('products_variations_photos') && $this->relation_table_name == 'photos_products_relation') {
$row['varSel'] = [];
$SQLp = sqlQuery("SELECT id_variation FROM {$this->relation_table_name} pp WHERE pp.id_photo=:id_photo AND pp.{$this->tablefield}=:ID AND pp.id_variation IS NOT NULL", ['id_photo' => $row['IDph'], 'ID' => $ID]);
foreach ($SQLp as $rowp) {
$row['varSel'][] = $rowp['id_variation'];
}
if (empty($row['varSel'])) {
$row['varSel'] = ['-1'];
}
}
$photos[] = $row;
}
$pageVars['photos'] = $photos;
if (findModule('products_variations_photos') && $this->relation_table_name == 'photos_products_relation') {
$variations = ['-1' => 'Žádná přiřazená varianta'];
if (findModule('products_variations_photos')) {
$SQLv = sqlQuery("SELECT id, title
FROM products_variations pv
WHERE pv.{$this->tablefield}=:ID", ['ID' => $ID]);
while (($row = sqlFetchAssoc($SQLv)) !== false) {
$variations[$row['id']] = $row['title'];
}
}
$pageVars['variations'] = $variations;
}
$pageVars['ID'] = $ID;
$pageVars['tablefield'] = $this->tablefield;
$pageVars['copy_from'] = $this->copy_from;
$pageVars['photo_nametype'] = $this->photo_nametype;
$pageVars['search_field'] = $this->search_field;
$vars['body'] = $pageVars;
return $vars;
}
public function handle()
{
global $cfg;
parent::handle();
$ID = $this->getID();
if (getVal('data') && $ID) {
if (findModule('products_variations_photos') && $this->relation_table_name == 'photos_products_relation') {
$photoVariations = getVal('id_variation', null, []);
foreach ($photoVariations as $IDph => $variations) {
sqlQuery("DELETE FROM {$this->relation_table_name} WHERE id_photo=:IDph AND {$this->tablefield} = :ID", ['ID' => $ID, 'IDph' => $IDph]);
foreach ($variations as $variation) {
$insert = [
'id_photo' => $IDph,
$this->tablefield => $ID,
'date_added' => 'NOW()',
];
if ($variation > 0) {
$insert['id_variation'] = $variation;
} else { // maze to duplicity z databaze
sqlQuery("DELETE FROM {$this->relation_table_name} WHERE id_photo=:IDph AND {$this->tablefield} = :ID", ['ID' => $ID, 'IDph' => $IDph]);
}
sqlQueryBuilder()->insert($this->relation_table_name)
->directValues($insert)->onDuplicateKeyUpdate([])->execute();
}
}
}
$data = getVal('data', null, []);
$pos = 0;
foreach ($data as $id => $photo) {
if (!empty($photo['delete']) || !$id) {
if ($id > 0) {
$this->handleDeleteRelationPhoto($id);
}
continue;
}
$values = ['position' => $pos++];
if (isset($cfg['Photo']['kind']) && $this->tablefield == 'id_product') {
$values['show_in_lead'] = $photo['show_in_lead'];
}
$this->serializeCustomData($photo);
$this->updateSQL('photos', $photo, ['id' => $id], ['position', 'show_in_lead']);
$this->updateSQL($this->relation_table_name, $values, [$this->tablefield => $ID, 'id_photo' => $id]);
}
Photos::checkLeadPhoto($this->relation_table_name, $this->tablefield, $ID);
$this->returnOK('Uloženo');
}
if (!empty($_FILES)) {
global $cfg;
sqlGetConnection()->transactional(function () use ($ID) {
$img = new Photos($this->photo_admin_name ?: lcfirst($this->photo_nametype));
$img->newImage();
// uploadovat velky obrazek
$img->uploadPhotoOrVideo($_FILES['qqfile'], ($_REQUEST['qqfilename'] ?? false) ? $_REQUEST['qqfilename'] : '');
// ID nove fotky
$IDph = $img->getID();
if ($this->photo_nametype == 'Product') {
$img->{"insert{$this->photo_nametype}Relation"}($IDph, $ID, 'N', 'Y');
} else {
$img->insertRelation($this->relation_table_name, $IDph, $this->tablefield, $ID, 'N');
}
});
header('Content-type: text/plain');
exit('{"success":true}');
}
}
public function handleDeleteRelationPhoto($IDph)
{
$IDpr = $this->getID();
sqlQuery("DELETE FROM {$this->relation_table_name} WHERE id_photo='{$IDph}' AND {$this->tablefield}=:IDpr", ['IDpr' => $IDpr]);
}
public function handleDeletePhoto()
{
$IDph = getVal('IDph');
sqlQuery('DELETE FROM photos WHERE id=:IDph', ['IDph' => $IDph]);
$this->returnOK();
}
public function handleInsertPhoto()
{
$errors = [];
$data = getVal('data');
$id_photos = explode(',', $data['id_photo']);
$count = sqlQueryBuilder()->select('COUNT(*)')
->from($this->relation_table_name)
->where(\Query\Operator::equals([$this->tablefield => $this->getID()]))
->execute()
->fetchColumn();
foreach ($id_photos as $id_photo) {
$data = [
$this->tablefield => $this->getID(),
'id_photo' => $id_photo,
'date_added' => date('Y-m-d H:i:s'),
];
if (empty($data['id_photo'])) {
$this->returnError('Nevybrána žádna fotografie!');
}
if (sqlQueryBuilder()->select('COUNT(*)')
->from($this->relation_table_name)
->where(\Query\Operator::equals(['id_photo' => $id_photo, $this->tablefield => $data[$this->tablefield]]))
->execute()
->fetchColumn()) {
$errors[] = "Fotografie s ID {$data['id_photo']} je již přiřazena!";
continue;
}
try {
$this->insertSQL($this->relation_table_name, $data);
} catch (Exception $e) {
switch (intval($e->getPrevious()->errorInfo[1])) {
case 1062:
$errors[] = "Fotografie s ID {$data['id_photo']} je již přiřazena!";
// no break
default:
throw $e;
}
}
$this->updateSQL(
$this->relation_table_name,
['position' => $count, 'show_in_lead' => $count == 0 ? 'Y' : 'N'],
[$this->tablefield => $data[$this->tablefield], 'id_photo' => $data['id_photo']]
);
$count++;
}
if ($errors) {
$this->returnError(join(' ', $errors));
}
$this->returnOK();
}
public function handleCopyPhotos()
{
$data = getVal('data');
$data['ID'] = $this->getID();
$data['count'] = returnSQLResult("SELECT COUNT(*) FROM {$this->relation_table_name} WHERE {$this->tablefield}=:field", ['field' => $this->getID()]);
sqlQuery("REPLACE INTO {$this->relation_table_name}
(id_photo, {$this->tablefield}, date_added, show_in_lead, position)
SELECT id_photo, :ID, NOW(), 'N', position+:count
FROM {$this->relation_table_name}
WHERE {$this->tablefield}=:{$this->tablefield}", $data);
Photos::checkLeadPhoto($this->relation_table_name, $this->tablefield, $this->getID());
$this->returnOK('Obrázky byly zkopírovány');
}
public function handleMovePhoto()
{
$item = getVal('moved_item');
if (!empty($item)) {
Photos::checkLeadPhoto($this->relation_table_name, $this->tablefield, $item[$this->tablefield]);
sqlQuery("UPDATE {$this->relation_table_name} SET position=position+1000 WHERE position >= :position AND {$this->tablefield}=:id", ['id' => $item[$this->tablefield], 'position' => $item['position']]);
sqlQuery("UPDATE {$this->relation_table_name} SET position=:position WHERE id_photo=:id_photo AND {$this->tablefield}=:id", ['id' => $item[$this->tablefield], 'position' => $item['position'], 'id_photo' => $item['id_photo']]);
Photos::checkLeadPhoto($this->relation_table_name, $this->tablefield, $item[$this->tablefield]);
}
}
public static function checkPhotos($table, $id_field, $id_photo)
{
$sql = sqlQuery("SELECT {$id_field} FROM {$table} WHERE id_photo=:idph", ['idph' => $id_photo]);
$array = sqlFetchAll($sql, [$id_field => $id_field]);
sqlQuery("DELETE FROM {$table} WHERE id_photo=:idph", ['idph' => $id_photo]);
foreach ($array as $ID) {
Photos::checkLeadPhoto($table, $id_field, $ID);
}
}
}

View File

@@ -0,0 +1,51 @@
<?php
use KupShop\AdminBundle\Util\AdminSectionTree;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
class BaseAdminSectionsRelations extends \Frame
{
protected $template = 'sectionsRelations.tpl';
protected AdminSectionTree $adminSectionTree;
protected string $label;
protected string $tableName;
protected string $column;
public function __construct()
{
$this->adminSectionTree = ServiceContainer::getService(AdminSectionTree::class);
}
public function get_vars()
{
$vars = parent::get_vars();
$pageVars['tree'] = $this->adminSectionTree->getCategories();
$pageVars['category0'] = $this->adminSectionTree->getCategory0();
$pageVars['selected'] = $this->adminSectionTree->getSelected($this->getID(), $this->tableName, $this->label, $this->column);
$this->adminSectionTree->getOpened($pageVars['tree']);
$pageVars['opened'] = $this->adminSectionTree->opened;
$vars['body'] = $pageVars;
$vars['body']['data']['id'] = $this->getID();
$vars['body']['ID'] = $this->getID();
return $vars;
}
public function handle()
{
parent::handle();
if (getVal('isSubmitted')) {
$this->handleSubmit();
}
}
protected function handleSubmit(): void
{
throw new \RuntimeException('Not implemented!');
}
}

View File

@@ -0,0 +1,556 @@
<?php
/**
* Created by PhpStorm.
* User: hanz
* Date: 9/2/15
* Time: 8:30 AM.
*/
use KupShop\AdminBundle\Exception\ExportException;
use KupShop\AdminBundle\Util\ActivityLog;
use KupShop\CatalogBundle\Section\SectionTree;
use KupShop\CatalogBundle\Util\ProductsFilterSpecs;
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Excel\ExcelGenerator;
use KupShop\StoresBundle\Query\StoresQuery;
use KupShop\StoresBundle\Utils\StoresInStore;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use Query\Operator;
use Query\QueryBuilder;
class ExportProducts
{
use \KupShop\AdminBundle\Util\CategoryTree;
public function getFile()
{
while (ob_get_level()) {
ob_end_clean();
}
increaseMemoryLimit(1024);
ini_set('max_execution_time', '600');
$filename = 'Products-'.date('Y-m-d_H-i').'.xlsx';
try {
$this->checkItemsCount();
$generator = new ExcelGenerator();
$this->defineHeader();
$generator->generateExcel($this->getHeader(), $this->getData(), $filename);
} catch (ExportException $e) {
redirect('launch.php?s=board.php&type=export_products&ErrStr='.urlencode($e->getMessage()));
} catch (Exception $exception) {
$sentry = getRaven();
$sentry->captureException($exception);
}
addActivityLog(
ActivityLog::SEVERITY_NOTICE,
ActivityLog::TYPE_COMMUNICATION,
sprintf('Export produktů: %s', $filename)
);
exit;
}
protected $fields = 'p.id,p.campaign, p.title, p.guarantee, pr.name as producer, p.short_descr, p.long_descr,
ps.id_section, v.vat, p.discount, p.show_in_feed, p.max_cpc, p.parameters, p.delivery_time, p.pieces_sold,
p.meta_title, p.meta_description, p.meta_keywords, GROUP_CONCAT(DISTINCT pa.link) AS attachments, p.date_added,
p.figure, pv.figure figure_variation,
COALESCE(pv.width, p.width) as width,
COALESCE(pv.height, p.height) as height,
COALESCE(pv.depth, p.depth) as depth';
protected $column_names = [
'code' => ['name' => 'Kód'],
'title' => ['name' => 'Název'],
'campaign' => ['name' => 'kampaně'],
'producer' => ['name' => 'Výrobce'],
'supplier_code' => ['name' => 'Kód dodavatele'],
'section' => ['name' => 'Sekce'],
'short_descr' => ['name' => 'Anotace'],
'long_descr' => ['name' => 'Popis'],
'parameters' => ['name' => 'Parametry'],
'photo' => ['name' => 'Fotografie'],
'vat' => ['name' => 'Sazba DPH', 'type' => DataType::TYPE_NUMERIC],
'price_without_vat' => ['name' => 'cena bez DPH [Kč]', 'type' => DataType::TYPE_NUMERIC, 'format' => '0.00'],
'price_with_vat' => ['name' => 'cena s DPH [Kč]', 'type' => DataType::TYPE_NUMERIC, 'format' => '0.00'],
'discount' => ['name' => 'sleva [%]', 'type' => DataType::TYPE_NUMERIC],
'price_for_discount' => ['name' => 'cena pro slevu', 'type' => DataType::TYPE_NUMERIC],
'discount_price_without_vat' => ['name' => 'cena po slevě bez DPH [Kč]', 'type' => DataType::TYPE_NUMERIC],
'discount_price_with_vat' => ['name' => 'cena po slevě s DPH [Kč]', 'type' => DataType::TYPE_NUMERIC],
'in_store' => ['name' => 'skladem [ks]', 'type' => DataType::TYPE_NUMERIC],
'in_store_min' => ['name' => 'Minimálně skladem [ks]', 'type' => DataType::TYPE_NUMERIC],
'delivery_time' => ['name' => 'Dostupnost', 'type' => DataType::TYPE_NUMERIC],
'guarantee' => ['name' => 'záruka [měs.]', 'type' => DataType::TYPE_NUMERIC],
'show_in_feed' => ['name' => 'Zobrazovat ve srovnávačích'],
'max_cpc' => ['name' => 'cena za proklik [Kč]', 'type' => DataType::TYPE_NUMERIC, 'format' => '0.00'],
'ean' => ['name' => 'Kód EAN'],
'pieces_sold' => ['name' => 'Počet prodaných kusů', 'type' => DataType::TYPE_NUMERIC, 'format' => '0'],
'id' => ['name' => 'ID produktu', 'type' => DataType::TYPE_NUMERIC],
'meta_title' => ['name' => 'SEO Titulek'],
'meta_description' => ['name' => 'SEO Popis'],
'attachments' => ['name' => 'Přílohy'],
'weight' => ['name' => 'Hmotnost', 'type' => DataType::TYPE_NUMERIC],
'width' => ['name' => 'Šířka', 'type' => DataType::TYPE_NUMERIC],
'height' => ['name' => 'Výška', 'type' => DataType::TYPE_NUMERIC],
'depth' => ['name' => 'Hloubka', 'type' => DataType::TYPE_NUMERIC],
'date_added' => ['name' => 'Datum vytvoření', 'type' => DataType::TYPE_ISO_DATE, 'format' => NumberFormat::FORMAT_DATE_DDMMYYYY],
'figure' => ['name' => 'Viditelné - produkt'],
'figure_variation' => ['name' => 'Viditelné - varianta'],
];
public function addFields($fields)
{
$this->fields = $this->fields.$fields;
}
public function getFields()
{
return $this->column_names;
}
public function getHeader($array = null)
{
if (!$array) {
$array = $this->getFields();
}
$fields = [];
foreach ($array as $key => $field) {
if (array_key_exists('sub', $field)) {
foreach ($field['sub'] as $subkey => $subfield) {
$fields[$subkey] = $subfield;
}
} else {
$fields[$key] = $field;
}
}
return $fields;
}
protected function checkItemsCount()
{
$data = $this->prepareQuery()->execute();
$items_count = $data->rowCount();
if ($items_count == 0) {
throw new ExportException('Export se nepodařil, protože zadanému filtru neodpovídá žádná položka');
}
}
protected function prepareQuery(): QueryBuilder
{
$qb = $this->getBaseQueryBuilder();
if (findModule(Modules::PRODUCTS, Modules::SUB_NOTE)) {
if (findModule(Modules::PRODUCTS_VARIATIONS)) {
$qb->addSelect('COALESCE(pv.note, p.note) as note');
} else {
$qb->addSelect('p.note');
}
}
if (findModule('products', 'price_common')) {
$qb->addSelect('p.price_common');
}
if (findModule(Modules::PRODUCTS, Modules::SUB_PRICE_BUY)) {
if (findModule('products_variations')) {
$qb->addSelect('COALESCE(pv.price_buy, p.price_buy) as price_buy');
} else {
$qb->addSelect('p.price_buy');
}
}
if (findModule(Modules::PRODUCTS, Modules::SUB_WEIGHT)) {
if (findModule(Modules::PRODUCTS_VARIATIONS)) {
$qb->addSelect('COALESCE(pv.weight, p.weight) as weight');
} else {
$qb->addSelect('p.weight as weight');
}
}
$qb->joinVariationsOnProducts();
$qb->addSelect('COALESCE(pv.id, 0) as id_variation');
if (findModule('products_variations')) {
if (findModule('products_variations', 'variationCode')) {
$qb->addSelect('COALESCE(pv.code, p.code) as code');
} else {
$qb->addSelect('p.code as code');
}
$qb->addSelect('COALESCE(pv.ean, p.ean) as ean, COALESCE(pv.price, p.price) as price_without_vat,
COALESCE(pv.in_store, p.in_store) as in_store');
if (findModule(\Modules::MISSING_PRODUCTS)) {
$qb->addSelect('COALESCE(pv.in_store_min, p.in_store_min) as in_store_min');
}
$qb->addSelect("GROUP_CONCAT(DISTINCT CONCAT(pvc.id_label, ':', pvc.id_value) SEPARATOR ';') as `variation_combination`");
$qb->leftJoin('p', 'products_variations_combination', 'pvc', 'pv.id=pvc.id_variation');
$qb->addGroupBy('pv.id');
} else {
$qb->addSelect('p.code as code, p.ean as ean, p.price as price_without_vat, p.in_store as in_store');
}
if (findModule('photos')) {
$qb->addSelect("(SELECT GROUP_CONCAT(CONCAT(ph.source, ph.image_2) SEPARATOR ';') FROM photos_products_relation as ppr
LEFT JOIN photos as ph ON ph.id=ppr.id_photo WHERE ppr.id_product=p.id ORDER BY ppr.position ASC ) as photos");
}
$filterSpecs = null;
$productsFilterSpecs = ServiceContainer::getService(ProductsFilterSpecs::class);
$filter = getval('filter');
if ($filter) {
$filterSpecs = $productsFilterSpecs->getSpecs($filter);
if ($filterSpecs) {
$qb->andWhere($filterSpecs);
}
}
if (findModule(Modules::SUPPLIERS)) {
if (findModule(Modules::PRODUCTS_VARIATIONS)) {
$qb->addSelect('pos.code as supplier_code')
->leftJoin('pv', 'products_of_suppliers', 'pos', 'p.id = pos.id_product AND pv.id <=> pos.id_variation');
} else {
$qb->addSelect('pos.code as supplier_code')
->leftJoin('p', 'products_of_suppliers', 'pos', 'p.id=pos.id_product');
}
}
if (findModule(\Modules::PRICE_HISTORY)) {
$qb->addSelect('p.price_for_discount as price_for_discount');
}
return $qb;
}
protected function getProducts(): Generator
{
$qb = $this->prepareQuery();
$limit = 5000;
$from = 0;
do {
$qb->setFirstResult($from);
$qb->setMaxResults($limit);
$batch = $qb->execute();
yield $batch;
$from = $from + $limit;
} while ($batch->rowCount() == $limit);
}
protected function getBaseQueryBuilder(): Query\QueryBuilder
{
return sqlQueryBuilder()->select($this->fields)
->fromProducts()
->leftJoin('p', 'producers', 'pr', 'p.producer = pr.id')
->joinVatsOnProducts()
->leftJoin('p', 'products_in_sections', 'ps', 'p.id = ps.id_product')
->leftJoin('p', 'attachments', 'pa', 'pa.id_product = p.id')
->groupBy('p.id');
}
protected function defineHeader()
{
$parameters = [];
$variants = [];
$pricelists = [];
if (findModule(Modules::PRODUCTS, Modules::SUB_NOTE)) {
$this->column_names['note']['name'] = 'Poznámka';
}
if (findModule('products', 'price_common')) {
$this->column_names['price_common'] = ['name' => 'Škrtlá cena [Kč]', 'type' => DataType::TYPE_NUMERIC];
}
if (findModule(Modules::PRODUCTS, Modules::SUB_PRICE_BUY)) {
$this->column_names['price_buy'] = ['name' => 'Nákupní cena', 'type' => DataType::TYPE_NUMERIC];
}
if (findModule(Modules::STORES) && $this->isExportOptionEnabled('exportStoresInStore')) {
$this->column_names['in_store']['sub']['in_store'] = $this->column_names['in_store'];
foreach (ServiceContainer::getService(StoresInStore::class)->getStoresNames() as $key => $name) {
$this->column_names['in_store']['sub']['store'.$key.'_in_store'] = ['name' => 'sklad '.$name, 'type' => DataType::TYPE_NUMERIC];
}
}
$SQL = sqlQuery('SELECT pvc.id_label, pvcl.label, pvc.id_value, pvcv.value
FROM products_variations_combination AS pvc
LEFT JOIN products_variations_choices_labels AS pvcl ON pvc.id_label=pvcl.id
LEFT JOIN products_variations_choices_values AS pvcv ON pvc.id_label = pvcv.id_label AND pvc.id_value = pvcv.id
GROUP BY pvc.id_value');
foreach ($SQL as $row) {
$variants['var'.$row['id_label']][$row['id_value']] = $row['value'];
$this->column_names['variants']['sub']['var'.$row['id_label']]['name'] = 'Varianta: '.$row['label'];
}
if (findModule('products_parameters') && $this->isExportOptionEnabled('exportParameters')) {
$iterParams = sqlQuery('SELECT pp.id_parameter, pp.value_list, pp.value_char, pp.value_float, p.name, p.value_type
FROM parameters_products AS pp
LEFT JOIN parameters AS p ON p.id=pp.id_parameter
LEFT JOIN parameters_list AS pl ON pl.id=pp.value_list
GROUP BY pl.id, p.id
ORDER BY p.id');
foreach ($iterParams as $row) {
$this->column_names['prod_parameters']['sub']['par'.$row['id_parameter']]['name'] = 'Parametr: '.$row['name'];
$parameters['par'.$row['id_parameter']] = '';
}
}
if (!findModule(\Modules::PRICE_HISTORY)) {
unset($this->column_names['price_for_discount']);
}
if (!findModule(\Modules::MISSING_PRODUCTS)) {
unset($this->column_names['in_store_min']);
}
if (findModule(Modules::PRICELISTS) && ($exportPricelists = $this->getExportOptions()['exportPricelists'] ?? null)) {
$exportPricelists = array_filter($exportPricelists);
if ($exportPricelists) {
$pricelists = sqlQueryBuilder()->select('CONCAT("pl", id), id, name, currency')->from('pricelists')
->where(Operator::inIntArray($exportPricelists, 'id'))
->execute()->fetchAllAssociativeIndexed();
foreach ($pricelists as $key => $row) {
$name = 'Ceník: '.$row['name'];
$this->column_names['prod_pricelists']['sub'][$key] = ['name' => $name.": cena bez DPH ({$row['currency']})", 'type' => DataType::TYPE_NUMERIC];
$this->column_names['prod_pricelists']['sub'][$key.'discount'] = ['name' => $name.': sleva (%)', 'type' => DataType::TYPE_NUMERIC];
if (findModule(\Modules::PRICE_HISTORY)) {
$this->column_names['prod_pricelists']['sub'][$key.'price_for_discount'] = ['name' => $name.": cena pro slevu ({$row['currency']})", 'type' => DataType::TYPE_NUMERIC];
}
$this->column_names['prod_pricelists']['sub'][$key.'final'] = ['name' => $name.": finální cena bez DPH ({$row['currency']})", 'type' => DataType::TYPE_NUMERIC];
$this->column_names['prod_pricelists']['sub'][$key.'final_with_vat'] = ['name' => $name.": finální cena s DPH ({$row['currency']})", 'type' => DataType::TYPE_NUMERIC];
}
}
}
$maxPhotos = sqlQueryBuilder()
->select('COUNT(ppr.id_photo) as cnt')
->from('photos_products_relation', 'ppr')
->groupBy('ppr.id_product')
->orderBy('cnt', 'DESC')
->setMaxResults(1)
->execute()
->fetchColumn();
for ($i = 1; $i <= $maxPhotos; $i++) {
$this->column_names['photos']['sub']['photo'.$i]['name'] = 'Fotografie '.$i;
}
return ['variants' => $variants, 'parameters' => $parameters ?? [], 'pricelists' => $pricelists ?? []];
}
protected function getData(): Generator
{
$cfg = Config::get();
$sectionTree = ServiceContainer::getService(SectionTree::class);
$fromHeader = $this->defineHeader();
$variants = $fromHeader['variants'];
$parameters = $fromHeader['parameters'];
foreach ($this->getProducts() as $batch) {
$sheet = [];
$foto = [];
$idProducts = [];
$idVariations = [];
foreach ($batch as $row) {
$idProduct = $row['id'];
$idVariation = $row['id_variation'];
$row['price_with_vat'] = toDecimal($row['price_without_vat'])->addVat(toDecimal($row['vat']))->printFloatValue(2);
$row['discount_price_without_vat'] = toDecimal($row['price_without_vat'])->addDiscount($row['discount'])->printFloatValue(4);
$row['discount_price_with_vat'] = toDecimal($row['price_with_vat'])->addDiscount($row['discount'])->printFloatValue(2);
$row['section'] = $sectionTree->getFullPath($row['id_section']);
$row['campaign'] = join(', ', array_map(function ($char) use ($cfg) {
return getVal($char, $cfg['Products']['Flags'], ['plural' => $char])['plural'];
}, explode(',', $row['campaign'])));
$attachments = $row['attachments'] ? explode(',', $row['attachments']) : [];
$attachments = array_map(function ($el) use ($cfg) {
return rtrim($cfg['Addr']['full'], '/').trim($el);
}, array_filter($attachments, function ($el) { return !empty(trim($el)); }));
$row['attachments'] = join(', ', $attachments);
$fotorow = [];
$output_row = [];
foreach ($this->column_names as $key => $name) {
if ($key == 'variants') {
$combination = null;
if (!empty($row['variation_combination'])) {
$variation_combination = explode(';', $row['variation_combination']);
foreach ($variation_combination as $item) {
$variation = explode(':', $item);
$combination['var'.$variation[0]] = $variation[1]; // id_label => id_value
}
}
foreach ($name['sub'] ?? [] as $id_label => $label) {
if ($combination) {
if (array_key_exists($id_label, $combination)) {
$output_row[$id_label] = $variants[$id_label][$combination[$id_label]];
} else {
$output_row[$id_label] = '';
}
} else {
$output_row[$id_label] = '';
}
}
} elseif ($key == 'photos') {
$photos = explode(';', $row['photos'] ?? '');
foreach ($name['sub'] as $pkey => $pvalue) {
$photoIndex = str_replace('photo', '', $pkey) - 1;
if (!empty($photos[$photoIndex])) {
$fotorow[$pkey] = $cfg['Addr']['full'].'data/photos/'.$photos[$photoIndex];
} else {
$fotorow[$pkey] = '';
}
}
} elseif ($key == 'in_store') {
if (findModule(Modules::STORES) && $this->isExportOptionEnabled('exportStoresInStore')) {
foreach ($name['sub'] as $subkey => $label) {
if (!empty($row[$subkey])) {
$output_row[$subkey] = (float) $row[$subkey];
} else {
$output_row[$subkey] = 0;
}
}
} else {
if (!empty($row[$key])) {
$output_row[$key] = (float) $row[$key];
} else {
$output_row[$key] = 0;
}
}
} elseif (!empty($row[$key])) {
$output_row[$key] = mb_strcut($row[$key], 0, 32767);
} elseif ($key == 'prod_parameters') {
foreach ($name['sub'] as $subkey => $label) {
$output_row[$subkey] = '';
}
} elseif ($key == 'prod_pricelists') {
foreach ($name['sub'] as $subkey => $label) {
$output_row[$subkey] = null;
}
} else {
$output_row[$key] = null;
}
}
$idProducts[] = $idProduct;
if ($idVariation) {
$idVariations[$idProduct][] = $idVariation;
} else {
$idVariations[$idProduct] = null;
}
$sheet[$idProduct][$idVariation] = $output_row;
$foto[$idProduct][$idVariation] = $fotorow;
}
if (findModule('products_parameters') && $this->isExportOptionEnabled('exportParameters')) {
$parqb = sqlQueryBuilder()->select('pp.id_parameter, pp.id_product, GROUP_CONCAT(COALESCE(pl.value, pp.value_char, pp.value_float) ORDER BY pl.position,pl.id) as parvalue')
->from('parameters_products', 'pp')
->leftJoin('pp', 'parameters_list', 'pl', 'pl.id=pp.value_list')
->where(Operator::inIntArray($idProducts, 'pp.id_product'))
->groupBy('pp.id_parameter, pp.id_product')
->orderBy('pp.id_product')
->execute();
foreach ($parqb as $par) {
foreach ($sheet[$par['id_product']] as &$row) {
$row['par'.$par['id_parameter']] = $par['parvalue'];
}
}
}
if (findModule(Modules::STORES) && $this->isExportOptionEnabled('exportStoresInStore')) {
$filter = getVal('filter');
$storeIds = null;
if (isset($filter['stores'])) {
$storeIds = $filter['stores'];
}
$storeQuery = sqlQueryBuilder()
->select('p.id id_product, pv.id id_variation')
->fromProducts()
->joinVariationsOnProducts()
->andWhere(Operator::inIntArray($idProducts, 'p.id'))
->andWhere(StoresQuery::addStoresInStoreAmounts($storeIds, addMinQuantity: false));
if (!empty($filter['variations'])) {
// ad limit for variations based on filter[variations]
$idVariations = sqlQueryBuilder()
->select('id_variation')
->from('products_variations_combination')
->andWhere(Operator::inIntArray($filter['variations'], 'id_value'))
->execute()->fetchFirstColumn();
$storeQuery->andWhere(Operator::inIntArray($idVariations, 'pv.id'));
}
foreach ($storeQuery->execute() as $storesRow) {
$id_product = $storesRow['id_product'];
$id_variation = $storesRow['id_variation'] ?? 0;
unset($storesRow['id_product'], $storesRow['id_variation']);
foreach ($storesRow as $key => $value) {
$sheet[$id_product][$id_variation][$key] = intval($value);
}
}
}
if ($pricelists = $fromHeader['pricelists']) {
$plIDs = implode(',', array_column($pricelists, 'id'));
// pouze data (ceny a slevy) vyplnene v ceniku, neni potreba COALESCE(prlv.price, pv.price, prlp.price, p.price) atd. jako na FE
$plqb = sqlQueryBuilder()
->select('p.id as id_product, pv.id as id_variation, v.vat, prl.id as id_pricelist,
COALESCE(prlv.price, prlp.price, pv.price, p.price) as price, COALESCE(prlv.discount, prlp.discount) as discount')
->fromProducts()->joinVariationsOnProducts()
->leftJoin('p', 'vats', 'v', 'v.id = p.vat')
->leftJoin('p', 'pricelists', 'prl', "prl.id IN ({$plIDs})")
->leftJoin('p', 'pricelists_products', 'prlp', 'prl.id = prlp.id_pricelist AND prlp.id_product = p.id AND prlp.id_variation IS NULL')
->leftJoin('p', 'pricelists_products', 'prlv', 'prl.id = prlv.id_pricelist AND prlv.id_product = p.id AND prlv.id_variation = pv.id')
->andWhere(\Query\Product::productsAndVariationsIds($idVariations))
->groupBy('p.id, pv.id, prl.id');
if (findModule(\Modules::PRICE_HISTORY)) {
$plqb->addSelect(['COALESCE(prlv.price_for_discount, prlp.price_for_discount, pv.price_for_discount, p.price_for_discount) as price_for_discount']);
}
foreach ($plqb->execute() as $pl_row) {
$id_product = $pl_row['id_product'];
$id_variation = $pl_row['id_variation'] ?? 0;
$col = 'pl'.$pl_row['id_pricelist'];
$sheet[$id_product][$id_variation][$col] = $pl_row['price'];
$sheet[$id_product][$id_variation][$col.'discount'] = $pl_row['discount'];
if (findModule(\Modules::PRICE_HISTORY)) {
$sheet[$id_product][$id_variation][$col.'price_for_discount'] = $pl_row['price_for_discount'];
}
if ($pl_row['price']) {
$sheet[$id_product][$id_variation][$col.'final'] = $pl_row['price'];
if ($pl_row['discount']) {
$sheet[$id_product][$id_variation][$col.'final'] = $pl_row['price'] * (100 - $pl_row['discount']) / 100;
}
$sheet[$id_product][$id_variation][$col.'final_with_vat'] = toDecimal($sheet[$id_product][$id_variation][$col.'final'] * ((100 + $pl_row['vat']) / 100))->printFloatValue(2);
}
}
}
foreach ($sheet as $idProd => $product) {
foreach ($product as $idVar => $variant) {
yield array_merge($variant, $foto[$idProd][$idVar] ?? []);
}
}
}
}
private function isExportOptionEnabled(string $option): bool
{
return ($this->getExportOptions()[$option] ?? false) === 'Y';
}
private function getExportOptions(): array
{
return getVal('options', null, []);
}
}

240
admin/class/class.Frame.php Normal file
View File

@@ -0,0 +1,240 @@
<?php
use KupShop\I18nBundle\Util\TranslationUtil;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
#[AllowDynamicProperties]
class Frame extends Base
{
protected $ID;
protected $errors = [];
protected $htmlErrors = [];
public function get_vars()
{
$vars = parent::get_vars();
$ErrStr = getVal('ErrStr');
if (!empty($ErrStr)) {
$this->errors[] = $ErrStr;
}
$vars['ErrStr'] = join(',', $this->getErrors());
if ($vars['ErrStr'] && $vars['ErrStr'] != translate('saved', 'status')) {
header('admin-error: '.urlencode(mb_strcut($vars['ErrStr'], 0, 1024)));
}
if (!empty($this->getHTMLErrors())) {
$error = '';
foreach ($this->getHTMLErrors() as $HTMLError) {
$error .= '<p>'.$HTMLError.'</p>';
}
header('admin-html-error: '.urlencode(mb_strcut($error, 0, 1024)));
}
$OkStr = getVal('OkStr');
if (!empty($OkStr)) {
$vars['OkStr'] = $OkStr;
}
if (!empty($this->getHTMLErrors())) {
$vars['htmlErrors'] = $this->getHTMLErrors();
}
$header = getVal('header', $vars, []);
$header['date'] = date('Ymd');
if (getVal('hdrType') != null) {
$header['hdrType'] = getVal('hdrType');
}
$header['refresh'] = getVal('refresh');
$vars['header'] = $header;
return $vars;
}
public function tryRights($acn = '')
{
// Musim mit budto prava na pozadovanou akci, nebo READ prava
if (!UserRights::hasRights($this->getRightsType(), $acn) && !UserRights::hasRights($this->getRightsType(), 'READ')) {
throw new AccessDeniedException('');
}
}
protected function getRightsType()
{
$type = getVal('s');
if (!$type || $type == 'list.php') {
$type = getVal('type');
if (!$type) {
$type = lcfirst($this->getClassName());
}
} else {
$type = substr($type, 0, -4);
}
return $type;
}
protected function getAction()
{
if (empty($this->action)) {
$acn = getVal('acn');
if (empty($acn)) {
$acn = 'add';
}
$this->action = $acn;
}
return $this->action;
}
protected function getID()
{
if (empty($this->ID)) {
$ID = getVal('ID');
/*if(empty($ID))
logError(__FILE__, __LINE__, "Empty ID");*/
$this->setID($ID);
}
return $this->ID;
}
public function setID($id)
{
$this->ID = $id;
}
public function getName()
{
return substr(getVal('s'), 0, -4);
}
public function returnError($ErrStr, $parentRefresh = '', $ID = null)
{
if (empty($ID)) {
$ID = $this->getID();
}
if ($parentRefresh) {
if ($refresh = getVal('refresh')) {
$parentRefresh = "&refresh={$refresh}";
} else {
$parentRefresh = '&refresh=parent';
}
}
if (getVal('autoclose')) {
$parentRefresh .= '&refresh=close';
}
$type = getVal('type');
if ($type) {
$parentRefresh .= '&type='.$type;
}
redirect("launch.php?s={$this->getName()}.php&acn=edit{$parentRefresh}&flap=".getVal('flap')."&ID={$ID}&ErrStr=".urlencode($ErrStr));
}
public function addError($ErrStr = null)
{
$this->errors[] = $ErrStr;
}
public function addHTMLError($error)
{
$this->htmlErrors[] = $error;
}
public function getHTMLErrors()
{
return array_unique($this->htmlErrors);
}
public function getErrors()
{
return array_unique($this->errors);
}
public function returnOK($ErrStr = null, $parentRefresh = false, $params = [])
{
if (empty($ErrStr)) {
$this->returnError($GLOBALS['txt_str']['status']['saved'], true);
}
if ($parentRefresh) {
$params['refresh'] = 'parent';
}
if (getVal('type')) {
$params['type'] = getVal('type');
}
if (getVal('flap')) {
$params['flap'] = getVal('flap');
}
$params['OkStr'] = $ErrStr;
if (empty($params['acn'])) {
$params['acn'] = 'edit';
}
return $this->redirect($params);
}
public function redirect($params = [])
{
$params = array_merge($_GET, $params);
return redirect('launch.php?'.http_build_query($params));
}
public function unserializeCustomData(&$data)
{
if (!isset($data['data'])) {
$data['data'] = [];
return;
}
if (is_string($data['data'])) {
$data['data'] = json_decode($data['data'], true);
}
if (!is_array($data['data']) && !is_object($data['data'])) {
$data['data'] = [];
}
}
public function serializeCustomData(&$data)
{
if (empty($data['data'])) {
$data['data'] = null;
} else {
$data['data'] = json_encode($data['data']);
}
}
protected function isDuplicate()
{
return getVal('Duplicate');
}
protected function getTranslationUtil(): ?TranslationUtil
{
if (!findModule(\Modules::TRANSLATIONS)) {
return null;
}
static $translationUtil;
if (!$translationUtil) {
$translationUtil = ServiceContainer::getService(TranslationUtil::class);
}
return $translationUtil;
}
}

View File

@@ -0,0 +1,28 @@
<?php
class Menu extends Frame
{
public function getTemplate()
{
if (!($template = $this->template)) {
$template = './menu/'.getVal('type').'.tpl';
}
if ($this->smarty->templateExists($template)) {
return $template;
}
return './menu.tpl';
}
public function get_vars()
{
$vars = parent::get_vars();
return array_merge($vars, [
'dateToday' => date('Y-m-d'),
'dateFrom' => date('Y-m-d', time() - (14 * 86400)),
'type' => getVal('type'),
]);
}
}

View File

View File

@@ -0,0 +1,390 @@
<?php
use KupShop\AdminBundle\Util\StockInProductOfSupplierService;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Functional\Mapping;
use Query\Operator;
class StockInImport
{
use DatabaseCommunication;
public $type;
public $errors = [];
public $default_settings = [
'type' => 'xlsx',
'fields' => [0 => 'code', 1 => 'name', 2 => 'quantity', 3 => 'ean', 4 => 'price', 5 => 'supplier_code'],
'search_in_products' => true,
'isdoc_search_in_ean' => true,
'encoding' => 'UTF-8',
'skip' => '1',
'piece_price' => true,
'default' => true,
];
public $supplier_settings;
protected $separator = ';';
protected $skip = 0;
protected $encoding;
protected $fields = [];
protected $stock_in;
protected $check_file_name = false;
protected $only_visible = false;
protected $search_in_products = false;
protected $multiple = 1;
protected $cut_code;
protected $ignore_code = false;
protected $stockInIndex;
protected StockInProductOfSupplierService $stockInProductOfSupplierService;
public function __construct($stock_in, $stockInIndex = 'invoice')
{
$this->stock_in = $stock_in;
$this->supplier_settings = sqlQueryBuilder()->select('s.import_settings')
->from('suppliers', 's')
->where(Operator::equals(['id' => $stock_in['id_supplier']]))
->execute()
->fetchColumn();
$this->stockInIndex = $stockInIndex;
/* @var StockInProductOfSupplierService $supplierService */
$this->stockInProductOfSupplierService = ServiceContainer::getService(StockInProductOfSupplierService::class);
}
public function load_supplier_settings()
{
$settings = $this->supplier_settings != null ? json_decode($this->supplier_settings, true) : $this->default_settings;
if ($this->supplier_settings && json_last_error()) {
throw new Exception('Nelze nacist nastaveni importu: '.json_last_error_msg());
}
foreach ((array) $settings as $key => $value) {
$this->$key = $value;
}
}
public function import($file)
{
if ($this->check_file_name) {
$name = pathinfo($file['name'], PATHINFO_FILENAME);
if ($name != $this->stock_in['code']) {
return $this->add_error("Nesedí jméno souboru s číslem faktury: {$name} != {$this->stock_in['code']}");
}
}
if (empty($file['tmp_name'])) {
return $this->add_error('Nebyl nahrán žádný soubor!');
}
$method = "import_{$this->type}";
sqlStartTransaction();
$ret = $this->$method($file['tmp_name']);
sqlFinishTransaction();
return $ret;
}
public function import_isdoc($file)
{
$xml = simplexml_load_file($file);
$factorage = [
'date_issued' => (string) $xml->IssueDate,
'note' => (string) $xml->note,
'date_expiration' => (string) $xml->PaymentMeans->Payment->Details->PaymentDueDate,
'total_price' => (string) $xml->LegalMonetaryTotal->TaxExclusiveAmount,
];
if (!$this->ignore_code) {
$factorage['code'] = (string) $xml->ID;
}
$this->updateSQL(
'stock_in',
$factorage,
[
'id' => $this->stock_in['id'],
]
);
foreach ($xml->InvoiceLines->InvoiceLine as $invoiceLine) {
$item = [
'code' => (string) $invoiceLine->Item->SellersItemIdentification->ID,
'name' => (string) $invoiceLine->Item->Description,
'quantity' => (string) $invoiceLine->InvoicedQuantity,
'price' => (string) $invoiceLine->LineExtensionAmount,
'vat' => (string) $invoiceLine->ClassifiedTaxCategory->Percent,
];
if ($this->isdoc_search_in_ean ?? false) {
$ean = array_filter([
(int) $invoiceLine->Item->CatalogueItemIdentification->ID ?? '', // tady by mel byt EAN dle dokumentace
(int) $invoiceLine->Item->SellersItemIdentification->ID ?? '', // nekdo ma EAN tady
]);
if ($ean) {
$ean = (count($ean) == 1 ? reset($ean) : $ean);
$item['ean'] = $ean;
}
}
if ($item['quantity'] < 0) {
$item['price'] = (string) $invoiceLine->UnitPrice;
}
$this->add_item($item);
}
return true;
}
public function import_isdocx($file)
{
$za = new ZipArchive();
$res = $za->open($file);
if ($res !== true) {
return false;
}
// finds the first .isdoc file and returns it or false
$findIsdoc = function ($zipArchive) {
// loop through all files in zip
for ($i = 0; $i < $zipArchive->numFiles; $i++) {
$stat = $zipArchive->statIndex($i);
// if extension is .isdoc return the filename
if (preg_match('/(.*\.isdoc)/', $stat['name']) === 1) {
return $stat['name'];
}
}
return false;
};
$fileName = 'zip://'.$file.'#'.$findIsdoc($za);
$za->close();
return $this->import_isdoc($fileName);
}
public function fopen_convert($fileName)
{
$fc = iconv($this->encoding, 'utf-8', file_get_contents($fileName));
$handle = fopen('php://memory', 'rw');
fwrite($handle, $fc);
fseek($handle, 0);
return $handle;
}
public function import_xlsx($file)
{
$xlsx = new AutomaticImportTransform($file);
$data = $xlsx->GetXml();
$i = 0;
foreach ($data->item as $row) {
if ($i < $this->skip) {
$i++;
continue;
}
$arr = json_decode(json_encode($row), true)['col'];
$arr = array_pad($arr, count($this->fields), null);
$item = array_combine($this->fields, array_slice($arr, 0, count($this->fields)));
// kontrola prázdného řádku
if (!empty($item) && !is_array($item['quantity'])) {
$this->add_item($item);
} else {
continue;
}
$i++;
}
return true;
}
public function import_csv($file)
{
if ($this->encoding) {
$file = $this->fopen_convert($file);
} else {
$file = fopen($file, 'r');
}
if (!$file) {
exit('Nelze načíst soubor');
}
$count = count($this->fields);
while ($this->skip-- > 0) {
fgetcsv($file, null, $this->separator);
}
while ($row = fgetcsv($file, null, $this->separator)) {
$row = array_combine($this->fields, array_slice($row, 0, $count));
$this->add_item($row);
}
return true;
}
public function add_item($item)
{
/*
* Funkce na uříznutí X počtu znaků z kodu. Stačí zadat v importu/exportu "cut" = 'začátek';'konec'
* */
if ($this->cut_code) {
$cut = explode(';', $this->cut_code);
$item['code'] = substr($item['code'], $cut[0], $cut[1] ?? (strlen($item['code']) - $cut[0]));
}
$mapping = [];
if (!empty($item['code'])) {
$mapping = ['code' => $item['code']];
}
if (!empty($item['ean'])) {
$mapping['ean'] = $item['ean'];
}
if (!empty($mapping)) {
$qb = sqlQueryBuilder()->select('pos.id_product', 'pos.id_variation', 'pos.import_multiplier', 'p.vat as id_vat')
->from('products_of_suppliers', 'pos')
->leftJoin('pos', 'products', 'p', 'pos.id_product=p.id')
->where(Operator::equals(['pos.id_supplier' => $this->stock_in['id_supplier']]));
if ($this->only_visible) {
$qb->andWhere(Operator::equals(['p.figure' => 'Y']));
}
$operators = array_map(function ($key, $value) {
if (is_array($value)) {
return Operator::inIntArray($value, "pos.{$key}");
}
return Operator::equals(["pos.{$key}" => $value]);
}, array_keys($mapping), $mapping);
$qb->andWhere(Operator::orX($operators));
$product = $qb->execute()->fetch();
if (!$product && $this->search_in_products) {
$qb = sqlQueryBuilder()->select('p.id AS id_product, pv.id AS id_variation')
->fromProducts()
->joinVariationsOnProducts();
$productsMapping = array_merge(
Mapping::mapKeys($mapping, function ($key, $value) {return ["p.{$key}", $value]; }),
Mapping::mapKeys($mapping, function ($key, $value) {return ["pv.{$key}", $value]; })
);
if (isset($productsMapping['pv.code']) && !findModule(Modules::PRODUCTS_VARIATIONS, Modules::SUB_CODE)) {
unset($productsMapping['pv.code']);
}
$operators = array_map(function ($key, $value) {
if (is_array($value)) {
return Operator::inStringArray($value, $key);
}
return Operator::equals([$key => $value]);
}, array_keys($productsMapping), $productsMapping);
$qb->andWhere(Operator::orX($operators));
if ($this->only_visible) {
$qb->andWhere(Operator::equals(['p.figure' => 'Y']));
}
$product = $qb->execute()->fetch();
if ($product) {
$product['import_multiplier'] = 1;
}
}
} else {
$product = null;
$mapping['code'] = translate('unknown');
$mapping['ean'] = translate('unknown');
}
if (!$product || $product['import_multiplier'] == 0) {
$product = ['id_product' => null, 'id_variation' => null, 'name' => "{$item['name']} (kód: {$mapping['code']}, ean: {$mapping['ean']})", 'import_multiplier' => 1, 'id_vat' => 0];
} else {
$product['name'] = null;
}
$product['id_stock_in'] = $this->stock_in['id'];
$product['quantity'] = round((float) $item['quantity'] * (float) $product['import_multiplier'] * (float) $this->multiple);
$product['vat'] = empty($item['vat']) ? getVat($product['id_vat']) : $item['vat'];
if (empty($item['price']) && !empty($item['price_with_vat'])) {
$price = toDecimal($this->preparePrice($item['price_with_vat']))->removeVat($product['vat']);
} else {
$price = toDecimal($this->preparePrice($item['price']));
}
// if isset price multiplier
if (isset($this->stock_in['multiplier'])) {
$price = $price->mul(toDecimal($this->stock_in['multiplier']));
}
unset($product['id_vat']);
if (isset($this->piece_price)) {
$product['price'] = $price;
} else {
$product['price'] = $product['quantity'] > 0 ? $price->div(toDecimal($product['quantity'])) : $price;
}
if ($this->insertSQL('stock_in_items', $product, ['import_multiplier']) <= 0) {
return $this->add_error('Cannot add '.print_r($product, true));
}
if ($product['id_product'] > 0 && !in_array($this->stockInIndex, ['future', 'preorder'])) {
$prod = new Product($product['id_product']);
$prod->storeIn($product['id_variation'], $product['quantity']);
}
$product['supplier_code'] = !empty($item['supplier_code']) ? trim($item['supplier_code']) : null;
$stockInData = getVal('data');
try {
$this->stockInProductOfSupplierService->updateOrInsertProductSupplier($product, $stockInData);
} catch (Exception|\Doctrine\DBAL\Driver\Exception) {
$this->add_error("Nepodařilo se uložit kód dodavatele '{$item['code']}' položky: {$item['name']}");
}
}
private function add_error($string)
{
$this->errors[] = $string;
return false;
}
}
if (!function_exists('json_last_error_msg')) {
function json_last_error_msg()
{
switch (json_last_error()) {
case JSON_ERROR_NONE:
return 'No errors';
case JSON_ERROR_DEPTH:
return 'Maximum stack depth exceeded';
case JSON_ERROR_STATE_MISMATCH:
return 'Underflow or the modes mismatch';
case JSON_ERROR_CTRL_CHAR:
return 'Unexpected control character found';
case JSON_ERROR_SYNTAX:
return 'Syntax error, malformed JSON';
case JSON_ERROR_UTF8:
return 'Malformed UTF-8 characters, possibly incorrectly encoded';
default:
return 'Unknown error';
}
}
}

View File

@@ -0,0 +1,742 @@
<?php
use KupShop\AdminBundle\AdminRegister\AdminRegisterLocator;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
class UserRights
{
private static $adminRegisterLocator;
public static function getAdminRegisterLocator(): AdminRegisterLocator
{
if (!isset(self::$adminRegisterLocator)) {
self::$adminRegisterLocator = ServiceContainer::getService(AdminRegisterLocator::class);
}
return self::$adminRegisterLocator;
}
public static function hasRights($type, $specific = '')
{
$item = self::getAdminRegisterLocator()->getPermissions($type) ?? getVal($type, self::$rights);
if (!$item) {
// logError(__FILE__, __LINE__, "Nonexisting user right: $type");
return true;
}
if (!empty($item['superadmin']) && !isSuperuser()) {
return false;
}
if (!empty($item['modules']) || !empty($item['submodules'])) {
$allow = false;
foreach ($item['modules'] ?? [] as $module) {
if (findModule($module)) {
$allow |= true;
}
}
foreach ($item['submodules'] ?? [] as $module => $submodule) {
if (findModule($module, $submodule)) {
$allow |= true;
}
}
if (!$allow) {
return false;
}
}
if (empty($item['rights'])) {
return true;
}
foreach ($item['rights'] as $right) {
if (substr($right, -1) == '_') {
if (findRight($right.$specific)) {
return true;
}
} elseif (findRight($right)) {
return true;
}
}
return false;
}
public static function isOnlySuperadmin($type)
{
$item = self::getAdminRegisterLocator()->getPermissions($type) ?? getVal($type, self::$rights);
if (!$item) {
return false;
}
if (!empty($item['superadmin']) && $item['superadmin'] === true) {
return true;
}
return false;
}
public function addRights($list, $rights = [])
{
self::$rights[$list] = $rights;
}
protected static $rights = [
'productsRelatedTypes' => [
'submodules' => [
Modules::PRODUCTS_RELATED => Modules::SUB_TYPES,
],
'superadmin' => true,
],
'products' => [
'modules' => [
'products',
],
'rights' => [
'PROD_',
],
],
'productsMassModification' => [
'modules' => [
'products',
],
'rights' => [
'PROD_EDIT',
'PROD_ERASE',
],
],
'parameters' => [
'modules' => [
'products_parameters',
],
'rights' => [
'PARAM',
],
],
'productsVarLabels' => [
'modules' => [
'products_variations',
],
'rights' => [
'VARIANT_LABELS',
],
],
'sections' => [
'modules' => [
'products_sections',
],
'rights' => [
'SEC_',
],
],
'producers' => [
'modules' => [
'producers',
],
'rights' => [
'PRODCR',
],
],
'orders' => [
'modules' => [
'orders',
],
'rights' => [
'ORDER_',
],
],
'ProductsSerialNumbers' => [
'modules' => [
'products_serial_numbers',
'stock_in',
],
'rights' => [
'PSERNUM',
],
],
'ProductsBatches' => [
'modules' => [
Modules::PRODUCTS_BATCHES,
Modules::WAREHOUSE,
],
'rights' => [
'PBATCHES',
],
],
'users' => [
'modules' => [
'eshop_users',
],
'rights' => [
'USR_',
],
],
'discounts' => [
'modules' => [
'order_discount',
],
'rights' => [
'DISCNT',
],
],
'ordersMassProcess' => [
'modules' => [
'orders_mass_process',
],
'rights' => [
'ORDER',
],
],
'photos' => [
'modules' => [
'photos',
],
'rights' => [
'PHOTOS_',
],
],
'fileBrowser' => [
'rights' => [
'FILE_BROWSER_USE',
],
],
'stockIn' => [
'modules' => [
'stock_in',
],
'rights' => [
'INSTORE_STOCKIN',
],
],
'suppliers' => [
'modules' => [
'products_suppliers',
'automatic_import',
'suppliers',
],
'rights' => [
'INSTORE_STOCKIN',
],
],
'stockInMissing' => [
'modules' => [
'missing_products',
],
'rights' => [
'INSTORE_MISSING',
],
],
'InfoPanelList' => [
'modules' => [
],
'rights' => [
'INFOPANEL',
],
],
'shopStore' => [
'modules' => [
],
'rights' => [
'MODULOVNA',
],
],
'ReturnDelivery' => [
'modules' => [
],
'rights' => [
'RETURNS',
],
],
'LabelsList' => [
'modules' => [
Modules::LABELS,
],
'rights' => [
'LABELS',
],
],
'templatesMenu' => [
'modules' => [
'templates',
],
'rights' => [
'PRODUCT_TEMPLATES',
],
],
'BonusProgramExchange' => [
'submodules' => [
Modules::BONUS_PROGRAM => Modules::SUB_POINTS_EXCHANGE,
],
'rights' => [
'BONUS_PROGRAM_EXCHANGE',
],
],
'Sales' => [
'modules' => [
Modules::SALES,
],
'rights' => [
'SALES',
],
],
'productsOfSuppliers' => [
'modules' => [
'stock_in',
'products_suppliers',
'suppliers',
],
'rights' => [
'INSTORE_STOCKIN',
],
],
'inventory' => [
'modules' => [
'inventory',
],
'rights' => [
'INVENTORY',
],
],
'productsPrices' => [
'submodules' => [
Modules::PRODUCTS => Modules::SUB_PRICE_BUY,
],
'rights' => [
'INVENTORY',
],
],
'stockManual' => [
'modules' => [
'stock_in',
],
'rights' => [
'INSTORE_STOCKIN',
],
],
'pages' => [
'modules' => [
'menulinks',
],
'rights' => [
'MENU_LINKS',
],
],
'menu' => [
'modules' => [
'menulinks',
],
'rights' => [
'MENU_LINKS',
],
],
'sliders' => [
'modules' => [
'sliders',
],
'rights' => [
'SLIDERS',
],
],
'articles' => [
'modules' => [
'articles',
],
'rights' => [
'ART_',
],
],
'artsections' => [
'modules' => [
'articles_sections',
],
'rights' => [
'ART_SEC_',
],
],
'articlesTags' => [
'modules' => [
'articles',
],
'rights' => [
'ART_',
],
],
'artauthors' => [
'modules' => [
Modules::ARTICLES_AUTHORS,
],
'rights' => [
'ART_AUTH_',
],
],
'dbbackup' => [
'modules' => [
'dbbackup',
],
'rights' => [
'OTH_BACKUP_',
],
],
'stats' => [
'modules' => [
'stats',
],
'rights' => [
'STAT',
],
],
'import-generic' => [
'modules' => [
'products',
],
'rights' => [
'IMPRT',
],
],
'import_automatic' => [
'modules' => [
'automatic_import',
],
'rights' => [
'IMPRT',
],
],
'import-xml_feed' => [
'modules' => [
'products',
],
'rights' => [
'IMPRT',
],
'superadmin' => true,
],
'import-xml_feed_new' => [
'modules' => [
'products',
],
'rights' => [
'IMPRT',
],
// 'superadmin' => true,
],
'orderPayment' => [
'modules' => [
'order_payment',
],
'rights' => [
'ORDER_PAYMENT',
'POS_',
],
],
'admins' => [
'modules' => [
],
'rights' => [
'OTH_ADM_',
],
],
'settings' => [
'modules' => [
],
'rights' => [
'OTH_SET_',
],
],
'delivery_type' => [
'modules' => [
'eshop_delivery',
],
'rights' => [
'DELVR',
],
],
'deliveryDelivery' => [
'modules' => [
'eshop_delivery',
],
'rights' => [
'DELVR',
],
],
'deliveryPayment' => [
'modules' => [
'eshop_delivery',
],
'rights' => [
'DELVR',
],
],
'vats' => [
'modules' => [
'products',
],
'rights' => [
'VAT',
],
],
'priceLevels' => [
'modules' => [
'price_levels',
],
'rights' => [
'PRICELEVELS',
],
],
'currencies' => [
'modules' => [
'currencies',
],
'rights' => [
'CURRENCY',
],
],
'automatic_import' => [
'modules' => [
'automatic_import',
],
'rights' => [
'IMPRT',
],
],
'export_orders' => [
'modules' => [
'orders',
],
'rights' => [
'EXPRT',
],
],
'export_products' => [
'modules' => [
'export',
],
'rights' => [
'EXPRT',
],
],
'export_selling_products' => [
'modules' => [
'orders',
],
'rights' => [
'EXPRT',
],
],
'export_users' => [
'modules' => [
'eshop_users',
],
'rights' => [
'EXPRT',
],
],
'ordersOfSuppliers' => [
'modules' => [
'orders_of_suppliers',
],
'rights' => [
'INSTORE_STOCKIN',
],
// 'superadmin' => true,
],
'replacement' => [
'modules' => [
'replacement',
],
'rights' => [
'ORDER_',
],
],
'templates' => [
'modules' => [
'templates',
],
'rights' => [
'PROD_',
],
],
'templatesCategories' => [
'modules' => [
'templates',
],
'rights' => [
'PROD_',
],
],
'templatesProducts' => [
'modules' => [
'templates',
],
'rights' => [
'PROD_',
],
],
'pos' => [
'rights' => [
'POS_',
],
'modules' => [
'new_pos',
],
],
'old_pos' => [
'rights' => [
'POS_',
],
'modules' => [
'pos',
],
],
'usersGroups' => [
'modules' => [
'eshop_users',
],
'rights' => [
'USER_GROUPS',
],
],
'cleaning' => [
'superadmin' => true,
],
'htmlComponents' => [
'superadmin' => true,
],
'languageCheckAdmin' => [
'superadmin' => true,
],
'balikonos' => [
'rights' => [
'ORDER_',
],
'modules' => [
'balikonos',
],
],
'balikobot' => [
'rights' => [
'BALIKOBOT',
],
],
'BalikonosOrders' => [
'rights' => [
'ORDER_',
],
'modules' => [
'balikonos',
],
],
'restrictions' => [
'rights' => [
'RESTR',
],
'modules' => [
'restrictions',
],
],
'reviews' => [
'rights' => [
'REVIEWS',
],
'modules' => [
'reviews',
],
],
'sellers' => [
'rights' => [
'SELLERS',
],
'modules' => [
'sellers',
'sellers_old',
],
],
'margins' => [
'rights' => [
'MARGINS',
],
'modules' => [
'margins',
],
],
'preOrders' => [
'rights' => [
'ORDER_',
],
],
'emails' => [
'modules' => [
'orders',
'forms',
],
'rights' => [
'OTH_EMAILS_',
],
],
'fulltext' => [
'modules' => [
'eshop_search',
],
'rights' => [
'FULLTEXT_SEARCH',
],
],
'translate' => [
'rights' => [
'TRANSLATE_',
],
],
'translationsStats' => [
'rights' => [
'TRANSLATE_',
],
],
'countries' => [
'rights' => [
'COUNTRY',
],
],
'languages' => [
'superadmin' => true,
'rights' => [
'LANGUAGE',
],
],
'feeds' => [
'modules' => [
'feeds',
],
'rights' => [
'FEEDS',
],
],
'pricelist' => [
'rights' => [
'PRICELISTS',
],
],
'invoices' => [
'modules' => [
'invoices',
],
'rights' => [
'ORDER_INVOICE', // fakturovat objednavky
'INVOICE', // spravovat fakturacni rady
],
],
'LlmPrompt' => [
'modules' => [
'llm',
],
'rights' => [
'LLM_',
],
],
];
}

View File

@@ -0,0 +1,735 @@
<?php
use Doctrine\DBAL\Types\Type;
use KupShop\AdminBundle\Admin\Actions\ActionsLocator;
use KupShop\AdminBundle\Event\WindowTabsEvent;
use KupShop\AdminBundle\Util\ActivityLog;
use KupShop\AdminBundle\Util\WindowTabLocator;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Logging\SentryLogger;
use Query\Operator;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class Window extends Frame
{
use DatabaseCommunication;
public const RIGHT_DELETE = 'delete';
public const RIGHT_DUPLICATE = 'duplicate';
public const RIGHT_SAVE = 'save';
protected $nameField = 'name';
protected $fields = [];
protected $defaults = [];
protected $required = [];
protected $types = [];
protected $uniques;
protected $tableName;
// Type of item to display on web
protected $show_on_web;
protected $action;
protected $ID;
protected $type;
protected $tabs;
protected $custom_data;
protected $processedData;
public function getTemplate()
{
if (empty($this->template)) {
$name = lcfirst($this->getClassName());
return "window/{$name}.tpl";
}
return $this->template;
}
public function createSQLFields($tablename)
{
$defaults = [];
$required = [];
$fields = [];
$types = [];
$conn = $this->getDbalConnection();
$tm = $conn->getSchemaManager();
$columns = $tm->listTableColumns($tablename);
foreach ($columns as $column) {
$name = $column->getName();
$fields[] = $name;
$defaults[$name] = $column->getDefault();
$required[$name] = ($column->getNotNull() && is_null($defaults[$name]));
$types[$name] = $column->getType()->getName();
}
$this->defaults = array_merge($defaults, $this->defaults);
$this->required = array_merge($required, $this->required);
$this->fields = array_merge($fields, $this->fields);
$this->types = array_merge($types, $this->types);
}
protected function collectVariables()
{
$acn = $this->getAction();
if ($acn == 'erased') {
return self::get_vars();
}
return $this->get_vars();
}
public function get_vars()
{
$vars = parent::get_vars();
$acn = $this->getAction();
$pageVars = [
'acn' => $acn,
];
$ID = $this->getID();
if (($acn == 'edit' && !empty($ID)) || $acn == 'add') {
if ($acn == 'edit' || ($acn == 'add' && $this->isDuplicate() && !empty($ID))) {
$pageVars['data'] = $this->getObject();
if (getVal('Submit')) {
$data = $this->getProcessedData();
$pageVars['data'] = array_merge($pageVars['data'], $data);
}
if (!empty($this->isDuplicate())) {
$this->getFields();
$this->duplicateObject($pageVars['data']);
$pageVars['duplicate'] = true;
}
} elseif ($acn == 'add') {
$pageVars['data'] = $this->createObject();
}
}
$vars['type'] = $this->getType();
$flap = getVal('flap', null, 1);
$vars['header']['flap'] = empty($flap) ? 1 : $flap;
$vars['header']['flap_next'] = getVal('flap_next');
$vars['header']['force_resize'] = getVal('force_resize');
$vars['tabs'] = $this->getTabs();
$vars['body'] = $pageVars;
$vars['actionsLocator'] = ServiceContainer::getService(ActionsLocator::class);
return $vars;
}
protected function getType()
{
if (empty($this->type)) {
$type = getVal('s');
if (!$type) {
$type = lcfirst($this->getClassName());
} else {
$type = substr($type, 0, -4);
}
$this->type = $type;
}
return $this->type;
}
public function setType($type)
{
$this->type = $type;
}
public function translateType()
{
// try to translate type to czech/english
$type = $this->getType();
// preferred:
// e.g. $txt_str['deliveryPriceLists']['navigation'] = 'Ceníky dopravy'
if ($typeName = translate('navigation', $type, true)) {
return $typeName;
}
// e.g. $txt_str['navigation']['deliveryDelivery'] = 'Dopravy'
if ($typeName = translate($type, 'navigation', true)) {
return $typeName;
}
return $type;
}
protected function getFields()
{
if (empty($this->fields)) {
$this->createSQLFields($this->getTableName());
}
}
protected function getUniques($table = null)
{
if (!is_null($this->uniques)) {
return $this->uniques;
}
if (empty($table)) {
$table = $this->getTableName();
}
$conn = $this->getDbalConnection();
$tm = $conn->getSchemaManager();
$indexes = $tm->listTableIndexes($table);
$this->uniques = [$this->nameField => true];
foreach ($indexes as $index) {
if ($index->isUnique() == true && $index->getName() != 'PRIMARY') {
if (isset($index->getColumns()[1])) {
$this->uniques[$index->getColumns()[1]] = true;
} else {
$this->uniques[$index->getName()] = true;
}
}
}
return $this->uniques;
}
public function getData()
{
$data = getVal('data', null, []);
if (!empty($data)) {
$data['ID'] = getVal('ID');
}
return $data;
}
/** Process all POSTed data from form. Transform data to SQL fields array */
public function processFormData()
{
return $this->getData();
}
final public function getProcessedData()
{
if (isset($this->processedData)) {
return $this->processedData;
}
return $this->processedData = $this->processFormData();
}
public function setCustomData($data)
{
$this->updateSQL($this->getTableName(), [
'data' => empty($data) ? null : json_encode($data),
], ['id' => $this->getID()]);
// reset custom data cache
$this->custom_data = null;
}
public function getCustomData()
{
if (empty($this->custom_data)) {
$object = $this->getObject();
$this->unserializeCustomData($object);
$this->custom_data = $object['data'];
}
return $this->custom_data;
}
public function getTableName()
{
if (empty($this->tableName)) {
$this->tableName = strtolower($this->getClassName());
}
return $this->tableName;
}
private function duplicateObject(&$data)
{
$uniques = $this->getUniques();
foreach ($uniques as $key => $value) {
if (isset($data[$key])) {
if ($this->required[$key] == false) {
$data[$key] = null;
} else {
$data[$key] = stringCopy(trim($data[$key]));
}
}
}
}
protected function createObject()
{
$data = $this->getData();
return array_merge($this->defaults, $data);
}
protected function getObject()
{
$object = $this->fetchObject($this->getTableName(), $this->getID());
if (!$object && $this->getAction() !== 'add') {
$errStr = sprintf(translate('errorNotFound', 'base'), $this->translateType(), $this->getID());
throw new NotFoundHttpException($errStr);
}
return $object;
}
public function getObjectData()
{
return $this->getObject();
}
// Vypisovani aktivit
protected function activityMessage($name, array $additionalData = [])
{
$acn = $this->getAction();
if ($acn == 'add') {
addActivityLog(ActivityLog::SEVERITY_NOTICE, ActivityLog::TYPE_CHANGE, sprintf(translate('activityAdded'), $name),
[
...ActivityLog::addObjectData([$this->getID() => $name], $this->getType()),
...$additionalData,
]);
} elseif ($acn == 'edit') {
addActivityLog(ActivityLog::SEVERITY_NOTICE, ActivityLog::TYPE_CHANGE, sprintf(translate('activityEdited'), $name),
[
...ActivityLog::addObjectData([$this->getID() => $name], $this->getType()),
...$additionalData,
]);
}
}
protected function getAdditionalActivityData(): array
{
return [];
}
public function handle()
{
try {
$acn = $this->getAction();
$ID = $this->getID();
if ($acn == 'add') {
$this->tryRights('ADD');
}
if ($acn == 'edit') {
$this->tryRights('EDIT');
}
if ((($acn == 'edit' && (strlen($ID) > 0)) || $acn == 'add') && getVal('Submit')) {
$data = $this->getProcessedData();
$missing = $this->checkRequired($data);
if (!$missing) {
$activityAdditionalData = $this->getAdditionalActivityData();
$SQL = $this->handleUpdate();
if ($SQL) {
if ((empty($this->getErrors()) && empty($this->getHTMLErrors())) || $acn == 'add') {
if (isset($data[$this->nameField])) {
$this->activityMessage($data[$this->nameField], $activityAdditionalData);
}
$this->returnOK();
}
} else {
$ErrStr = getTextString('status', 'scripterror');
$this->returnError($ErrStr);
}
} else {
$ErrStr = getTextString('base', 'errorNotAllValid');
$ErrStr .= join(',', $missing);
$this->addError($ErrStr);
}
} elseif ($acn == 'erase' && !empty($ID)) {
$this->tryRights('ERASE');
$this->handleDelete();
} else {
$this->handleTabs();
parent::handle();
}
} catch (Doctrine\DBAL\DBALException $e) {
$this->handleException($e);
}
}
public function handleException($e)
{
if (intval($e->getPrevious()->errorInfo[1]) === 1062) {
$ErrStr = 'Duplicitní ';
$badFields = $this->getBadValues($this->getTableName(), ['id' => $this->ID]);
foreach ($badFields as $value) {
$ErrStr .= '{'.$value.'} ';
}
if (!$badFields) {
$ErrStr = "Duplicitní záznam: \n".$e->getMessage();
}
$this->addError($ErrStr);
} elseif (intval($e->getPrevious()->getCode()) === 45000) {
$msg = $e->getPrevious()->getMessage();
$this->addError(mb_substr($msg, mb_strpos($msg, 'EAN')));
} elseif (in_array(intval($e->getPrevious()->getErrorCode()), [1205, 1213])) {
$this->addError('Chyba při zpracování požadavku. Zkuste to prosím znovu.');
$sentryLogger = ServiceContainer::getService(SentryLogger::class);
$data = json_encode($this->getAllSQLProcesses());
$sentryLogger->captureException(new Exception('Deadlock v administraci!', 1205, $e), ['extra' => ['processes' => $data]]);
} else {
throw $e;
}
}
// Kontroluje, jestli v datech z formulare jsou vsechny povinne polozky
public function checkRequired($data)
{
$this->getFields();
$required = [];
foreach ($data as $key => $value) {
if (!is_array($value)) {
$value = trim($value);
}
if (isset($this->required[$key])
&& $this->required[$key] == true
&& $value === ''
&& ((@$this->types[$key] != 'string' && @$this->types[$key] != 'simple_array' && @$this->types[$key] != 'text') || $key == $this->nameField)
) {
$required[] = $key;
}
}
return $required;
}
// Obecna funkce pro update & insert
public function handleUpdate()
{
$acn = $this->getAction();
$SQL = null;
if ($acn == 'add') {
$sqlFields = $this->getSQLFields();
$this->insertSQL($this->getTableName(), $sqlFields);
$SQL = true;
if (empty($ID)) {
if (isset($sqlFields['id'])) {
$this->setID($sqlFields['id']);
} else {
$this->setID(sqlInsertID());
}
}
} elseif ($acn == 'edit') {
$sqlFields = $this->getSQLFields();
$this->updateSQL($this->getTableName(), $sqlFields, ['id' => $this->getID()]);
if (isset($sqlFields['id'])) {
$this->setID($sqlFields['id']);
}
$SQL = true;
}
// reset custom data cache
$this->custom_data = null;
$this->handleTabs(true);
return $SQL;
}
public function forceUpdate()
{
try {
// get actual action
$action = $this->getAction();
// change action to edit
$this->action = 'edit';
// do update
$_REQUEST['Submit'] = 'OK';
$this->createSQLFields($this->getTableName());
$result = $this->handleUpdate();
// return action
$this->action = $action;
return $result;
} catch (Doctrine\DBAL\DBALException $e) {
$this->handleException($e);
return false;
}
}
public function getIdFromDatabase($field)
{
$id = returnSQLResult('SELECT id FROM '.getTableName($this->getTableName())." WHERE {$field[0]}='{$field[1]}' ");
return $id;
}
public function getSQLFields($data = null, $fields = null, $defaults = null, $types = null)
{
if ($data == null) {
$data = $this->getProcessedData();
}
if ($fields == null) {
$fields = $this->fields;
}
if ($defaults == null) {
$defaults = $this->defaults;
}
if ($types == null) {
$types = $this->types;
}
$sqlField = [];
foreach ($fields as $row) {
if (array_key_exists($row, $data) && !is_array($data[$row])) {
if (!is_null($data[$row])) {
$data[$row] = trim($data[$row]);
}
if (array_key_exists($row, $types)) {
$type = $types[$row];
if (($type == Type::DECIMAL) || ($type == Type::FLOAT)) {
$this->preparePrice($data[$row]);
}
}
if (isset($data[$row]) && ($data[$row] === '') && (@$defaults[$row] === null) && @!$this->required[$row]) {
$sqlField[$row] = null;
} else {
$sqlField[$row] = $data[$row];
}
}
}
return $sqlField;
}
// Smazani polozky
public function handleDelete()
{
if ($this->nameField) {
$name = sqlQueryBuilder()->select($this->nameField)->from($this->getTableName())
->andWhere(Operator::equals(['id' => $this->getID()]))
->execute()->fetchOne();
if ($logMessage = translate('activityDeleted', $this->getType(), true)) {
$logMessage = sprintf($logMessage, $name);
} else {
$logMessage = translate('activityDeleted', 'status'); // 'Deleted %s: %s'
$logMessage = sprintf($logMessage, $this->getType(), $name);
}
}
try {
$res = sqlQueryBuilder()->delete($this->getTableName())
->andWhere(Operator::equals(['id' => $this->getID()]))
->execute();
if ($res && !empty($logMessage)) {
addActivityLog(ActivityLog::SEVERITY_WARNING, ActivityLog::TYPE_CHANGE, $logMessage);
}
} catch (Doctrine\DBAL\DBALException $e) {
switch (intval($e->getPrevious()->errorInfo[1])) {
case 1451:
$ErrStr = 'Tento objekt je použit a nelze ho smazat.';
$this->returnError($ErrStr);
break;
default:
$this->handleException($e);
}
}
throw new \KupShop\KupShopBundle\Exception\RedirectException("launch.php?s={$this->getName()}.php&acn=erased");
}
public function hasRights($name = null)
{
switch ($name) {
case self::RIGHT_DUPLICATE:
if ($this->getAction() == 'edit' && $this->getID() != null) {
return true;
}
break;
case self::RIGHT_SAVE:
// Kdyz mam READ a nemam EDIT, tak nezobrazim save button
if (UserRights::hasRights($this->getRightsType(), 'READ') && !UserRights::hasRights($this->getRightsType(), 'EDIT')) {
return false;
}
return true;
default:
return true;
}
return true;
}
public function getBadValues($table = null, $rowIdentifier = [])
{
if (!empty($table)) {
$uniques = $this->getUniques($table);
} else {
$table = $this->getTableName();
$uniques = [];
}
$where = '';
foreach ($rowIdentifier as $key => $value) {
$where .= " AND {$key}!=:{$key}";
}
$data = $this->getData();
$badFields = [];
foreach ($uniques as $key => $value) {
if ($value) {
if (isset($data[$key])) {
$SQL = returnSQLResult('SELECT COUNT(*) FROM '.getTableName($table)." WHERE {$key}=:{$key} {$where}",
array_merge($data, $rowIdentifier));
if ($SQL > 0) {
$badFields[] = $key;
}
}
}
}
return $badFields;
}
public function redirect($params = [])
{
parent::redirect(array_merge(['ID' => $this->getID(), 'acn' => 'edit'], $params));
}
public function getShowOnWeb()
{
if ($this->show_on_web == null) {
return false;
}
if ($this->getID() === null) {
return null;
}
return ['type' => $this->show_on_web, 'id' => $this->getID()];
}
public function getNameField()
{
return $this->nameField;
}
public function handleTabs($update = false)
{
$tabs = $this->getTabs();
foreach ($tabs as $tab) {
$tab->setID($this->getID());
if ($update) {
$tab->handleUpdate();
// reset custom data cache
$this->custom_data = null;
} else {
$tab->handle();
}
}
}
/**
* Return WindowTabs.
*/
protected function getTabs()
{
if (!is_null($this->tabs)) {
return $this->tabs;
}
$windowTabLocator = ServiceContainer::getService(WindowTabLocator::class, 0);
$dispatcher = ServiceContainer::getService('event_dispatcher');
$tabsEvent = new WindowTabsEvent();
$dispatcher->dispatch($tabsEvent, WindowTabsEvent::NAME_PREFIX.$this->getType());
$tabs = array_merge(
$windowTabLocator ? $windowTabLocator->getTabs($this->getType()) : [],
$tabsEvent->getTabs()
);
foreach ($tabs as &$tab) {
$tab->setWindow($this);
}
return $this->tabs = $tabs;
}
public function handleGetActionSnippet()
{
$actionName = getVal('action');
/** @var $massActionsLocator ActionsLocator */
$actionsLocator = ServiceContainer::getService(ActionsLocator::class);
$action = $actionsLocator->getServiceByActionClassName($actionName);
$smarty = createSmarty(true, true);
$smarty->assign($action->getVars());
$smarty->display($action->getTemplate());
exit;
}
public function handleExecuteAction()
{
$actionName = getVal('action');
/** @var $massActionsLocator ActionsLocator */
$actionsLocator = ServiceContainer::getService(ActionsLocator::class);
$action = $actionsLocator->getServiceByActionClassName($actionName);
$action->setWindow($this);
$data = $this->getData();
$result = $action->execute($data, getVal('config', $_POST, []), $this->getType());
if ($result->isSuccessful()) {
if ($result->getHTMLMessage()) {
$this->action = 'edit';
$this->addHTMLError($result->getHTMLMessage());
return;
}
$params = ['action' => null];
if ($result->getRedirect()) {
$params = array_merge($params, $result->getRedirect());
}
$this->returnOK(!empty($result->getMsg()) ? $result->getMsg() : ('Akce ['.$action->getName().'] byla provedena.'),
false,
$params);
} else {
$this->redirect(['acn' => 'edit',
'action' => null,
'ErrStr' => !empty($result->getMsg()) ? $result->getMsg() : ('Akce ['.$action->getName().'] se nezdařila.')]);
}
}
protected function getAllSQLProcesses()
{
return sqlQuery('SHOW FULL PROCESSLIST')->fetchAllAssociative();
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {find_module} plugin.
*
* Type: function<br>
* Name: url<br>
* Purpose: finding module
*
* @param array $params parameters
* @param Smarty_Internal_Template $smarty
*
* @return string
*/
function smarty_function_find_module($params, &$smarty)
{
return findModule($params['name']);
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {find_right} plugin.
*
* Type: function<br>
* Name: url<br>
* Purpose: finding rights
*
* @param array $params parameters
* @param Smarty_Internal_Template $smarty
*
* @return string
*/
function smarty_function_find_right($params, &$smarty)
{
$var = null;
$name = '';
extract($params);
if (empty($name)) {
throw new InvalidArgumentException('find_right: \'name\' parameter empty');
}
return findRight($name, $var);
}

View File

@@ -0,0 +1,27 @@
<?php
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\OrderingBundle\Util\Order\OrderInfo;
/**
* Smarty plugin.
*/
function smarty_function_get_named_vats($params, &$smarty)
{
if (!isset($params['vats'])) {
throw new InvalidArgumentException('Parameter \'vats\' is required!');
}
if (!is_array($params['vats'])) {
throw new InvalidArgumentException('Parameter \'vats\' must be of type array!');
}
$orderInfo = ServiceContainer::getService(OrderInfo::class);
$namedVats = $orderInfo->getNamedVats($params['vats']);
if (!empty($params['assign'])) {
$smarty->assign($params['assign'], $namedVats);
} else {
return $namedVats;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {get_statuses} plugin.
*
* Type: function<br>
* Name: url<br>
* Purpose: get statuses
*
* @param array $params parameters
* @param Smarty_Internal_Template $smarty
*
* @return string
*/
function smarty_function_get_statuses($params, &$smarty)
{
$statuses = getStatuses($params['name']);
if (!empty($params['assign'])) {
$smarty->assign($params['assign'], $statuses);
} else {
return $statuses;
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {get_statuses} plugin.
*
* Type: function<br>
* Name: url<br>
* Purpose: get statuses
*
* @param array $params parameters
* @param Smarty_Internal_Template $smarty
*
* @return string
*/
function smarty_function_get_today_selled_items($params, &$smarty)
{
$last_item = end($params['items']);
if (empty($last_item['date'])) {
return $params['items'];
}
$last_datetime = (new DateTime($last_item['date']))->modify('-1 hours');
$items = [];
foreach ($params['items'] as $item) {
$datetime = new DateTime($item['date']);
if ($last_datetime < $datetime) {
$items[] = $item;
}
}
if (empty($items)) {
return $params['items'];
}
if (!empty($params['assign'])) {
$smarty->assign($params['assign'], $items);
} else {
return $items;
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {get_user} plugin.
*
* Type: function<br>
* Name: get_user<br>
* Purpose: get User ID
*
* @return number
*/
function smarty_function_get_user($params, &$smarty)
{
if (!empty($GLOBALS['adminID'])) {
return $GLOBALS['adminID'];
} else {
return '';
}
}

View File

@@ -0,0 +1,17 @@
<?php
function smarty_function_helpscout_beacon_identity()
{
$admin = getAdminUser();
return json_encode([
'name' => $admin['name'] ?? $admin['login'],
'email' => $admin['email'],
'company' => getShopUniqueName(),
'signature' => hash_hmac(
'sha256',
$admin['email'],
'MjodsaAdWfVlVXSiOnas0qgE7CQzbRrdjTEEXLR0RUY='
),
]);
}

View File

@@ -0,0 +1,25 @@
<?php
function smarty_function_insert_autocomplete_form($params, $smarty)
{
static $instance = 0;
$defaults = [
'instance' => $instance,
];
$params = array_merge($defaults, $params);
$requiredParams = ['type', 'searchInput', 'inputName', 'items'];
foreach ($requiredParams as $requiredParam) {
if (!array_key_exists($requiredParam, $params)) {
throw new InvalidArgumentException(
sprintf('Missing required parameter "%s"', $requiredParam)
);
}
}
echo $smarty->_subTemplateRender('autocomplete-form/'.$params['type'].'.tpl', $smarty->cache_id, $smarty->compile_id, 0, null, $params, 0, false);
$instance++;
}

View File

@@ -0,0 +1,118 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {insert_calendar} plugin.
*
* Type: function<br>
* Name: url<br>
* Purpose: insert calendar to field
*
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
*
* @return string
*/
function smarty_function_insert_calendar($params, $template)
{
$selector = null;
$format = 'date';
$figureFormat = true;
$czechformat = '';
$used = false;
extract($params);
if (empty($selector)) {
throw new InvalidArgumentException('insert_calendar: \'selector\' parameter empty');
}
echo openCalenderButton($selector, $format, $figureFormat, $czechformat, $used);
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
function openCalenderButton($selector, $dateFormat, $figureFormat = true, $czechformat = null, $param_used = false)
{
global $cfg;
static $used = false;
$used = $used || $param_used;
/*$format = "dd-mm-yy";
$timeFormat = "";
if ($dateFormat == 'datetime')
$timeFormat = "hh:mm:ss";
*/
// if (!empty($czechformat)){
$format = calendarDateFormat();
$timeFormat = '';
if ($dateFormat == 'datetime') {
$timeFormat = calendarTimeFormat();
}
// }
$ret = "<script>
$(function(){
openCalenderIFrame('{$selector}', '{$format}', '{$timeFormat}');
});
</script>";
if (!$used) {
$used = true;
$ret .= '<script src="./static/js/jquery.datetimepicker.js"></script>';
$ret .= '<script src="./static/js/jquery-ui.datepicker-cs.js"></script>';
}
return $ret;
}
function calendarDateFormat()
{
$dbcfg = Settings::getDefault();
switch ($dbcfg['date_format']) {
case '%e.%c.%y':
return 'd.m.y';
break;
case '%d.%m.%Y':
return 'dd.mm.yy';
break;
case '%d/%m/%Y':
return 'dd/mm/yy';
break;
case '%d/%m/%y':
return 'dd/mm/y';
break;
case '%e.%c.%Y':
default:
return 'd.m.yy';
break;
}
}
function calendarTimeFormat()
{
$dbcfg = Settings::getDefault();
switch ($dbcfg['time_format']) {
case '%k:%i:%s':
return 'h:mm:ss';
break;
case '%H:%i':
return 'hh:mm';
break;
case '%k:%i':
return 'h:mm';
break;
case '%H:%i:%s':
default:
return 'hh:mm:ss';
break;
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {insert_file_browse} plugin.
*
* Type: function<br>
* Name: url<br>
* Purpose: insert file browser
*
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
*
* @return string
*/
function smarty_function_insert_file_browse($params, $template)
{
static $inserted = false;
if (!$inserted) {
?>
<script src="/web/bundles/cksourceckfinder/ckfinder/ckfinder.js"></script>
<script type="application/javascript">
CKFinder.config({connectorPath: '/ckfinder/connector'});
CKFinder.basePath = '/web/bundles/cksourceckfinder/ckfinder/';
//############### BROWSE FILES #####################//
$(document).on('click', '[data-file-browse]', function () {
var $input = $(this).closest('.input-group').find('input');
if (!$input)
return true;
CKFinder.popup({
language: 'cs',
resourceType: 'Soubory',
chooseFiles: true,
width: 800,
height: 600,
onInit: function (finder) {
finder.config.resourceType = 'Soubory';
finder.on('files:choose', function (evt) {
var file = evt.data.files.first();
$input.val(decodeURIComponent(file.getUrl()));
$input.change();
});
},
});
return false;
});
</script>
<?php
$inserted = true;
} ?>
<a class="btn btn-primary btn-sm" data-file-browse href="#" title="<?php echo getTextString('products', 'findFile'); ?>">
<span class="glyphicon glyphicon-folder-open"></span>
</a>
<?php
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {insert_llm_button} plugin.
*
* Purpose: Insert llm button
*
* @param array $params parameters
* @param Smarty_Internal_Template $smarty template object
*
* @return string
*/
function smarty_function_insert_llm_button($params, $smarty)
{
if (!findModule(Modules::LLM)) {
return;
}
$textObjectUtil = \KupShop\KupShopBundle\Util\Compat\ServiceContainer::getService(\KupShop\LLMBundle\Util\TextObjectUtil::class);
$params['actions'] = [];
foreach ($textObjectUtil->getObjectLabelPrompts($params['type']) as $id => $prompt) {
$json = [
'entityType' => $params['entityType'] ?? substr(getVal('s'), 0, -4),
'entityId' => $params['entityId'] ?? getVal('ID'),
'target' => $params['target'],
'promptId' => $id,
'objectLabel' => $params['type'] ?? '',
'title' => $prompt->getTitle(),
];
$params['actions'][] = [
'id' => $id,
'title' => $prompt->getTitle(),
'json' => $json,
];
}
echo $smarty->_subTemplateRender('llm/text-dropdown.tpl', $smarty->cache_id, $smarty->compile_id, 0, null, $params, 0, false);
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {insert_wysiwyg} plugin.
*
* Type: function<br>
* Name: url<br>
* Purpose: insert wysiwyg editor
*
* @param array $params parameters
* @param Smarty_Internal_Template $smarty template object
*
* @return string
*/
function smarty_function_insert_wysiwyg($params, $smarty)
{
static $index = 0;
$defaults = [
'type' => 'BasicTable',
'index' => $index,
];
$params = array_merge($defaults, $params);
if (empty($params['target'])) {
throw new InvalidArgumentException('insert_wysiwyg: \'target\' parameter empty');
}
echo $smarty->_subTemplateRender('utils/wysiwyg.tpl', $smarty->cache_id, $smarty->compile_id, 0, null, $params, 0, false);
$index++;
}

View File

@@ -0,0 +1,14 @@
<?php
function smarty_function_print_delivery_settings($params, &$smarty)
{
if (!empty($params['template'])) {
$_smarty_tpl_vars = $smarty->tpl_vars;
echo $smarty->_subTemplateRender($params['template'], $smarty->cache_id, $smarty->compile_id, 0, null, $params, 0, false);
$smarty->tpl_vars = $_smarty_tpl_vars;
}
if (!empty($params['assign'])) {
$smarty->assign($params['assign'], $params);
}
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {print_select} plugin.
*
* Type: function<br>
* Name: url<br>
* Purpose: print select
*
* @param array $params parameters
* @param Smarty_Internal_Template $smarty
*
* @return string
*/
function smarty_function_print_select($params, &$smarty)
{
$name = '';
$var = [];
$selected = '';
$param = '';
$class = 'selecter';
$keep_value = false;
extract($params);
if (!is_array($selected)) {
$selected = [$selected => true];
}
if ($keep_value) {
foreach ($selected as $key => $value) {
if (!array_key_exists($key, $var)) {
$var[$key] = $key;
}
}
} ?>
<select class="<?php echo $class; ?>" data-filter-type="<?php echo (strpos($param, 'multiple') !== false) ? 'multiselect' : 'select'; ?>" name="<?php echo $name; ?>" <?php echo $param; ?>>
<?php
foreach ($var as $index => $value) {
?>
<option value="<?php echo $index; ?>"
<?php echo (isset($selected[$index]) && ($selected[$index] || $selected[$index] == '0')) ? 'selected' : ''; ?>>
<?php echo $value; ?>
</option>
<?php
} ?>
</select>
<?php
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {print_toggle} plugin.
*
* Type: function<br>
* Name: url<br>
* Purpose: print toggle with hidden button for get Y/N value
*
* @param array $params parameters
* @param Smarty_Internal_Template $smarty
*
* @return string
*/
function smarty_function_print_toggle($params, &$smarty)
{
$name = null;
$nameRaw = null;
$disabled = null;
$class = '';
$attrs = '';
$value = null;
$numeric = false;
$onOff = false;
extract($params);
if (empty($name) && empty($nameRaw)) {
throw new InvalidArgumentException('print_toggle: \'name\' parameter empty');
}
if (is_null($value)) {
$data = $smarty->getTemplateVars('body');
if (!empty($data['data'])) {
$data = $data['data'];
}
$value = getVal($name, $data);
}
$class .= ' toggle';
if ($disabled) {
$attrs .= ' disabled ';
}
if ($value == 'Y' || $value == '1') {
$attrs .= 'checked="checked" ';
}
$attrName = $name ? "data[{$name}]" : $nameRaw;
if ($onOff) {
$valueTrue = 'ON';
$valueFalse = 'OFF';
} else {
$valueTrue = $numeric ? 1 : 'Y';
$valueFalse = $numeric ? 0 : 'N';
}
$ret = "<input type='hidden' name='{$attrName}' value='{$valueFalse}'/>
<label class='{$class}'><input name='{$attrName}' type='checkbox' {$attrs} value='{$valueTrue}'/>
<span class=\"handle\"></span></label>";
return $ret;
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {format_date} function plugin.
*/
function smarty_modifier_format_date($string, $value = null)
{
if (empty($string)) {
return '';
} else {
$datetime = new DateTime($string);
}
return $datetime->format(Settings::getDateFormat());
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {format_datetime} function plugin.
*/
function smarty_modifier_format_datetime($string, $value = null)
{
if ($string == '-0001-11-30') {
return '00-00-0000';
} elseif ($string instanceof \DateTime) {
$datetime = $string;
} elseif (empty($string)) {
return '';
} else {
$datetime = new DateTime($string);
}
$format = Settings::getDateFormat().' '.Settings::getTimeFormat();
return $datetime->format($format);
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* Smarty plugin.
*/
/**
* Smarty {format_editable_price} function plugin.
*
* @param Decimal $decimal - value to format
* @param null $precision - how many decimal places to use. Use negative numbers to pretty print rounded values (strip trailing zeros)
*
* @return string
*/
function smarty_modifier_format_editable_price(Decimal $decimal, $precision = null)
{
return $decimal->printFloatValue($precision ?: 2);
}