1<?php 2/** 3 * 2007-2016 PrestaShop 4 * 5 * thirty bees is an extension to the PrestaShop e-commerce software developed by PrestaShop SA 6 * Copyright (C) 2017-2018 thirty bees 7 * 8 * NOTICE OF LICENSE 9 * 10 * This source file is subject to the Open Software License (OSL 3.0) 11 * that is bundled with this package in the file LICENSE.txt. 12 * It is also available through the world-wide-web at this URL: 13 * http://opensource.org/licenses/osl-3.0.php 14 * If you did not receive a copy of the license and are unable to 15 * obtain it through the world-wide-web, please send an email 16 * to license@thirtybees.com so we can send you a copy immediately. 17 * 18 * DISCLAIMER 19 * 20 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer 21 * versions in the future. If you wish to customize PrestaShop for your 22 * needs please refer to https://www.thirtybees.com for more information. 23 * 24 * @author thirty bees <contact@thirtybees.com> 25 * @author PrestaShop SA <contact@prestashop.com> 26 * @copyright 2017-2018 thirty bees 27 * @copyright 2007-2016 PrestaShop SA 28 * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 29 * PrestaShop is an internationally registered trademark & property of PrestaShop SA 30 */ 31 32/** 33 * Class AdminShopControllerCore 34 * 35 * @since 1.0.0 36 */ 37class AdminShopControllerCore extends AdminController 38{ 39 /** 40 * AdminShopControllerCore constructor. 41 * 42 * @since 1.0.0 43 */ 44 public function __construct() 45 { 46 $this->bootstrap = true; 47 $this->context = Context::getContext(); 48 $this->table = 'shop'; 49 $this->className = 'Shop'; 50 $this->multishop_context = Shop::CONTEXT_ALL; 51 52 $this->id_shop_group = (int) Tools::getValue('id_shop_group'); 53 54 /* if $_GET['id_shop'] is transmitted, virtual url can be loaded in config.php, so we wether transmit shop_id in herfs */ 55 if ($this->id_shop = (int) Tools::getValue('shop_id')) { 56 $_GET['id_shop'] = $this->id_shop; 57 } 58 59 $this->list_skip_actions['delete'] = [(int) Configuration::get('PS_SHOP_DEFAULT')]; 60 $this->fields_list = [ 61 'id_shop' => [ 62 'title' => $this->l('Shop ID'), 63 'align' => 'center', 64 'class' => 'fixed-width-xs', 65 ], 66 'name' => [ 67 'title' => $this->l('Shop name'), 68 'filter_key' => 'a!name', 69 'width' => 200, 70 ], 71 'shop_group_name' => [ 72 'title' => $this->l('Shop group'), 73 'width' => 150, 74 'filter_key' => 'gs!name', 75 ], 76 'category_name' => [ 77 'title' => $this->l('Root category'), 78 'width' => 150, 79 'filter_key' => 'cl!name', 80 ], 81 'url' => [ 82 'title' => $this->l('Main URL for this shop'), 83 'havingFilter' => 'url', 84 ], 85 ]; 86 87 parent::__construct(); 88 } 89 90 /** 91 * @param bool $disable 92 * 93 * @return string 94 * 95 * @since 1.0.0 96 */ 97 public function viewAccess($disable = false) 98 { 99 return Configuration::get('PS_MULTISHOP_FEATURE_ACTIVE'); 100 } 101 102 /** 103 * Initialize page header toolbar 104 * 105 * @return void 106 * 107 * @since 1.0.0 108 */ 109 public function initPageHeaderToolbar() 110 { 111 parent::initPageHeaderToolbar(); 112 113 if (!$this->display && $this->id_shop_group) { 114 if ($this->id_object) { 115 $this->loadObject(); 116 } 117 118 if (!$this->id_shop_group && $this->object && $this->object->id_shop_group) { 119 $this->id_shop_group = $this->object->id_shop_group; 120 } 121 122 $this->page_header_toolbar_btn['edit'] = [ 123 'desc' => $this->l('Edit this shop group'), 124 'href' => $this->context->link->getAdminLink('AdminShopGroup').'&updateshop_group&id_shop_group='.$this->id_shop_group, 125 ]; 126 127 $this->page_header_toolbar_btn['new'] = [ 128 'desc' => $this->l('Add new shop'), 129 'href' => $this->context->link->getAdminLink('AdminShop').'&add'.$this->table.'&id_shop_group='.$this->id_shop_group, 130 ]; 131 } 132 } 133 134 /** 135 * Initialize toolbar 136 * 137 * @return void 138 * 139 * @since 1.0.0 140 */ 141 public function initToolbar() 142 { 143 parent::initToolbar(); 144 145 if ($this->display != 'edit' && $this->display != 'add') { 146 if ($this->id_object) { 147 $this->loadObject(); 148 } 149 150 if (!$this->id_shop_group && $this->object && $this->object->id_shop_group) { 151 $this->id_shop_group = $this->object->id_shop_group; 152 } 153 154 $this->toolbar_btn['new'] = [ 155 'desc' => $this->l('Add new shop'), 156 'href' => $this->context->link->getAdminLink('AdminShop').'&add'.$this->table.'&id_shop_group=' 157 .$this->id_shop_group, 158 ]; 159 } 160 } 161 162 /** 163 * Initialize content 164 * 165 * @return void 166 * 167 * @since 1.0.0 168 */ 169 public function initContent() 170 { 171 parent::initContent(); 172 173 $this->addJqueryPlugin('cooki-plugin'); 174 $data = Shop::getTree(); 175 176 foreach ($data as $keyGroup => &$group) { 177 foreach ($group['shops'] as $keyShop => &$shop) { 178 $currentShop = new Shop($shop['id_shop']); 179 $urls = $currentShop->getUrls(); 180 181 foreach ($urls as $keyUrl => &$url) { 182 $title = $url['domain'].$url['physical_uri'].$url['virtual_uri']; 183 if (strlen($title) > 23) { 184 $title = substr($title, 0, 23).'...'; 185 } 186 187 $url['name'] = $title; 188 $shop['urls'][$url['id_shop_url']] = $url; 189 } 190 } 191 } 192 193 $shopsTree = new HelperTreeShops('shops-tree', $this->l('Multistore tree')); 194 $shopsTree->setNodeFolderTemplate('shop_tree_node_folder.tpl')->setNodeItemTemplate('shop_tree_node_item.tpl') 195 ->setHeaderTemplate('shop_tree_header.tpl')->setActions( 196 [ 197 new TreeToolbarLink( 198 'Collapse All', 199 '#', 200 '$(\'#'.$shopsTree->getId().'\').tree(\'collapseAll\'); return false;', 201 'icon-collapse-alt' 202 ), 203 new TreeToolbarLink( 204 'Expand All', 205 '#', 206 '$(\'#'.$shopsTree->getId().'\').tree(\'expandAll\'); return false;', 207 'icon-expand-alt' 208 ), 209 ] 210 ) 211 ->setAttribute('url_shop_group', $this->context->link->getAdminLink('AdminShopGroup')) 212 ->setAttribute('url_shop', $this->context->link->getAdminLink('AdminShop')) 213 ->setAttribute('url_shop_url', $this->context->link->getAdminLink('AdminShopUrl')) 214 ->setData($data); 215 $shopsTree = $shopsTree->render(null, false, false); 216 217 if ($this->display == 'edit') { 218 $this->toolbar_title[] = $this->object->name; 219 } elseif (!$this->display && $this->id_shop_group) { 220 $group = new ShopGroup($this->id_shop_group); 221 $this->toolbar_title[] = $group->name; 222 } 223 224 $this->context->smarty->assign( 225 [ 226 'toolbar_scroll' => 1, 227 'toolbar_btn' => $this->toolbar_btn, 228 'title' => $this->toolbar_title, 229 'shops_tree' => $shopsTree, 230 ] 231 ); 232 } 233 234 /** 235 * Render list 236 * 237 * @return false|string 238 * 239 * @since 1.0.0 240 */ 241 public function renderList() 242 { 243 $this->addRowAction('edit'); 244 $this->addRowAction('delete'); 245 246 $this->_select = 'gs.name shop_group_name, cl.name category_name, CONCAT(\'http://\', su.domain, su.physical_uri, su.virtual_uri) AS url'; 247 $this->_join = ' 248 LEFT JOIN `'._DB_PREFIX_.'shop_group` gs 249 ON (a.id_shop_group = gs.id_shop_group) 250 LEFT JOIN `'._DB_PREFIX_.'category_lang` cl 251 ON (a.id_category = cl.id_category AND cl.id_lang='.(int) $this->context->language->id.') 252 LEFT JOIN '._DB_PREFIX_.'shop_url su 253 ON a.id_shop = su.id_shop AND su.main = 1 254 '; 255 $this->_group = 'GROUP BY a.id_shop'; 256 257 if ($idShopGroup = (int) Tools::getValue('id_shop_group')) { 258 $this->_where = 'AND a.id_shop_group = '.$idShopGroup; 259 } 260 261 return parent::renderList(); 262 } 263 264 /** 265 * @return void 266 * 267 * @since 1.0.0 268 */ 269 public function displayAjaxGetCategoriesFromRootCategory() 270 { 271 if (Tools::isSubmit('id_category')) { 272 $selectedCat = [(int) Tools::getValue('id_category')]; 273 $children = Category::getChildren((int) Tools::getValue('id_category'), $this->context->language->id); 274 foreach ($children as $child) { 275 $selectedCat[] = $child['id_category']; 276 } 277 278 $helper = new HelperTreeCategories('categories-tree', null, (int) Tools::getValue('id_category'), null, false); 279 $this->content = $helper->setSelectedCategories($selectedCat)->setUseSearch(true)->setUseCheckBox(true) 280 ->render(); 281 } 282 parent::displayAjax(); 283 } 284 285 /** 286 * Post processing 287 * 288 * @return bool|Shop 289 * 290 * @since 1.0.0 291 */ 292 public function postProcess() 293 { 294 if (Tools::isSubmit('id_category_default')) { 295 $_POST['id_category'] = Tools::getValue('id_category_default'); 296 } 297 298 if (Tools::isSubmit('submitAddshopAndStay') || Tools::isSubmit('submitAddshop')) { 299 $shopGroup = new ShopGroup((int) Tools::getValue('id_shop_group')); 300 if ($shopGroup->shopNameExists(Tools::getValue('name'), (int) Tools::getValue('id_shop'))) { 301 $this->errors[] = Tools::displayError('You cannot have two shops with the same name in the same group.'); 302 } 303 } 304 305 if (count($this->errors)) { 306 return false; 307 } 308 309 /** @var Shop|bool $result */ 310 $result = parent::postProcess(); 311 312 if ($result != false && (Tools::isSubmit('submitAddshopAndStay') || Tools::isSubmit('submitAddshop')) && (int) $result->id_category != (int) Configuration::get('PS_HOME_CATEGORY', null, null, (int) $result->id)) { 313 Configuration::updateValue('PS_HOME_CATEGORY', (int) $result->id_category, false, null, (int) $result->id); 314 } 315 316 if ($this->redirect_after) { 317 $this->redirect_after .= '&id_shop_group='.$this->id_shop_group; 318 } 319 320 return $result; 321 } 322 323 /** 324 * Process delete 325 * 326 * @return bool 327 * 328 * @since 1.0.0 329 */ 330 public function processDelete() 331 { 332 if (!Validate::isLoadedObject($object = $this->loadObject())) { 333 $this->errors[] = Tools::displayError('Unable to load this shop.'); 334 } elseif (!Shop::hasDependency($object->id)) { 335 $result = Category::deleteCategoriesFromShop($object->id) && parent::processDelete(); 336 Tools::generateHtaccess(); 337 338 return $result; 339 } else { 340 $this->errors[] = Tools::displayError('You can\'t delete this shop (customer and/or order dependency).'); 341 } 342 343 return false; 344 } 345 346 /** 347 * Get list 348 * 349 * @param int $idLang 350 * @param string|null $orderBy 351 * @param string|null $orderWay 352 * @param int $start 353 * @param int|null $limit 354 * @param int|bool $idLangShop 355 * 356 * @since 1.0.0 357 */ 358 public function getList($idLang, $orderBy = null, $orderWay = null, $start = 0, $limit = null, $idLangShop = false) 359 { 360 if (Shop::getContext() == Shop::CONTEXT_GROUP) { 361 $this->_where .= ' AND a.id_shop_group = '.(int) Shop::getContextShopGroupID(); 362 } 363 364 parent::getList($idLang, $orderBy, $orderWay, $start, $limit, $idLangShop); 365 $shopDeleteList = []; 366 367 // don't allow to remove shop which have dependencies (customers / orders / ... ) 368 foreach ($this->_list as &$shop) { 369 if (Shop::hasDependency($shop['id_shop'])) { 370 $shopDeleteList[] = $shop['id_shop']; 371 } 372 } 373 $this->context->smarty->assign('shops_having_dependencies', $shopDeleteList); 374 } 375 376 /** 377 * Render form 378 * 379 * @return string 380 * 381 * @since 1.0.0 382 */ 383 public function renderForm() 384 { 385 /** @var Shop $obj */ 386 if (!($obj = $this->loadObject(true))) { 387 return ''; 388 } 389 390 $this->fields_form = [ 391 'legend' => [ 392 'title' => $this->l('Shop'), 393 'icon' => 'icon-shopping-cart', 394 ], 395 'identifier' => 'shop_id', 396 'input' => [ 397 [ 398 'type' => 'text', 399 'label' => $this->l('Shop name'), 400 'desc' => [ 401 $this->l('This field does not refer to the shop name visible in the front office.'), 402 sprintf($this->l('Follow %sthis link%s to edit the shop name used on the front office.'), '<a href="'.$this->context->link->getAdminLink('AdminStores').'#store_fieldset_general">', '</a>'), 403 ], 404 'name' => 'name', 405 'required' => true, 406 ], 407 ], 408 ]; 409 410 $displayGroupList = true; 411 if ($this->display == 'edit') { 412 $group = new ShopGroup($obj->id_shop_group); 413 if ($group->share_customer || $group->share_order || $group->share_stock) { 414 $displayGroupList = false; 415 } 416 } 417 418 if ($displayGroupList) { 419 $options = []; 420 foreach (ShopGroup::getShopGroups() as $group) { 421 /** @var ShopGroup $group */ 422 if ($this->display == 'edit' && ($group->share_customer || $group->share_order || $group->share_stock) && ShopGroup::hasDependency($group->id)) { 423 continue; 424 } 425 426 $options[] = [ 427 'id_shop_group' => $group->id, 428 'name' => $group->name, 429 ]; 430 } 431 432 if ($this->display == 'add') { 433 $groupDesc = $this->l('Warning: You won\'t be able to change the group of this shop if this shop belongs to a group with one of these options activated: Share Customers, Share Quantities or Share Orders.'); 434 } else { 435 $groupDesc = $this->l('You can only move your shop to a shop group with all "share" options disabled -- or to a shop group with no customers/orders.'); 436 } 437 438 $this->fields_form['input'][] = [ 439 'type' => 'select', 440 'label' => $this->l('Shop group'), 441 'desc' => $groupDesc, 442 'name' => 'id_shop_group', 443 'options' => [ 444 'query' => $options, 445 'id' => 'id_shop_group', 446 'name' => 'name', 447 ], 448 ]; 449 } else { 450 $this->fields_form['input'][] = [ 451 'type' => 'hidden', 452 'name' => 'id_shop_group', 453 'default' => $group->name, 454 ]; 455 $this->fields_form['input'][] = [ 456 'type' => 'textShopGroup', 457 'label' => $this->l('Shop group'), 458 'desc' => $this->l('You can\'t edit the shop group because the current shop belongs to a group with the "share" option enabled.'), 459 'name' => 'id_shop_group', 460 'value' => $group->name, 461 ]; 462 } 463 464 $categories = Category::getRootCategories($this->context->language->id); 465 $this->fields_form['input'][] = [ 466 'type' => 'select', 467 'label' => $this->l('Category root'), 468 'desc' => sprintf($this->l('This is the root category of the store that you\'ve created. To define a new root category for your store, %splease click here%s.'), '<a href="'.$this->context->link->getAdminLink('AdminCategories').'&addcategoryroot" target="_blank">', '</a>'), 469 'name' => 'id_category', 470 'options' => [ 471 'query' => $categories, 472 'id' => 'id_category', 473 'name' => 'name', 474 ], 475 ]; 476 477 if (Tools::isSubmit('id_shop')) { 478 $shop = new Shop((int) Tools::getValue('id_shop')); 479 $idRoot = $shop->id_category; 480 } else { 481 $idRoot = $categories[0]['id_category']; 482 } 483 484 $idShop = (int) Tools::getValue('id_shop'); 485 static::$currentIndex = static::$currentIndex.'&id_shop_group='.(int) (Tools::getValue('id_shop_group') ? 486 Tools::getValue('id_shop_group') : (isset($obj->id_shop_group) ? $obj->id_shop_group : Shop::getContextShopGroupID())); 487 $shop = new Shop($idShop); 488 $selectedCat = Shop::getCategories($idShop); 489 490 if (empty($selectedCat)) { 491 // get first category root and preselect all these children 492 $rootCategories = Category::getRootCategories(); 493 $rootCategory = new Category($rootCategories[0]['id_category']); 494 $children = $rootCategory->getAllChildren($this->context->language->id); 495 $selectedCat[] = $rootCategories[0]['id_category']; 496 497 foreach ($children as $child) { 498 $selectedCat[] = $child->id; 499 } 500 } 501 502 if (Shop::getContext() == Shop::CONTEXT_SHOP && Tools::isSubmit('id_shop')) { 503 $rootCategory = new Category($shop->id_category); 504 } else { 505 $rootCategory = new Category($idRoot); 506 } 507 508 $this->fields_form['input'][] = [ 509 'type' => 'categories', 510 'name' => 'categoryBox', 511 'label' => $this->l('Associated categories'), 512 'tree' => [ 513 'id' => 'categories-tree', 514 'selected_categories' => $selectedCat, 515 'root_category' => $rootCategory->id, 516 'use_search' => true, 517 'use_checkbox' => true, 518 ], 519 'desc' => $this->l('By selecting associated categories, you are choosing to share the categories between shops. Once associated between shops, any alteration of this category will impact every shop.'), 520 ]; 521 522 $themes = Theme::getThemes(); 523 if (!isset($obj->id_theme)) { 524 foreach ($themes as $theme) { 525 if (isset($theme->id)) { 526 $idTheme = $theme->id; 527 break; 528 } 529 } 530 } 531 532 $this->fields_form['input'][] = [ 533 'type' => 'theme', 534 'label' => $this->l('Theme'), 535 'name' => 'theme', 536 'values' => $themes, 537 ]; 538 539 $this->fields_form['submit'] = [ 540 'title' => $this->l('Save'), 541 ]; 542 543 if (Shop::getTotalShops() > 1 && $obj->id) { 544 $disabled = ['active' => false]; 545 } else { 546 $disabled = false; 547 } 548 549 $importData = [ 550 'carrier' => $this->l('Carriers'), 551 'cms' => $this->l('CMS pages'), 552 'contact' => $this->l('Contact information'), 553 'country' => $this->l('Countries'), 554 'currency' => $this->l('Currencies'), 555 'discount' => $this->l('Discount prices'), 556 'employee' => $this->l('Employees'), 557 'image' => $this->l('Images'), 558 'lang' => $this->l('Languages'), 559 'manufacturer' => $this->l('Manufacturers'), 560 'module' => $this->l('Modules'), 561 'hook_module' => $this->l('Module hooks'), 562 'meta_lang' => $this->l('Meta information'), 563 'product' => $this->l('Products'), 564 'product_attribute' => $this->l('Product combinations'), 565 'scene' => $this->l('Scenes'), 566 'stock_available' => $this->l('Available quantities for sale'), 567 'store' => $this->l('Stores'), 568 'warehouse' => $this->l('Warehouses'), 569 'webservice_account' => $this->l('Webservice accounts'), 570 'attribute_group' => $this->l('Attribute groups'), 571 'feature' => $this->l('Features'), 572 'group' => $this->l('Customer groups'), 573 'tax_rules_group' => $this->l('Tax rules groups'), 574 'supplier' => $this->l('Suppliers'), 575 'referrer' => $this->l('Referrers/affiliates'), 576 'zone' => $this->l('Zones'), 577 'cart_rule' => $this->l('Cart rules'), 578 ]; 579 580 // Hook for duplication of shop data 581 $modulesList = Hook::getHookModuleExecList('actionShopDataDuplication'); 582 if (is_array($modulesList) && count($modulesList) > 0) { 583 foreach ($modulesList as $m) { 584 $importData['Module'.ucfirst($m['module'])] = Module::getModuleName($m['module']); 585 } 586 } 587 588 asort($importData); 589 590 if (!$this->object->id) { 591 $this->fields_import_form = [ 592 'radio' => [ 593 'type' => 'radio', 594 'label' => $this->l('Import data'), 595 'name' => 'useImportData', 596 'value' => 1, 597 ], 598 'select' => [ 599 'type' => 'select', 600 'name' => 'importFromShop', 601 'label' => $this->l('Choose the source shop'), 602 'options' => [ 603 'query' => Shop::getShops(false), 604 'name' => 'name', 605 ], 606 ], 607 'allcheckbox' => [ 608 'type' => 'checkbox', 609 'label' => $this->l('Choose data to import'), 610 'values' => $importData, 611 ], 612 'desc' => $this->l('Use this option to associate data (products, modules, etc.) the same way for each selected shop.'), 613 ]; 614 } 615 616 $this->fields_value = [ 617 'id_shop_group' => (Tools::getValue('id_shop_group') ? Tools::getValue('id_shop_group') : 618 (isset($obj->id_shop_group)) ? $obj->id_shop_group : Shop::getContextShopGroupID()), 619 'id_category' => (Tools::getValue('id_category') ? Tools::getValue('id_category') : 620 (isset($obj->id_category)) ? $obj->id_category : (int) Configuration::get('PS_HOME_CATEGORY')), 621 'id_theme_checked' => (isset($obj->id_theme) ? $obj->id_theme : $idTheme), 622 ]; 623 624 $idsCategory = []; 625 $shops = Shop::getShops(false); 626 foreach ($shops as $shop) { 627 $idsCategory[$shop['id_shop']] = $shop['id_category']; 628 } 629 630 $this->tpl_form_vars = [ 631 'disabled' => $disabled, 632 'checked' => (Tools::getValue('addshop') !== false) ? true : false, 633 'defaultShop' => (int) Configuration::get('PS_SHOP_DEFAULT'), 634 'ids_category' => $idsCategory, 635 ]; 636 if (isset($this->fields_import_form)) { 637 $this->tpl_form_vars = array_merge($this->tpl_form_vars, ['form_import' => $this->fields_import_form]); 638 } 639 640 return parent::renderForm(); 641 } 642 643 /** 644 * Object creation 645 * 646 * @return void 647 * 648 * @since 1.0.0 649 */ 650 public function processAdd() 651 { 652 if (!Tools::getValue('categoryBox') || !in_array(Tools::getValue('id_category'), Tools::getValue('categoryBox'))) { 653 $this->errors[] = $this->l('You need to select at least the root category.'); 654 } 655 656 if (Tools::isSubmit('id_category_default')) { 657 $_POST['id_category'] = (int) Tools::getValue('id_category_default'); 658 } 659 660 /* Checking fields validity */ 661 $this->validateRules(); 662 663 if (!count($this->errors)) { 664 /** @var Shop $object */ 665 $object = new $this->className(); 666 $this->copyFromPost($object, $this->table); 667 $this->beforeAdd($object); 668 if (!$object->add()) { 669 $this->errors[] = Tools::displayError('An error occurred while creating an object.'). 670 ' <b>'.$this->table.' ('.Db::getInstance()->getMsgError().')</b>'; 671 } /* voluntary do affectation here */ 672 elseif (($_POST[$this->identifier] = $object->id) && $this->postImage($object->id) && !count($this->errors) && $this->_redirect) { 673 $parentId = (int) Tools::getValue('id_parent', 1); 674 $this->afterAdd($object); 675 $this->updateAssoShop($object->id); 676 // Save and stay on same form 677 if (Tools::isSubmit('submitAdd'.$this->table.'AndStay')) { 678 $this->redirect_after = static::$currentIndex.'&shop_id='.(int) $object->id.'&conf=3&update'.$this->table.'&token='.$this->token; 679 } 680 // Save and back to parent 681 if (Tools::isSubmit('submitAdd'.$this->table.'AndBackToParent')) { 682 $this->redirect_after = static::$currentIndex.'&shop_id='.(int) $parentId.'&conf=3&token='.$this->token; 683 } 684 // Default behavior (save and back) 685 if (empty($this->redirect_after)) { 686 $this->redirect_after = static::$currentIndex.($parentId ? '&shop_id='.$object->id : '').'&conf=3&token='.$this->token; 687 } 688 } 689 } 690 691 $this->errors = array_unique($this->errors); 692 if (count($this->errors) > 0) { 693 $this->display = 'add'; 694 695 return; 696 } 697 698 $object->associateSuperAdmins(); 699 700 $categories = Tools::getValue('categoryBox'); 701 array_unshift($categories, Configuration::get('PS_ROOT_CATEGORY')); 702 Category::updateFromShop($categories, $object->id); 703 if (Tools::getValue('useImportData') && ($importData = Tools::getValue('importData')) && is_array($importData) && isset($importData['product'])) { 704 ini_set('max_execution_time', 7200); // like searchcron.php 705 Search::indexation(true); 706 } 707 708 return $object; 709 } 710 711 /** 712 * @param Shop $newShop 713 * 714 * @return bool 715 * 716 * @since 1.0.0 717 */ 718 protected function afterAdd($newShop) 719 { 720 $importData = Tools::getValue('importData', []); 721 722 // The root category should be at least imported 723 $newShop->copyShopData((int) Tools::getValue('importFromShop'), $importData); 724 725 // copy default data 726 if (!Tools::getValue('useImportData') || (is_array($importData) && !isset($importData['group']))) { 727 $sql = 'INSERT INTO `'._DB_PREFIX_.'group_shop` (`id_shop`, `id_group`) 728 VALUES 729 ('.(int) $newShop->id.', '.(int) Configuration::get('PS_UNIDENTIFIED_GROUP').'), 730 ('.(int) $newShop->id.', '.(int) Configuration::get('PS_GUEST_GROUP').'), 731 ('.(int) $newShop->id.', '.(int) Configuration::get('PS_CUSTOMER_GROUP').') 732 '; 733 Db::getInstance()->execute($sql); 734 } 735 736 return parent::afterAdd($newShop); 737 } 738 739 /** 740 * Display edit link 741 * 742 * @param null $token 743 * @param int $id 744 * @param null $name 745 * 746 * @return string|void 747 * 748 * @since 1.0.0 749 */ 750 public function displayEditLink($token = null, $id, $name = null) 751 { 752 if ($this->tabAccess['edit'] == 1) { 753 $tpl = $this->createTemplate('helpers/list/list_action_edit.tpl'); 754 if (!array_key_exists('Edit', static::$cache_lang)) { 755 static::$cache_lang['Edit'] = $this->l('Edit', 'Helper'); 756 } 757 758 $tpl->assign( 759 [ 760 'href' => $this->context->link->getAdminLink('AdminShop').'&shop_id='.(int) $id.'&update'.$this->table, 761 'action' => static::$cache_lang['Edit'], 762 'id' => $id, 763 ] 764 ); 765 766 return $tpl->fetch(); 767 } else { 768 return; 769 } 770 } 771 772 /** 773 * Initialize categories association 774 * 775 * @param null $idRoot 776 * 777 * @return string 778 * 779 * @since 1.0.0 780 */ 781 public function initCategoriesAssociation($idRoot = null) 782 { 783 if (is_null($idRoot)) { 784 $idRoot = Configuration::get('PS_ROOT_CATEGORY'); 785 } 786 $idShop = (int) Tools::getValue('id_shop'); 787 $shop = new Shop($idShop); 788 $selectedCat = Shop::getCategories($idShop); 789 if (empty($selectedCat)) { 790 // get first category root and preselect all these children 791 $rootCategories = Category::getRootCategories(); 792 $rootCategory = new Category($rootCategories[0]['id_category']); 793 $children = $rootCategory->getAllChildren($this->context->language->id); 794 $selectedCat[] = $rootCategories[0]['id_category']; 795 796 foreach ($children as $child) { 797 $selectedCat[] = $child->id; 798 } 799 } 800 if (Shop::getContext() == Shop::CONTEXT_SHOP && Tools::isSubmit('id_shop')) { 801 $rootCategory = new Category($shop->id_category); 802 } else { 803 $rootCategory = new Category($idRoot); 804 } 805 $rootCategory = ['id_category' => $rootCategory->id, 'name' => $rootCategory->name[$this->context->language->id]]; 806 807 $helper = new Helper(); 808 809 return $helper->renderCategoryTree($rootCategory, $selectedCat, 'categoryBox', false, true); 810 } 811 812 /** 813 * Ajax process tree 814 * 815 * @return void 816 * 817 * @since 1.0.0 818 */ 819 public function ajaxProcessTree() 820 { 821 $tree = []; 822 $sql = 'SELECT g.id_shop_group, g.name as group_name, s.id_shop, s.name as shop_name, u.id_shop_url, u.domain, u.physical_uri, u.virtual_uri 823 FROM '._DB_PREFIX_.'shop_group g 824 LEFT JOIN '._DB_PREFIX_.'shop s ON g.id_shop_group = s.id_shop_group 825 LEFT JOIN '._DB_PREFIX_.'shop_url u ON u.id_shop = s.id_shop 826 ORDER BY g.name, s.name, u.domain'; 827 $results = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); 828 foreach ($results as $row) { 829 $idShopGroup = $row['id_shop_group']; 830 $idShop = $row['id_shop']; 831 $idShopUrl = $row['id_shop_url']; 832 833 // Group list 834 if (!isset($tree[$idShopGroup])) { 835 $tree[$idShopGroup] = [ 836 'data' => [ 837 'title' => '<b>'.$this->l('Group').'</b> '.$row['group_name'], 838 'icon' => 'themes/'.$this->context->employee->bo_theme.'/img/tree-multishop-groups.png', 839 'attr' => [ 840 'href' => $this->context->link->getAdminLink('AdminShop').'&id_shop_group='.$idShopGroup, 841 'title' => sprintf($this->l('Click here to display the shops in the %s shop group', 'AdminShop', false, false), $row['group_name']), 842 ], 843 ], 844 'attr' => [ 845 'id' => 'tree-group-'.$idShopGroup, 846 ], 847 'children' => [], 848 ]; 849 } 850 851 // Shop list 852 if (!$idShop) { 853 continue; 854 } 855 856 if (!isset($tree[$idShopGroup]['children'][$idShop])) { 857 $tree[$idShopGroup]['children'][$idShop] = [ 858 'data' => [ 859 'title' => $row['shop_name'], 860 'icon' => 'themes/'.$this->context->employee->bo_theme.'/img/tree-multishop-shop.png', 861 'attr' => [ 862 'href' => $this->context->link->getAdminLink('AdminShopUrl').'&shop_id='.(int) $idShop, 863 'title' => sprintf($this->l('Click here to display the URLs of the %s shop', 'AdminShop', false, false), $row['shop_name']), 864 ], 865 ], 866 'attr' => [ 867 'id' => 'tree-shop-'.$idShop, 868 ], 869 'children' => [], 870 ]; 871 } 872 // Url list 873 if (!$idShopUrl) { 874 continue; 875 } 876 877 if (!isset($tree[$idShopGroup]['children'][$idShop]['children'][$idShopUrl])) { 878 $url = $row['domain'].$row['physical_uri'].$row['virtual_uri']; 879 if (strlen($url) > 23) { 880 $url = substr($url, 0, 23).'...'; 881 } 882 883 $tree[$idShopGroup]['children'][$idShop]['children'][$idShopUrl] = [ 884 'data' => [ 885 'title' => $url, 886 'icon' => 'themes/'.$this->context->employee->bo_theme.'/img/tree-multishop-url.png', 887 'attr' => [ 888 'href' => $this->context->link->getAdminLink('AdminShopUrl').'&updateshop_url&id_shop_url='.$idShopUrl, 889 'title' => $row['domain'].$row['physical_uri'].$row['virtual_uri'], 890 ], 891 ], 892 'attr' => [ 893 'id' => 'tree-url-'.$idShopUrl, 894 ], 895 ]; 896 } 897 } 898 899 // jstree need to have children as array and not object, so we use sort to get clean keys 900 // DO NOT REMOVE this code, even if it seems really strange ;) 901 sort($tree); 902 foreach ($tree as &$groups) { 903 sort($groups['children']); 904 foreach ($groups['children'] as &$shops) { 905 sort($shops['children']); 906 } 907 } 908 909 $tree = [ 910 [ 911 'data' => [ 912 'title' => '<b>'.$this->l('Shop groups list').'</b>', 913 'icon' => 'themes/'.$this->context->employee->bo_theme.'/img/tree-multishop-root.png', 914 'attr' => [ 915 'href' => $this->context->link->getAdminLink('AdminShopGroup'), 916 'title' => $this->l('Click here to display the list of shop groups', 'AdminShop', false, false), 917 ], 918 ], 919 'attr' => [ 920 'id' => 'tree-root', 921 ], 922 'state' => 'open', 923 'children' => $tree, 924 ], 925 ]; 926 927 $this->ajaxDie(json_encode($tree)); 928 } 929 930 /** 931 * @param Shop $newShop 932 * 933 * @return bool 934 * 935 * @since 1.0.0 936 */ 937 protected function afterUpdate($newShop) 938 { 939 $categories = Tools::getValue('categoryBox'); 940 941 if (!is_array($categories)) { 942 $this->errors[] = $this->l('Please create some sub-categories for this root category.'); 943 944 return false; 945 } 946 947 array_unshift($categories, Configuration::get('PS_ROOT_CATEGORY')); 948 949 if (!Category::updateFromShop($categories, $newShop->id)) { 950 $this->errors[] = $this->l('You need to select at least the root category.'); 951 } 952 if (Tools::getValue('useImportData') && ($importData = Tools::getValue('importData')) && is_array($importData)) { 953 $newShop->copyShopData((int) Tools::getValue('importFromShop'), $importData); 954 } 955 956 if (Tools::isSubmit('submitAddshopAndStay') || Tools::isSubmit('submitAddshop')) { 957 $this->redirect_after = static::$currentIndex.'&shop_id='.(int) $newShop->id.'&conf=4&token='.$this->token; 958 } 959 960 return parent::afterUpdate($newShop); 961 } 962} 963