1074 lines
42 KiB
PHP
1074 lines
42 KiB
PHP
<?php
|
|
|
|
use KupShop\AdminBundle\Util\ActivityLog;
|
|
use KupShop\AdminBundle\Util\AdminSectionTree;
|
|
use KupShop\CatalogBundle\Event\ProductEvent;
|
|
use KupShop\CatalogBundle\Search\FulltextInterface;
|
|
use KupShop\KupShopBundle\Config;
|
|
use KupShop\KupShopBundle\Context\VatContext;
|
|
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
|
use KupShop\KupShopBundle\Util\Contexts;
|
|
use KupShop\KupShopBundle\Util\EANValidator;
|
|
use KupShop\KupShopBundle\Util\StringUtil;
|
|
use KupShop\OrderingBundle\Util\Discount\DiscountGenerator;
|
|
use Query\Operator;
|
|
|
|
class Products extends Window
|
|
{
|
|
private AdminSectionTree $adminSectionTree;
|
|
protected $nameField = 'title';
|
|
protected $show_on_web = 'product';
|
|
protected $required = ['title' => true];
|
|
|
|
public function __construct()
|
|
{
|
|
$this->adminSectionTree = ServiceContainer::getService(AdminSectionTree::class);
|
|
}
|
|
|
|
public function get_vars()
|
|
{
|
|
$cfg = \KupShop\KupShopBundle\Config::get();
|
|
$vars = parent::get_vars();
|
|
$ID = $this->getID();
|
|
|
|
$pageVars = getVal('body', $vars, []);
|
|
|
|
$pageVars['vats'] = VatContext::getAdminVats();
|
|
|
|
// backward compatibility
|
|
if (!isset($pageVars['vats'][$pageVars['data']['vat']])) {
|
|
$pageVars['vats'][$pageVars['data']['vat']] = VatContext::getAdminVats(true)[$pageVars['data']['vat']];
|
|
}
|
|
|
|
if (findModule(Modules::PRODUCTS, Modules::SUB_UNITS)) {
|
|
$qb = sqlQueryBuilder()->select('id, short_name_admin')->from('products_units')
|
|
->orderBy('id');
|
|
|
|
if (findModule(Modules::PRODUCTS, Modules::SUB_UNITS_FLOAT)) {
|
|
$qb->addSelect('pieces_precision');
|
|
}
|
|
foreach ($qb->execute() as $units) {
|
|
$pageVars['units'][$units['id']] = $units['short_name_admin'];
|
|
if (findModule(Modules::PRODUCTS, Modules::SUB_UNITS_FLOAT)) {
|
|
$pageVars['units_pieces_precision'][$units['id']] = $units['pieces_precision'];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (findModule(Modules::PRODUCTS_CHARGES)) {
|
|
$SQL = sqlQuery('SELECT *, IF(admin_title!="", admin_title, title) as title FROM charges WHERE type="product" ORDER BY id ASC ');
|
|
$pageVars['charges'] = sqlFetchAll($SQL, ['id' => 'title']);
|
|
}
|
|
|
|
if (!empty($pageVars['data']['producer'])) {
|
|
$pageVars['producer'] = $this->selectSQL('producers', ['id' => $pageVars['data']['producer']], ['name'])->fetch();
|
|
}
|
|
|
|
$pageVars['POSITION_FIRST'] = POSITION_FIRST;
|
|
$pageVars['POSITION_LAST'] = POSITION_LAST;
|
|
$pageVars['positions'] = [POSITION_FIRST => 'Vpředu', '' => 'Standardní řazení', POSITION_LAST => 'Vzadu', '-1' => 'Konkrétní pozice'];
|
|
$pageVars['parameters'] = [];
|
|
|
|
// missing parameters
|
|
$productSections = array_keys(sqlFetchAll($this->selectSQL('products_in_sections', ['id_product' => $ID]), 'id_section'));
|
|
$sectionsMissingParameters = 0;
|
|
$producersMissingParameters = 0;
|
|
$sectionsRequiredParameters = [];
|
|
$producersRequiredParameters = [];
|
|
if (!empty($productSections)) {
|
|
$sectionsRequiredParameters = sqlFetchAll(
|
|
sqlQueryBuilder()
|
|
->select('id_parameter')
|
|
->from('parameters_sections')
|
|
->where(\Query\Operator::inIntArray($productSections, 'id_section'))
|
|
->andWhere(Operator::equals(['required' => 'Y']))
|
|
->groupBy('id_parameter')
|
|
->execute(),
|
|
'id_parameter'
|
|
);
|
|
|
|
$qb = sqlQueryBuilder()->select('('.count($sectionsRequiredParameters).' - COUNT(DISTINCT id_parameter))')
|
|
->from('parameters_products')
|
|
->where(\Query\Operator::inIntArray(array_keys($sectionsRequiredParameters), 'id_parameter'))
|
|
->andWhere(\Query\Operator::equals(['id_product' => $ID]))
|
|
->execute();
|
|
|
|
$sectionsMissingParameters = $qb->fetchColumn();
|
|
}
|
|
|
|
if (findModule(Modules::PRODUCERS) && !empty($pageVars['data']['producer'])) {
|
|
$producersRequiredParameters = sqlFetchAll(
|
|
sqlQueryBuilder()
|
|
->select('id_parameter')
|
|
->from('parameters_producers')
|
|
->where(\Query\Operator::equals(['id_producer' => $pageVars['data']['producer']]))
|
|
->groupBy('id_parameter')
|
|
->execute(),
|
|
'id_parameter'
|
|
);
|
|
|
|
$producersMissingParameters = sqlQueryBuilder()->select('('.count($producersRequiredParameters).' - COUNT(DISTINCT id_parameter))')
|
|
->from('parameters_products')
|
|
->where(\Query\Operator::inIntArray(array_keys($producersRequiredParameters), 'id_parameter'))
|
|
->andWhere(\Query\Operator::equals(['id_product' => $ID]))
|
|
->execute()->fetchColumn();
|
|
}
|
|
|
|
$missingParameters = max(0, $producersMissingParameters + $sectionsMissingParameters);
|
|
$pageVars['missingParameters'] = [
|
|
'count' => $missingParameters,
|
|
'required' => !empty($sectionsRequiredParameters) || !empty($producersRequiredParameters),
|
|
];
|
|
|
|
if (!empty($ID)) {
|
|
if (findModule('links')) {
|
|
$SQL = sqlQueryBuilder()->select('*')
|
|
->from('links', 'pis')
|
|
->where(Operator::equals(['id_product' => $ID]))
|
|
->execute();
|
|
$pageVars['links'] = [];
|
|
foreach ($SQL as $key => $row) {
|
|
$pageVars['links'][$key] = $row;
|
|
}
|
|
}
|
|
|
|
if (findModule('attachments')) {
|
|
$SQL = sqlQueryBuilder()->select('*')
|
|
->from('attachments')
|
|
->where(\Query\Operator::equals(['id_product' => $ID]))
|
|
->orderBy('position', 'ASC')
|
|
->execute();
|
|
|
|
$pageVars['attachments'] = [];
|
|
foreach ($SQL as $key => $row) {
|
|
$pageVars['attachments'][$key] = $row;
|
|
}
|
|
}
|
|
|
|
if (findModule('photos')) {
|
|
$product_photos = sqlQueryBuilder()->select('*')
|
|
->from('photos_products_relation')
|
|
->where(\Query\Operator::equals(['id_product' => $ID]))
|
|
->execute()->fetchAll();
|
|
$pageVars['product_photos'] = $product_photos;
|
|
}
|
|
|
|
$product = new Product($ID);
|
|
$pageVars['sets'] = $product->fetchSets(true);
|
|
foreach ($pageVars['sets'] as &$set) {
|
|
$set->fetchImages('admin');
|
|
$set->fetchVariations();
|
|
$variations = false;
|
|
if (!empty($set['variations']['variations'])) {
|
|
$variations = [];
|
|
foreach ($set['variations']['variations'] as $variation) {
|
|
$selected = false;
|
|
if ($variation['id'] == $set['selected_variation']) {
|
|
$selected = true;
|
|
}
|
|
$variations[] = ['label' => $variation['title'], 'value' => $variation['id'], 'selected' => $selected];
|
|
}
|
|
}
|
|
$set['variations'] = $variations;
|
|
}
|
|
|
|
if (findModule(\Modules::PRODUCTS_COLLECTIONS)) {
|
|
$pageVars['collections'] = $product->fetchCollections(false);
|
|
if (!empty($pageVars['collections']['own'])) {
|
|
foreach ($pageVars['collections']['own'] as &$collection) {
|
|
$collection->fetchImages('admin');
|
|
}
|
|
}
|
|
}
|
|
|
|
if (findModule(Modules::PRODUCTS_CHARGES)) {
|
|
// Příplatky
|
|
$pageVars['data']['products_charges'] = $product->fetchCharges(onlyVisible: false);
|
|
}
|
|
|
|
$variations = sqlFetchAssoc(sqlQuery('SELECT COUNT(*) AS cnt, MAX(price) price FROM products_variations WHERE id_product=:id', ['id' => $ID]));
|
|
$pageVars['variationCount'] = $variations['cnt'];
|
|
$pageVars['variationPrice'] = $variations['price'];
|
|
|
|
$pageVars['piecesOrdered'] = returnSQLResult('SELECT SUM(oi.pieces)
|
|
FROM '.getTableName('order_items').' oi
|
|
LEFT JOIN '.getTableName('orders')." o ON oi.id_order=o.id
|
|
WHERE oi.id_product={$ID} AND o.status_storno=0 AND o.status IN (".join(',', getStatuses('notpacked')).')');
|
|
|
|
$pageVars['data']['in_store'] = floatval($pageVars['data']['in_store']);
|
|
$pageVars['product'] = $product;
|
|
}
|
|
|
|
$dbcfg = Settings::getDefault();
|
|
$pageVars['data']['priceWithVat'] = $dbcfg['prod_prefer_price_vat'] == 'Y' || $dbcfg['prod_prefer_price_vat'] == 'F';
|
|
|
|
if ($pageVars['data']['priceWithVat'] && !empty($pageVars['data']['vat'])) {
|
|
$pageVars['data']['price'] = calcPrice($pageVars['data']['price'], $pageVars['vats'][$pageVars['data']['vat']]['vat']);
|
|
} else {
|
|
$pageVars['data']['price'] = toDecimal($pageVars['data']['price']);
|
|
}
|
|
$pageVars['data']['discount'] = \Decimal::create($pageVars['data']['discount'], 8);
|
|
$pageVars['data']['campaigns'] = explodeFlags($pageVars['data']['campaign']);
|
|
$pageVars['tree'] = $this->adminSectionTree->getCategories();
|
|
$pageVars['selected'] = ($this->getID() ? $this->adminSectionTree->getSelected($this->getID(), 'products_in_sections', 'id_product') : []);
|
|
$this->adminSectionTree->getOpened($pageVars['tree']);
|
|
$pageVars['opened'] = $this->adminSectionTree->opened;
|
|
$pageVars['disabled'] = $this->getDisabledSections();
|
|
if (findModule(Modules::PRICE_HISTORY) && !empty($pageVars['data']['price_for_discount'])) {
|
|
$pageVars['data']['price_for_discount'] = toDecimal($pageVars['data']['price_for_discount']);
|
|
}
|
|
|
|
if ($this->isDuplicate()) {
|
|
$pageVars['data']['code'] = $this->generateCode();
|
|
$pageVars['data']['pieces_sold'] = 0;
|
|
$pageVars['data']['ean'] = '';
|
|
$pageVars['data']['price_for_discount'] = null;
|
|
}
|
|
|
|
if (findModule('templates')) {
|
|
$categories = sqlQuery('SELECT CONCAT_WS(" - ", tc.name, t.name) name, t.id
|
|
FROM '.getTableName('templates').' t
|
|
LEFT JOIN '.getTableName('templates_categories').' tc ON t.id_category = tc.id
|
|
ORDER BY tc.position, t.position, t.name');
|
|
$pageVars['templates'] = array_map(function ($x) {
|
|
return $x['name'];
|
|
}, sqlFetchAll($categories, 'id'));
|
|
|
|
$pageVars['data']['templates'] = sqlFetchAll(sqlQueryBuilder()
|
|
->select('tp.id_template')->from('templates_products', 'tp')
|
|
->leftJoin('tp', 'templates', 't', 't.id=tp.id_template')
|
|
->leftJoin('t', 'templates_categories', 'tc', 'tc.id=t.id_category')
|
|
->where(Operator::equals(['tp.id_product' => $ID]))
|
|
->orderBy('tc.position')->addOrderBy('t.position')->addOrderBy('t.name')
|
|
->execute(), 'id_template');
|
|
}
|
|
|
|
if (findModule(Modules::OSS_VATS)) {
|
|
$ossSettings = \Settings::getDefault()['oss_vats'] ?? [];
|
|
$ossIdCN = !empty($pageVars['data']['id_cn']) ? $pageVars['data']['id_cn'] : ($ossSettings['default'] ?? false);
|
|
|
|
$ossCountryID = !empty($ossSettings['homeCountry']) ? $ossSettings['homeCountry'] : 'CZ';
|
|
if (!empty($ossIdCN)) {
|
|
$pageVars['data']['selected_oss_vat'] = sqlQueryBuilder()->select('vc.id_vat, v.descr')
|
|
->from('vats_cns', 'vc')
|
|
->innerJoin('vc', 'vats', 'v', 'v.id=vc.id_vat AND v.id_country=:country')
|
|
->setParameter('country', $ossCountryID)
|
|
->where(Operator::equals(['id_cn' => $ossIdCN]))
|
|
->execute()->fetchAllAssociative();
|
|
|
|
$pageVars['data']['oss_vat'] = $pageVars['data']['selected_oss_vat'][0]['id_vat'] ?? null;
|
|
} else {
|
|
$pageVars['data']['oss_vat'] = sqlQueryBuilder()->select('id')
|
|
->from('vats')->setParameter('country', $ossCountryID)
|
|
->where(Operator::equals([
|
|
'automanaged' => 1,
|
|
'is_default' => 'Y',
|
|
'id_country' => $ossCountryID,
|
|
]))
|
|
->execute()->fetchColumn();
|
|
}
|
|
}
|
|
|
|
if (findModule(Modules::LABELS, Modules::SUB_PRODUCT_LABELS)) {
|
|
$pageVars['data']['product_labels'] = sqlQueryBuilder()
|
|
->select('l.id, COALESCE(l.name_admin, l.name) as name, l.short_name, plr.generated, plr.id_label, plr.id_product')
|
|
->from('labels', 'l')
|
|
->leftJoin('l', 'product_labels_relation', 'plr', 'l.id = plr.id_label AND plr.id_product = :idProduct')
|
|
->setParameter('idProduct', $ID)
|
|
->orderBy('l.name')
|
|
->execute()
|
|
->fetchAllAssociative();
|
|
}
|
|
|
|
$this->unserializeCustomData($pageVars['data']);
|
|
|
|
$vars['body'] = $pageVars;
|
|
|
|
return $vars;
|
|
}
|
|
|
|
public function handleDeleteAttach()
|
|
{
|
|
$IDa = getVal('IDa');
|
|
sqlQuery('DELETE FROM '.getTableName('attachments')."
|
|
WHERE id='".$IDa."' ");
|
|
$this->returnOK();
|
|
}
|
|
|
|
public function handleDeleteLink()
|
|
{
|
|
$IDl = getVal('IDl');
|
|
sqlQuery('DELETE FROM '.getTableName('links')."
|
|
WHERE id='".$IDl."' ");
|
|
$this->returnOK();
|
|
}
|
|
|
|
public function handleFindCode()
|
|
{
|
|
$code = getVal('code');
|
|
$this->setID(returnSQLResult('SELECT id FROM products WHERE code=:code', ['code' => $code]));
|
|
$this->redirect();
|
|
}
|
|
|
|
public function getData()
|
|
{
|
|
$cfg = Config::get();
|
|
$data = parent::getData();
|
|
$acn = $this->getAction();
|
|
$ID = $this->getID();
|
|
|
|
if (getVal('Submit')) {
|
|
if (isset($data['delivery_time']) && $data['delivery_time'] == 1) {
|
|
$data['delivery_time'] = $data['deliveryTimeDays'];
|
|
}
|
|
if (empty($data['price_common'])) {
|
|
$data['price_common'] = '0';
|
|
}
|
|
if ($data['position'] == '-1') {
|
|
if (is_numeric($data['position_abs'])) {
|
|
$data['position'] = intval($data['position_abs']);
|
|
} else {
|
|
$data['position'] = null;
|
|
}
|
|
}
|
|
|
|
if ($data['code'] == '') {
|
|
$data['code'] = null;
|
|
} else {
|
|
if (findModule('products_variations', 'variationCode')) {
|
|
$uniqueCode = Variations::makeCodeUnique(0, $data['code'], $ID);
|
|
|
|
if ($uniqueCode != $data['code']) {
|
|
$this->addError("Kód {$data['code']} není unikátní a byl změněn na {$uniqueCode}!");
|
|
}
|
|
|
|
$data['code'] = $uniqueCode;
|
|
}
|
|
}
|
|
|
|
if (!empty($data['price_buy'])) {
|
|
$data['price_buy'] = $this->prepareVatPrice($data['price_buy']);
|
|
}
|
|
|
|
if (!empty($data['date_added'])) {
|
|
$data['date_added'] = DateTime::createFromFormat('d.m.Y H:i:s', $data['date_added'])->format('Y-m-d H:i:s');
|
|
}
|
|
|
|
if (!empty($data['date_stock_in'])) {
|
|
$data['date_stock_in'] = DateTime::createFromFormat('d.m.Y H:i:s', $data['date_stock_in'])->format('Y-m-d H:i:s');
|
|
}
|
|
|
|
if (!empty($data['ean'])) {
|
|
$data['ean'] = StringUtil::unicode_trim($data['ean']);
|
|
if (Settings::getDefault()->admin_ean_check === 'Y'
|
|
&& !EANValidator::checkEAN($data['ean'])
|
|
) {
|
|
$this->addHTMLError("EAN <strong>{$data['ean']}</strong> není validní.");
|
|
}
|
|
|
|
$exists = Variations::eanExists(0, $data['ean'], $ID);
|
|
|
|
if ($exists) {
|
|
$this->updateSQL('products', ['ean' => null], ['id' => $ID]);
|
|
$message = Variations::eanExistsMessage($exists);
|
|
$this->addHTMLError($message); // EAN {ean} není unikátní. {odkaz na duplicitní produkt}
|
|
}
|
|
}
|
|
|
|
if (!findRight('PROD_STOCK')) {
|
|
$data['inStoreOverride'] = false;
|
|
}
|
|
|
|
if (!getVal('inStoreOverride', $data)) {
|
|
unset($data['in_store']);
|
|
}
|
|
|
|
// Campaign
|
|
$campaign = [];
|
|
foreach ($GLOBALS['cfg']['Products']['Flags'] as $flag => $name) {
|
|
if (getVal("camp{$flag}", $data) == 'ON') {
|
|
$campaign[] = $flag;
|
|
}
|
|
}
|
|
|
|
$data['campaign'] = join(',', $campaign);
|
|
|
|
// uprava desetinnych znamenek
|
|
$data['price'] = str_replace(',', '.', $data['price']);
|
|
$data['price_common'] = str_replace(',', '.', $data['price_common']);
|
|
// $data['discount'] = str_replace(',', '.', $data['discount']);
|
|
$data['max_cpc'] = str_replace(',', '.', $data['max_cpc']);
|
|
|
|
if (!empty($data['weight'])) {
|
|
$data['weight'] = str_replace(',', '.', $data['weight']);
|
|
}
|
|
|
|
if (empty($data['discount'])) {
|
|
$data['discount'] = 0;
|
|
}
|
|
|
|
if (findModule('seo')) {
|
|
if (empty($data['meta_title_changed'])) {
|
|
$data['meta_title'] = '';
|
|
}
|
|
}
|
|
|
|
if (findModule(Modules::OSS_VATS) && !empty($data['id_cn'])) {
|
|
ServiceContainer::getService(\KupShop\OSSVatsBundle\Util\VatsUtil::class)->refreshVatsCnsRelations([$data['id_cn']]);
|
|
}
|
|
|
|
if ($acn == 'add') {
|
|
if (getVal('ID') && $this->isDuplicate() && getVal('ignoreFlagNews')) {
|
|
$dbcfg = Settings::getDefault();
|
|
try {
|
|
$date_added = new DateTime();
|
|
$date_added->sub(new DateInterval('P'.($dbcfg->prod_flag_automatic_new + 1).'D'));
|
|
$data['date_added'] = $date_added->format('Y-m-d H:i');
|
|
} catch (Exception $e) {
|
|
}
|
|
} else {
|
|
$data['date_added'] = date('Y-m-d H:i');
|
|
}
|
|
}
|
|
|
|
$data['data'] = array_merge($this->getCustomData(), $data['data'] ?? []);
|
|
$this->serializeCustomData($data);
|
|
}
|
|
|
|
if (($acn == 'add') && !getVal('Submit')) {
|
|
$data['code'] = $this->generateCode();
|
|
$data['ean'] = '';
|
|
$data['price'] = '0';
|
|
$data['price_for_discount'] = null;
|
|
$data['discount'] = '0';
|
|
$data['vat'] = $data['vat'] ?? getAdminVat()['id'];
|
|
$data['guarantee'] = '24';
|
|
$data['in_store'] = '0';
|
|
$data['pieces_sold'] = '0';
|
|
$data['delivery_time'] = array_key_first($cfg['Products']['DeliveryTime'] ?? []); // -1;
|
|
$data['campaign'] = '';
|
|
$data['showInLead'] = 'Y';
|
|
$data['figure'] = 'Y';
|
|
$data['max_cpc'] = 0;
|
|
$data['show_in_feed'] = 'Y';
|
|
$data['show_in_search'] = 'Y';
|
|
$data['serial_number_require'] = 'N';
|
|
$data['showRawPrince'] = 'N';
|
|
$data['in_store_show_max'] = null;
|
|
$data['position'] = null;
|
|
$data['price_common'] = 0;
|
|
$data['data'] = null;
|
|
}
|
|
|
|
$vatContext = Contexts::get(VatContext::class);
|
|
$data['vatValue'] = $vatContext->getVat($data['vat'])['vat'] ?? 0;
|
|
if (getVal('Submit')) {
|
|
if ($data['priceWithVat']) {
|
|
try {
|
|
$data['price'] = calcPrice($data['price'], -$data['vatValue']);
|
|
} catch (InvalidArgumentException $e) {
|
|
$this->returnError('Špatný formát ceny!');
|
|
}
|
|
}
|
|
if (!empty($data['price_for_discount'])) {
|
|
$data['price_for_discount'] = $this->prepareVatPrice(['value' => $data['price_for_discount'], 'vat' => $data['vatValue']]);
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
public function generateCode()
|
|
{
|
|
if (findModule(Modules::PRODUCTS, Modules::SUB_DONT_GENERATE_CODE)) {
|
|
return '';
|
|
}
|
|
|
|
$code = '';
|
|
$strAlpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
for ($i = 0; $i < 5; $i++) {
|
|
if ($i < 2) {
|
|
$code .= $strAlpha[rand(0, strlen($strAlpha) - 1)];
|
|
}
|
|
if ($i >= 2) {
|
|
$code .= rand(0, 9);
|
|
}
|
|
}
|
|
|
|
return $code;
|
|
}
|
|
|
|
public function handleUpdate()
|
|
{
|
|
$acn = $this->getAction();
|
|
|
|
if ($acn == 'edit' && !findRight('PROD_EDIT')) {
|
|
redirect('launch.php?s=error.php&id=1');
|
|
}
|
|
if ($acn == 'add' && !findRight('PROD_ADD')) {
|
|
redirect('launch.php?s=error.php&id=1');
|
|
}
|
|
|
|
$oldInStore = $this->getObject()['in_store'] ?? 0;
|
|
|
|
parent::handleUpdate();
|
|
|
|
$ID = $this->getID();
|
|
$data = $this->getData();
|
|
$duplicate = $this->isDuplicate();
|
|
|
|
// zalogovat, ze byla rucne zmenena skladovost
|
|
if (($data['inStoreOverride'] ?? false) && ($data['in_store'] ?? false) !== false) {
|
|
addActivityLog(
|
|
ActivityLog::SEVERITY_NOTICE,
|
|
ActivityLog::TYPE_CHANGE,
|
|
sprintf(
|
|
translate('activityEdited', 'products'),
|
|
$this->getID(),
|
|
sprintf(translate('activityInStoreEdited', 'products'), $oldInStore, $data['in_store'])
|
|
)
|
|
);
|
|
}
|
|
|
|
global $dbcfg, $cfg;
|
|
if (!empty($dbcfg['prod_flag_automatic_new']) && !empty($cfg['Products']['Flags']['N'])) {
|
|
Product::automaticUpdateFlagForNewProducts($ID);
|
|
}
|
|
|
|
$ID = $this->getID();
|
|
|
|
// ############################################
|
|
// # ZAPSANI ODKAZU
|
|
|
|
$links = getVal('links', $data, []);
|
|
foreach ($links as $id => $link) {
|
|
$link['id'] = intval($link['id']);
|
|
$link['id_product'] = $ID;
|
|
|
|
if ($duplicate && $id > 0) {
|
|
unset($link['id']);
|
|
$id = -99;
|
|
}
|
|
|
|
if (!empty($link['delete']) || !$id || !$link['link']) {
|
|
if ($id > 0) {
|
|
$this->deleteSQL('links', ['id' => $link['id']]);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if ($id < 0) {
|
|
$this->insertSQL('links', $link);
|
|
} else {
|
|
$this->updateSQL('links', $link, ['id' => $link['id']]);
|
|
}
|
|
}
|
|
// ############################################
|
|
// # ZAPSANI PRILOH
|
|
|
|
$attach = getVal('attach', $data, []);
|
|
foreach ($attach as $id => $att) {
|
|
$att['id'] = intval($att['id']);
|
|
$att['id_product'] = $ID;
|
|
|
|
if ($duplicate && $id > 0) {
|
|
unset($att['id']);
|
|
$id = -99;
|
|
}
|
|
|
|
if (!empty($att['delete']) || !$id || !$att['link']) {
|
|
if ($id > 0) {
|
|
$this->deleteSQL('attachments', ['id' => $att['id']]);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (isset($att['title']) && empty($att['title']) && !empty($att['link'])) {
|
|
$att['title'] = basename($att['link']);
|
|
}
|
|
|
|
if ($id < 0) {
|
|
$this->insertSQL('attachments', $att);
|
|
} else {
|
|
$this->updateSQL('attachments', $att, ['id' => $att['id']]);
|
|
}
|
|
}
|
|
|
|
// ############################################
|
|
// # ZAPSANI SETU
|
|
$sets = getVal('sets', $data, []);
|
|
foreach ($sets as $id => $set) {
|
|
$set['id_product_set'] = intval($set['id_product_set']);
|
|
$set['id_product'] = $ID;
|
|
if (empty($set['id_variation'])) {
|
|
$set['id_variation'] = null;
|
|
}
|
|
|
|
$this->prepareNull($set['price']);
|
|
|
|
if (!empty($set['price'])) {
|
|
$setProductVatId = sqlQueryBuilder()
|
|
->select('vat')
|
|
->from('products')
|
|
->where(Operator::equals(['id' => $set['id_product_set']]))
|
|
->execute()->fetchOne();
|
|
|
|
$set['price'] = toDecimal($set['price'])->removeVat(getVat($setProductVatId));
|
|
}
|
|
|
|
if (!ctype_digit($set['pieces']) || $set['pieces'] < 1) {
|
|
$set['pieces'] = 1;
|
|
}
|
|
|
|
if ($duplicate && $id > 0) {
|
|
$id = -99;
|
|
}
|
|
|
|
if (!empty($set['delete']) || !$id || $set['id_product_set'] <= 0) {
|
|
if ($id > 0) {
|
|
$this->deleteSQL('products_sets', ['id' => $set['id']]);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if ($id < 0) {
|
|
$this->insertSQL('products_sets', $set);
|
|
} else {
|
|
$this->updateSQL('products_sets', $set, ['id' => $set['id']]);
|
|
}
|
|
}
|
|
// ############################################
|
|
// # ZAPSANI SABLON
|
|
if (findModule('templates')) {
|
|
$templates = getVal('templates', $data, []);
|
|
foreach ($templates as $id_template_old => $template) {
|
|
$template['id_template'] = intval(getVal('id_template', $template));
|
|
$template['id_product'] = $ID;
|
|
|
|
if ($duplicate && $id_template_old > 0) {
|
|
unset($template['id']);
|
|
$id_template_old = -99;
|
|
}
|
|
|
|
$where = ['id_template' => $id_template_old, 'id_product' => $ID];
|
|
|
|
if (!empty($template['delete']) || !$id_template_old) {
|
|
if ($id_template_old > 0) {
|
|
$this->deleteSQL('templates_products', $where);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if ($template['id_template'] <= 0) {
|
|
continue;
|
|
}
|
|
|
|
if ($id_template_old < 0) {
|
|
$this->insertSQL('templates_products', $template);
|
|
} else {
|
|
$this->updateSQL('templates_products', $template, $where);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ZAPSANI PRIPLATKU
|
|
if (findModule(Modules::PRODUCTS_CHARGES)) {
|
|
$products_charges = getVal('products_charges', $data, []);
|
|
foreach ($products_charges as $key => $charge) {
|
|
$charge['id'] = intval($charge['id']);
|
|
$charge['id_product'] = $ID;
|
|
|
|
if ($duplicate && $key > 0) {
|
|
unset($charge['id']);
|
|
$key = -99;
|
|
}
|
|
|
|
if (!empty($charge['delete']) || !$key) {
|
|
if ($key > 0) {
|
|
$this->deleteSQL('products_charges', ['id' => $charge['id']]);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if ($key < 0) {
|
|
$this->insertSQL('products_charges', $charge);
|
|
} else {
|
|
$this->updateSQL('products_charges', $charge, ['id' => $charge['id']]);
|
|
}
|
|
}
|
|
}
|
|
|
|
$duplicateID = getVal('duplicateID');
|
|
|
|
// ############################################
|
|
// # DUPLIKACE OBRAZKU
|
|
if (findModule('photos') && getVal('duplicateImages') && getVal('duplicateID')) {
|
|
$fromID = intval(getVal('duplicateID'));
|
|
$toID = intval($ID);
|
|
|
|
sqlQuery('INSERT INTO '.getTableName('photos_products_relation')." (id_photo, id_product, show_in_lead, active, date_added, position)
|
|
SELECT id_photo, {$toID}, show_in_lead, active, date_added, position
|
|
FROM photos_products_relation
|
|
WHERE id_product={$fromID}
|
|
GROUP BY id_photo");
|
|
}
|
|
// ############################################
|
|
// # DUPLIKACE Variant
|
|
if (findModule('products_variations') && getVal('duplicateVariants') && getVal('duplicateID')) {
|
|
Variations::duplicateVariations(intval(getVal('duplicateID')), intval($ID));
|
|
}
|
|
if (findModule('photos') && getVal('duplicateImages') && getVal('duplicateID')) {
|
|
Photos::checkLeadPhoto('photos_products_relation', 'id_product', intval($ID));
|
|
}
|
|
|
|
// duplikace sekci
|
|
if (findModule(Modules::PRODUCTS_SECTIONS) && $duplicateID) {
|
|
sqlQuery('INSERT INTO products_in_sections (id_product, id_section, figure, generated)
|
|
SELECT :id_product_new, id_section, figure, generated FROM products_in_sections WHERE id_product = :id_product;', [
|
|
'id_product' => $duplicateID,
|
|
'id_product_new' => $ID,
|
|
]);
|
|
}
|
|
|
|
// duplikace souvisejiciho zbozi
|
|
if (findModule(Modules::PRODUCTS_RELATED) && $duplicateID) {
|
|
$relatedTypeFiled = '';
|
|
if (findModule(Modules::PRODUCTS_RELATED, Modules::SUB_TYPES)) {
|
|
$relatedTypeFiled = ', type';
|
|
}
|
|
|
|
sqlQuery('INSERT INTO products_related (id_top_product, id_rel_product, position'.$relatedTypeFiled.')
|
|
SELECT :id_product_new, id_rel_product, position'.$relatedTypeFiled.' FROM products_related WHERE id_top_product = :id_product;', [
|
|
'id_product' => $duplicateID,
|
|
'id_product_new' => $ID,
|
|
]);
|
|
}
|
|
|
|
// duplikace kolekci
|
|
if (findModule(\Modules::PRODUCTS_COLLECTIONS) && $duplicateID) {
|
|
sqlQuery('INSERT INTO products_collections (id_product, id_product_related)
|
|
SELECT :id_product_new, id_product_related FROM products_collections WHERE id_product = :id_product;', [
|
|
'id_product' => $duplicateID,
|
|
'id_product_new' => $ID,
|
|
]);
|
|
}
|
|
|
|
if (findModule(\Modules::ARTICLES) && $duplicateID) {
|
|
sqlQuery('INSERT INTO products_in_articles (id_product, id_article)
|
|
SELECT :id_product_new, id_article FROM products_in_articles WHERE id_product = :id_product;', [
|
|
'id_product' => $duplicateID,
|
|
'id_product_new' => $ID,
|
|
]);
|
|
}
|
|
|
|
// Duplikace parametru
|
|
if (findModule(Modules::PRODUCTS_PARAMETERS) && getVal('duplicateID')) {
|
|
$fromID = intval(getVal('duplicateID'));
|
|
$toID = intval($ID);
|
|
|
|
$additionalField = '';
|
|
if (findModule(Modules::PRODUCTS_PARAMETERS.Modules::SUB_CONFIGURATIONS)) {
|
|
$additionalField = ', configuration_price';
|
|
}
|
|
|
|
sqlQuery('INSERT INTO parameters_products (id_product, id_parameter, value_list, value_char, value_float, unit, weight'.$additionalField.')
|
|
SELECT '.$toID.', id_parameter, value_list, value_char, value_float, unit, weight'.$additionalField.'
|
|
FROM parameters_products
|
|
WHERE id_product=:id_product', ['id_product' => $fromID]);
|
|
|
|
// konfigurace parametru
|
|
if (findModule(Modules::PRODUCTS_PARAMETERS.Modules::SUB_CONFIGURATIONS)) {
|
|
sqlQuery('INSERT INTO parameters_configurations (id_parameter, id_product)
|
|
SELECT id_parameter, '.$toID.'
|
|
FROM parameters_configurations
|
|
WHERE id_product=:id_product', ['id_product' => $fromID]);
|
|
}
|
|
|
|
// skupina parametru
|
|
if (findModule(Modules::PARAMETER_GROUPS)) {
|
|
sqlQuery('UPDATE products SET id_parameter_group = (
|
|
SELECT id_parameter_group FROM products WHERE id = :from_id
|
|
)
|
|
WHERE id = :to_id', ['to_id' => $toID, 'from_id' => $fromID]);
|
|
}
|
|
}
|
|
|
|
// Zapsani stitku
|
|
if (findModule(Modules::LABELS, Modules::SUB_PRODUCT_LABELS)) {
|
|
$labels = $data['labels'] ?? [];
|
|
|
|
// odfiltruju generovany stitky na produktu
|
|
$labels = array_filter($labels);
|
|
|
|
$labelIds = array_keys($labels);
|
|
|
|
// nactu si aktualni stitky na produktu
|
|
$oldLabelIds = sqlQueryBuilder()
|
|
->select('id_label')
|
|
->from('product_labels_relation')
|
|
->andWhere(Operator::equals(['id_product' => $ID]))
|
|
->andWhere(Operator::equals(['generated' => 0]))
|
|
->execute()
|
|
->fetchFirstColumn();
|
|
|
|
// najdu si hodnoty, ktere mam smazat
|
|
$deleteLabelIds = array_diff($oldLabelIds, $labelIds);
|
|
// najdu si hodnoty, ktere mam insertovat
|
|
$insertLabelsIds = array_diff($labelIds, $oldLabelIds);
|
|
|
|
// provedu delete
|
|
if (!empty($deleteLabelIds)) {
|
|
sqlQueryBuilder()
|
|
->delete('product_labels_relation')
|
|
->andWhere(Operator::equals([
|
|
'id_product' => $ID,
|
|
'generated' => 0]))
|
|
->andWhere(Operator::inIntArray($deleteLabelIds, 'id_label'))
|
|
->execute();
|
|
}
|
|
|
|
// provedu insert
|
|
foreach ($insertLabelsIds as $labelId) {
|
|
sqlQueryBuilder()
|
|
->insert('product_labels_relation')
|
|
->directValues([
|
|
'id_label' => $labelId,
|
|
'id_product' => $ID,
|
|
])
|
|
->onDuplicateKeyUpdate(['id_label' => 'id_label'])
|
|
->execute();
|
|
}
|
|
|
|
if (!empty($insertLabelsIds) || !empty($deleteLabelIds)) {
|
|
$this->updateSQL('products', ['updated' => date('Y-m-d H:i:s')], ['id' => $ID]);
|
|
}
|
|
}
|
|
|
|
// ############################################
|
|
// # Aktualizace fulltextového vyhledávání
|
|
if (findModule(\Modules::SEARCH)) {
|
|
$fulltext = ServiceContainer::getService(FulltextInterface::class);
|
|
$languageContext = Contexts::get(\KupShop\KupShopBundle\Context\LanguageContext::class);
|
|
foreach ($languageContext->getSupported() as $language) {
|
|
$languageContext->activate($language->getId());
|
|
$fulltext->updateProduct($ID);
|
|
}
|
|
}
|
|
|
|
if ($acn == 'add') {
|
|
$product = new Product();
|
|
$product->createFromDB($this->getID());
|
|
$eventDispatcher = ServiceContainer::getService('event_dispatcher');
|
|
$event = new ProductEvent($product);
|
|
$eventDispatcher->dispatch($event, ProductEvent::PRODUCT_CREATED);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Vypisovani aktivit
|
|
protected function activityMessage($name, array $additionalData = [])
|
|
{
|
|
$acn = $this->getAction();
|
|
$ID = $this->getID();
|
|
$data = sqlQueryBuilder()->select('title, code')->fromProducts()->where(\Query\Operator::equals(['id' => $ID]))->execute()->fetch();
|
|
if ($acn == 'add') {
|
|
writeDownActivity(sprintf(getTextString('products', 'activityAdded'), $ID, $data['title'].($data['code'] ? " ({$data['code']})" : '')));
|
|
} elseif ($acn == 'edit') {
|
|
writeDownActivity(sprintf(getTextString('products', 'activityEdited'), $ID, $data['title'].($data['code'] ? " ({$data['code']})" : '')));
|
|
}
|
|
}
|
|
|
|
public function handleDelete()
|
|
{
|
|
if (!findRight('PROD_ERASE')) {
|
|
redirect('launch.php?s=error.php&id=1');
|
|
}
|
|
|
|
$ID = $this->getID();
|
|
$data = sqlQueryBuilder()->select('title, code')->fromProducts()->where(\Query\Operator::equals(['id' => $ID]))->execute()->fetch();
|
|
writeDownActivity(sprintf(getTextString('products', 'activityDeleted'), $ID, $data['title'].($data['code'] ? " ({$data['code']})" : '')));
|
|
|
|
$classProd = new Product($this->getID());
|
|
$classProd->delete();
|
|
|
|
// ############################################
|
|
// # Aktualizace fulltextového vyhledávání
|
|
if (findModule(\Modules::SEARCH) && !findModule(Modules::KAFKA)) {
|
|
$fulltext = ServiceContainer::getService(FulltextInterface::class);
|
|
$fulltext->updateProduct($this->getID());
|
|
}
|
|
|
|
redirect('launch.php?s=products.php&acn=erased');
|
|
}
|
|
|
|
public function handleEraseSelected()
|
|
{
|
|
if (!findRight('PROD_ERASE')) {
|
|
redirect('launch.php?s=error.php&id=1');
|
|
}
|
|
$ID = $this->getID();
|
|
$no = count($ID);
|
|
|
|
for ($i = 0; $i < $no; $i++) {
|
|
$ID = $ID[$i];
|
|
|
|
writeDownActivity('smazáno zboží: '.returnSQLResult('SELECT title FROM '.getTableName('products')." WHERE id='".$ID."' "));
|
|
|
|
$classProd = new Product($ID);
|
|
$classProd->delete();
|
|
}
|
|
|
|
$ErrStr = 'Bylo smazáno '.$no.' položek';
|
|
$url = 'launch.php?s=products.php&acn=erased&ErrStr='.urlencode($ErrStr);
|
|
|
|
redirect($url);
|
|
}
|
|
|
|
public function handleGenerateCouponPhoto()
|
|
{
|
|
$data = $this->getData();
|
|
$id_discount = ($data['data']['generate_coupon_discount'] ?? null);
|
|
if ($id_discount) {
|
|
$discountGenerator = ServiceContainer::getService(DiscountGenerator::class);
|
|
$result = $discountGenerator->generateCouponPhoto($id_discount, $this->getID());
|
|
|
|
if ($result === true) {
|
|
$this->returnOK();
|
|
} else {
|
|
$this->returnError($result);
|
|
}
|
|
}
|
|
}
|
|
|
|
public function handleGenerateEan()
|
|
{
|
|
if ($ID = $this->getID()) {
|
|
$ean = EANValidator::generateEan(['id_product' => $ID]);
|
|
|
|
$exists = Variations::eanExists(0, $ean, $ID);
|
|
|
|
if ($exists) {
|
|
$message = Variations::eanExistsMessage($exists);
|
|
$this->addHTMLError('Vygenerovaný '.$message); // Vygenerovaný EAN {ean} není unikátní. {odkaz na duplicitní produkt}
|
|
} else {
|
|
sqlQueryBuilder()->update('products')
|
|
->directValues(['ean' => $ean])
|
|
->where(Operator::equals(['id' => $ID]))
|
|
->execute();
|
|
|
|
$this->returnOK();
|
|
}
|
|
}
|
|
}
|
|
|
|
private function getDisabledSections(): array
|
|
{
|
|
$sections = sqlQueryBuilder()
|
|
->select('id_section')
|
|
->from('products_in_sections')
|
|
->where(Operator::equals(['id_product' => $this->getID(), 'generated' => 1]))
|
|
->execute()->fetchAll();
|
|
|
|
return \KupShop\KupShopBundle\Util\Functional\Mapping::mapKeys($sections, function ($k, $v) {
|
|
return [$v['id_section'], true];
|
|
});
|
|
}
|
|
|
|
public function handleDeactivatePriceForDiscount()
|
|
{
|
|
if ($ID = $this->getID()) {
|
|
sqlQueryBuilder()->update('products')
|
|
->directValues(['price_for_discount' => -1])
|
|
->where(Operator::equals(['id' => $ID]))
|
|
->execute();
|
|
sqlQueryBuilder()->update('products_variations')
|
|
->directValues(['price_for_discount' => -1])
|
|
->where(Operator::equals(['id_product' => $ID]))
|
|
->andWhere('price_for_discount IS NOT NULL')
|
|
->execute();
|
|
if (findModule(Modules::PRICELISTS)) {
|
|
sqlQueryBuilder()->update('pricelists_products')
|
|
->directValues(['price_for_discount' => -1])
|
|
->where(Operator::equals(['id_product' => $ID]))
|
|
->execute();
|
|
}
|
|
}
|
|
|
|
$this->returnOK();
|
|
}
|
|
|
|
public function handleActivatePriceForDiscount()
|
|
{
|
|
if ($ID = $this->getID()) {
|
|
sqlQueryBuilder()->update('products')
|
|
->directValues(['price_for_discount' => null])
|
|
->where(Operator::equals(['id' => $ID]))
|
|
->execute();
|
|
sqlQueryBuilder()->update('products_variations')
|
|
->directValues(['price_for_discount' => null])
|
|
->where(Operator::equals(['id_product' => $ID]))
|
|
->andWhere('price_for_discount = -1')
|
|
->execute();
|
|
if (findModule(Modules::PRICELISTS)) {
|
|
sqlQueryBuilder()->update('pricelists_products')
|
|
->directValues(['price_for_discount' => null])
|
|
->where(Operator::equals(['id_product' => $ID]))
|
|
->andWhere('price_for_discount = -1')
|
|
->execute();
|
|
}
|
|
}
|
|
|
|
$this->returnOK();
|
|
}
|
|
|
|
public function handleException($e)
|
|
{
|
|
switch (intval($e->getPrevious()->errorInfo[1])) {
|
|
case 1062:
|
|
$badFields = $this->getBadValues($this->getTableName(), ['id' => $this->ID]);
|
|
$ErrStr = '';
|
|
if (in_array('title', $badFields)) {
|
|
$ErrStr .= 'Produkt s tímto názvem již existuje. Zvolte prosím jiný název. ';
|
|
}
|
|
|
|
foreach ($badFields as $key => $value) {
|
|
if ($value == 'title') {
|
|
continue;
|
|
}
|
|
if ($key == 0) {
|
|
$ErrStr .= 'Duplicitní ';
|
|
}
|
|
$ErrStr .= '{'.$value.'} ';
|
|
}
|
|
|
|
if (!$badFields) {
|
|
$ErrStr = "Duplicitní záznam: \n".$e->getMessage();
|
|
}
|
|
|
|
$this->addError($ErrStr);
|
|
|
|
return;
|
|
}
|
|
|
|
parent::handleException($e);
|
|
}
|
|
|
|
public function hasRights($name = null)
|
|
{
|
|
switch ($name) {
|
|
case Window::RIGHT_DELETE:
|
|
return findRight('PROD_ERASE') && parent::hasRights($name);
|
|
default:
|
|
return parent::hasRights($name);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Products::class;
|