Files
kupshop/admin/products.php
2025-08-02 16:30:27 +02:00

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;