* @copyright Since 2013 Ovidiu Cimpean * @license Do not edit, modify or copy this file * * @version Release: 4 */ use PQNP\Config; use PQNP\Version; if (!defined('_PS_VERSION_')) { exit; } require_once dirname(__FILE__).'/config/config.inc.php'; class NewsletterPro extends Module { public $url_location = ''; public $uri_location = ''; public $dir_location = ''; public $tpl_location = ''; public $lang_img_path = ''; public $lang_img_dir = ''; public $class_name = 'AdminNewsletterPro'; public $menu_name = 'Newsletter Pro'; public $ajax_file_name = 'ajax_newsletterpro.php'; public $id_parent = 11; public $token = ''; public $link = ''; public $default_campaign_params = ''; public $request; public $response; /** * @var NewsletterProUpgrade */ public $upgrade = null; /** * The value needs to be changed from the file config.ini. * * @var int */ public $step; public $my_account_url = ''; public $ajax_destination = ''; // public $subscribe_hooks = array('displayFooterBefore', 'displayFooter', 'displayRightColumn', 'displayLeftColumn'); /** * @var NewsletterProMailChimpController */ public $chimp; /* ini configuration */ public $uninstall_all_tables = false; public $ini_config; public $demo_mode; public static $replace_vars; public static $instance; public $embed_images_message; public $embed_images_attachments = []; public $context; /** * @var NewsletterProSubscriptionTpl */ private $subscription_tpl; private $dev_subscription_tpl; const SEND_BOOSTER = true; const BACKUP_TYPE = 'xml'; const BACKUP_TYPE_XML = 1; const BACKUP_TYPE_SQL = 2; /** * This constants need to be changed also in the file init.js. */ const SEND_METHOD_DEFAULT = 0; const SEND_METHOD_ANTIFLOOD = 1; const SEND_THROTTLER_TYPE_EMAILS = 0; const SEND_THROTTLER_TYPE_MB = 1; /* the value is md5(newsletterpro) */ const NEWSLETTER_PRO_KEY = '5a112de88bead4ef8eeb07825d5af6e1'; /* * if the opton is false, you can import emails that already exists into ps_customer into the table ps_newsletter_pro_email, when you are importing a csv file */ const CSV_IMPORT_STRICT = true; const LIST_CUSTOMERS = 101; const LIST_VISITORS = 102; const LIST_VISITORS_NP = 103; const LIST_ADDED = 104; const SEARCH_CONDITION_CONTAINS = 100; const SEARCH_CONDITION_IS = 101; const SEARCH_CONDITION_IS_NOT = 102; const SEARCH_CONDITION_GREATER = 103; const SEARCH_CONDITION_LESS = 104; const REPLACE_ADMIN_PATH = true; /** * Test function. */ public function dev() { } public function devLoadSubscriptionTemplate($install_filename) { $dirname = _NEWSLETTER_PRO_DIR_.'/install/tables/subscription_tpl/'.$install_filename.'/'; $this->dev_subscription_tpl = NewsletterProSubscriptionTpl::loadFile($dirname, true, true); } /** * Init. */ public function __construct() { self::$instance = &$this; $this->name = 'newsletterpro'; $this->tab = 'advertising_marketing'; $this->version = '5.0.3'; $this->author = 'ProQuality'; $this->module_key = 'cd3f5ac1a07c62f20ba41465a387a8de'; $this->author_address = '0x79A346Cb657578a98e464200DFF789eE447A3e2a'; $this->ps_versions_compliancy = ['min' => '1.5', 'max' => _PS_VERSION_]; if (version_compare(_PS_VERSION_, '1.6.0.1', '>=')) { $this->bootstrap = true; } else { $this->bootstrap = false; } parent::__construct(); $this->displayName = $this->l('Newsletter Pro'); $this->description = $this->l('Advertise selected products from your store via newsletter.'); $this->confirmUninstall = $this->l('Are you sure you want to uninstall this module? All data will be lost. If you desire you can create a backup from the module "Settings" tab.'); if (defined('_PS_ADMIN_DIR_')) { $this->admin_name = basename(_PS_ADMIN_DIR_); } else { $this->admin_name = ''; } $this->displayCompatibilityError(); try { // this will protect the front office $module_dir = $this->relplaceAdminLink(_MODULE_DIR_); $ps_img = $this->relplaceAdminLink(_PS_IMG_); $this->_path = $this->relplaceAdminLink($this->_path); $this->request = new NewsletterProRequest(); $this->response = new NewsletterProResponse(); $this->upgrade = new NewsletterProUpgrade(); $this->initContext(); $this->initInitConfiguration(); $this->initConfiguration(); $this->url_location = Tools::getHttpHost(true).$module_dir.$this->name.'/'; $this->uri_location = $module_dir.$this->name.'/'; $this->dir_location = _PS_MODULE_DIR_.$this->name.'/'; $this->tpl_location = _PS_MODULE_DIR_.$this->name.'/mail_templates/'; $this->lang_img_path = Tools::getHttpHost(true).$ps_img.'l/'; $this->lang_img_dir = _PS_IMG_DIR_.'l/'; if (defined('_PS_ADMIN_DIR_')) { $this->ajax_destination = Version::isHigher('1.6.0.4') ? _PS_ADMIN_DIR_.'/filemanager/' : _PS_ADMIN_DIR_.'/ajaxfilemanager/'; } $this->my_account_url = $this->context->link->getModuleLink($this->name, 'myaccount'); $this->default_campaign_params = ['UTM_SOURCE' => 'Newsletter', 'UTM_MEDIUM' => 'email', 'UTM_CAMPAIGN' => '{newsletter_title}', 'UTM_CONTENT' => '{product_name}', ]; $this->token = Tools::getAdminToken($this->class_name.(int) Tab::getIdFromClassName($this->class_name).(int) $this->context->cookie->id_employee); $this->link = 'index.php?controller='.$this->class_name.'&token='.$this->token; $this->chimp = new NewsletterProMailChimpController(pqnp_config_get('CHIMP.API_KYE', '')); } catch (Exception $e) { NewsletterProLog::writeStrip($e->getMessage(), NewsletterProLog::ERROR_FILE); $this->exception_message = $e->getMessage(); } $this->dev(); } public static function getNewsletterProToken() { return Tools::encrypt(NewsletterPro::NEWSLETTER_PRO_KEY); } /** * Display the compatibility problems for older versions of prestashop. */ private function displayCompatibilityError() { if (Tools::isSubmit('controller') && Tools::strtolower(Tools::getValue('controller')) == Tools::strtolower('AdminNewsletterPro')) { if (version_compare(_PS_VERSION_, '1.5.1.0', '<=') && (!method_exists('Db', 'update') || !method_exists('Db', 'insert') || !method_exists('Db', 'delete'))) { exit(Tools::displayError( sprintf($this->l('You have to override the class "%s" from the folder "%s" into the folder "%s" in order to work properly. If you have experience with PHP please ask the developer to do this.'), 'Db.php', '/newsletterpro/compatibility/', '/override/classes/db/') )); } if (version_compare(_PS_VERSION_, '1.5.1.0', '<=')) { $reflection_error = sprintf($this->l('You need to change the property "%s" from private to protected variable, from the file "%s".'), '$asso_tables', 'Shop.php'); $reflection_class = new ReflectionClass('Shop'); try { $property = $reflection_class->getProperty('asso_tables'); if ($property->isPrivate()) { exit(Tools::displayError($reflection_error)); } } catch (Exception $e) { exit(Tools::displayError($reflection_error)); } } } } /** * Module installation. * * @return bool */ public function install() { if (Shop::isFeatureActive()) { Shop::setContext(Shop::CONTEXT_ALL); } @ini_set('max_execution_time', 600); $errors = []; $success = []; $success[] = parent::install() && $this->installConfiguration() && $this->installModuleTab('AdminNewsletterPro', 'Newsletter Pro') && $this->registerHook('header') && $this->registerHook('customerAccount') && $this->registerHook('createAccount') && $this->registerHook('actionShopDataDuplication') && $this->registerHook('backOfficeHeader') && $this->registerHook('actionAdminControllerSetMedia') && $this->registerHook('registerGDPRConsent') && $this->registerHook('actionDeleteGDPRCustomer') && $this->registerHook('actionExportGDPRData') && $this->registerHook('displayCustomerIdentityForm') && $this->registerHook('displayCustomerAccountForm') && $this->registerHook('actionCustomerAccountAdd') && $this->registerHook('actionCustomerAccountUpdate') && (Version::isLower('1.5.4.1') ? $this->installLang('id_lang') : true) && (Version::isLower('1.5.0.4') ? $this->updateShopName((string) Configuration::get('PS_SHOP_NAME')) : true) && $this->installFiles() && $this->installTemplates(); if (!Tools::isSubmit('reset')) { $success[] = $this->installDb(); } if (!($install_data = NewsletterProInstallData::newInstance($this)->execute($errors))) { $this->_errors = array_merge($this->_errors, $errors); } return !in_array(false, $success) && $install_data; } /** * Module desinstallation. * * @return bool */ public function uninstall() { // 10 minutes if need regards the prestashop uninstallation time bug, in some cases @ini_set('max_execution_time', 600); $success = []; $success[] = parent::uninstall() && $this->unregisterHook('backOfficeHeader') && $this->unregisterHook('actionAdminControllerSetMedia') && $this->unregisterHook('registerGDPRConsent') && $this->unregisterHook('actionDeleteGDPRCustomer') && $this->unregisterHook('actionExportGDPRData') && $this->unregisterHook('displayCustomerIdentityForm') && $this->unregisterHook('displayCustomerAccountForm') && $this->unregisterHook('actionCustomerAccountAdd') && $this->unregisterHook('actionCustomerAccountUpdate') && $this->uninstallConfiguration() && $this->uninstallAttachments() && $this->uninstallModuleTab('AdminNewsletterPro'); if (!Tools::isSubmit('reset')) { $success[] = $this->uninstallDb(); } return !in_array(false, $success); } public function installDemo() { NewsletterProTerminalCommand::setConfig('demo_mode', 0); // install users NewsletterProGenerateCustomers::newInstance()->generate(0, 20, 10, 20); // enable the templates pqnp_config('NEWSLETTER_TEMPLATE', 'responsive_template_0003.html'); pqnp_config('PRODUCT_TEMPLATE', 'responsive_template_0003_layout_3_products_blue.html'); // add mail connectin $smtp = new NewsletterProMail(); $smtp->method = NewsletterProMail::METHOD_MAIL; $smtp->name = 'MAIL - '.uniqid(); $smtp->from_name = ''; $smtp->from_email = Configuration::get('PS_SHOP_EMAIL'); $smtp->reply_to = ''; $smtp->domain = ''; $smtp->server = ''; $smtp->user = ''; $smtp->passwd = ''; $smtp->encryption = 'off'; $smtp->port = ''; $smtp->list_unsubscribe_active = false; $smtp->list_unsubscribe_email = ''; $smtp->add(); pqnp_config('SMTP_ACTIVE', true); pqnp_config('SMTP', (int) $smtp->id); // activate the subscription popup $this->newsletterproSubscriptionActive(true, ['displayFooter']); // setup the front subscription $subscription = new NewsletterProSubscriptionTpl(3); if (Validate::isLoadedObject($subscription)) { $subscription->show_on_pages = 'index'; $subscription->when_to_show = NewsletterProSubscriptionTpl::WHEN_TO_SHOW_POPUP_COOKIE; $subscription->cookie_lifetime = 1 / 24 / 60 / 60 * 60; $subscription->save(); } NewsletterProTerminalCommand::setConfig('demo_mode', 1); } /** * Initialize module configuration. */ public function initInitConfiguration() { $file = _PS_MODULE_DIR_.$this->name.'/config.ini'; if (file_exists($file)) { try { $config = @parse_ini_file($file); if (!$config) { $config = []; $init_file = Tools::file_get_contents($file); if (preg_match_all('/^\w+\s+?=\s+?\w+/m', $init_file, $matches)) { $matches = $matches[0]; foreach ($matches as $line) { $line_arr = explode('=', $line); $key = trim($line_arr[0]); $value = trim($line_arr[1]); if ('true' === $value) { $value = true; } elseif ('false' === $value) { $value = false; } else { $value = (int) $value; } $config[$key] = $value; } } } $this->ini_config = $config; if (isset($config['uninstall_all_tables'])) { $this->uninstall_all_tables = $config['uninstall_all_tables']; } if (isset($config['step'])) { $this->step = (int) $config['step']; } } catch (Exception $e) { NewsletterProLog::writeStrip($e->getMessage(), NewsletterProLog::ERROR_FILE); } } $file = _PS_MODULE_DIR_.$this->name.'/demo_mode.json'; if (file_exists($file)) { if ((int) pqnp_ini_config('demo_mode')) { $this->demo_mode = Tools::jsonDecode(Tools::file_get_contents($file), true); } } } /** * Install prestashop files for the older versions of prestashop. * * @return bool */ public function installFiles() { if (version_compare(_PS_VERSION_, '1.5.2.0', '<')) { $to_file = _PS_ROOT_DIR_.'/js/tiny_mce/plugins/'; $destination = $to_file.'fullpage/'; $zip_path = $this->dir_location.'install/tiny_mce/'; $zip_file = $zip_path.'fullpage.zip'; if (file_exists($zip_file)) { $zip = new ZipArchive(); if (true === $zip->open($zip_file)) { // create all folders for ($i = 0; $i < $zip->numFiles; ++$i) { $only_file_name = $zip->getNameIndex($i); $full_file_name = $zip->statIndex($i); if ('/' == $full_file_name['name'][Tools::strlen($full_file_name['name']) - 1]) { @NewsletterProTools::createFolder($zip_path.$full_file_name['name']); } } // unzip into the folders for ($i = 0; $i < $zip->numFiles; ++$i) { $only_file_name = $zip->getNameIndex($i); $full_file_name = $zip->statIndex($i); if (!('/' == $full_file_name['name'][Tools::strlen($full_file_name['name']) - 1])) { copy('zip://'.$zip_file.'#'.$only_file_name, $zip_path.$full_file_name['name']); } } $zip->close(); // unzip done // copy the folder only the folder does not exists if (file_exists($to_file) && !file_exists($destination)) { $move_file = $this->dir_location.'install/tiny_mce/fullpage/'; if (!file_exists($move_file)) { $this->addError(sprintf($this->l('The tiny mce plugin "%s" not exists for instalation.'), 'fullpage')); return false; } @NewsletterProTools::recurseCopy($move_file, $destination); } } else { $this->addError(sprintf($this->l('Failed to open file "%s"'), $zip_file)); } } } return true; } public function installTemplates() { $path = $this->tpl_location.'newsletter/'; $result = NewsletterProTools::getDirectoryIterator($path, '/^[a-zA-Z0-9_-]+$/'); $languages = Language::getLanguages(false); $index_file = $path.'index.php'; try { foreach ($result as $file) { if ($file->isDir()) { $folder_path = $file->getPathName(); if (!$file->isWritable()) { throw new Exception(sprintf($this->l('The file "%s" is not writable, please check the CHMOD permissions.'), $folder_path)); } $file_name = $file->getFileName().'.html'; $file_path = $folder_path.'/en/'.$file_name; foreach ($languages as $lang) { if ('en' != $lang['iso_code']) { $new_iso_path = $folder_path.'/'.$lang['iso_code']; if (!file_exists($new_iso_path)) { if (!mkdir($new_iso_path, 0777)) { throw new Exception(sprintf($this->l('Cannot create the directory "%s", please check the CHMOD permissions.'), $new_iso_path)); } } $copy_message = $this->l('Cannot copy the file "%s", please checked the CHMOD permissions.'); $new_index = $new_iso_path.'/index.php'; if (!copy($index_file, $new_index)) { throw new Exception(sprintf($copy_message, $new_index)); } $new_file_name = $new_iso_path.'/'.$file_name; if (!copy($file_path, $new_file_name)) { throw new Exception(sprintf($copy_message, $new_file_name)); } } } } } } catch (Exception $e) { $this->addError($e->getMessage()); return false; } return true; } /** * Get an instance of the module. * * @return NewsletterPro */ public static function getInstance() { return self::$instance; } /** * For Prestashop 1.6, for 1.7 read the dev/Readme.md file. * * Allow authentication with postman * * This function will be placed in the file admin/init.php * * $newsletterpro = Module::getInstanceByName('newsletterpro'); * if (Validate::isLoadedObject($newsletterpro)) * $newsletterpro->allowAuthorization(); * * You need to place in .htaccess file the lines * * RewriteEngine on * * RewriteCond %{HTTP:Authorization} ^(.*) * RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1] */ public function allowAuthorization() { if (function_exists('getallheaders')) { $headers = call_user_func('getallheaders'); if (isset($headers['Authorization']) && !empty($headers['Authorization'])) { $context = Context::getContext(); $authorization = explode(' ', $headers['Authorization']); $auth = call_user_func_array('base64_decode', [$authorization[1]]); $user = explode(':', $auth); if (isset($user[0], $user[1])) { $context->employee = new Employee(); $context->employee = $context->employee->getByEmail($user[0], $user[1]); if (Validate::isLoadedObject($context->employee)) { $context->employee->remote_addr = (int) ip2long(Tools::getRemoteAddr()); // Update cookie $cookie = Context::getContext()->cookie; $cookie->id_employee = $context->employee->id; $cookie->email = $context->employee->email; $cookie->profile = $context->employee->id_profile; $cookie->passwd = $context->employee->passwd; $cookie->remote_addr = $context->employee->remote_addr; if (!Tools::getValue('stay_logged_in')) { $cookie->last_activity = time(); } $cookie->write(); } } } } } /** * Get the MailChimp object. * * @return object */ public function getChimp() { return $this->chimp; } /** * Hook customer account. * * @return string */ public function hookCustomerAccount() { if ((bool) pqnp_config('DISPLYA_MY_ACCOUNT_NP_SETTINGS')) { $this->context->smarty->assign([ 'url_location' => $this->url_location, 'my_account_url' => $this->my_account_url, ]); if (NewsletterProTools::is17()) { return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/front/1.7/my_account_button.tpl')); } elseif ($this->isPS16()) { return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/front/1.6/my_account_button.tpl')); } else { return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/front/1.5/my_account_button.tpl')); } } return ''; } public function hookDisplayCustomerAccount() { return $this->hookCustomerAccount(); } /** * Get the module css path, according to the prestashop version. * * @return string */ public function getCssPath($default = false) { $css_path = $this->uri_location.'views/css/'; if ($default) { return $css_path; } if (Version::isLower('1.6.0.0')) { $css_path = $this->uri_location.'views/css/1.5/'; } else { $css_path = $this->uri_location.'views/css/1.6/'; } return $css_path; } /** * Get css dir path. * * @return string */ public function getCssDirPath() { $css_path = $this->dir_location.'views/css/'; if (Version::isLower('1.6.0.0')) { $css_path = $this->dir_location.'views/css/1.5/'; } else { $css_path = $this->dir_location.'views/css/1.6/'; } return $css_path; } /** * Id language exists. * * @param int $id_lang * * @return bool */ private function idLangExists($id_lang) { $languages = Language::getLanguages(true, $this->context->shop->id); foreach ($languages as $lang) { if ($id_lang == $lang['id_lang']) { return true; } } return false; } /** * Id gender exists. * * @param int $id_gender * * @return bool */ private function idGenderExists($id_gender) { $genders = Gender::getGenders(); foreach ($genders as $gender) { if ($gender->id_gender == $id_gender) { return true; } } return false; } /** * Close front subscription window popup, according to the cookie lifetime. * * @return json */ public function submitNewsletterProSubscribeCloseForever() { $response = new NewsletterProAjaxResponse(); $subscrbtion_template = NewsletterProSubscriptionTpl::getActiveTemplateInstance(); $one_day = 60 * 60 * 24; $life_time_days = round($one_day * (float) $subscrbtion_template->cookie_lifetime); $cookie = new NewsletterProCookie('subscription_template_front', time() + $life_time_days); $cookie->set('popup_show', '0'); if (true == (bool) $cookie->get('popup_show')) { $response->addError($this->l('An error occurred to proceed this action.')); } return $response->display(); } /** * Submit the front subscription forum. * * @return json */ public function submitNewsletterProSubscribe() { $response = new NewsletterProAjaxResponse([ 'msg' => '', 'displaySubscribeMessage' => false, ]); try { $subscribe = new NewsletterProSubscribers(); $subscribe->active = 1; $subscribe->firstname = Tools::getValue('firstname'); $subscribe->lastname = Tools::getValue('lastname'); $email = trim(Tools::getValue('email')); if (!empty($email)) { $subscribe->email = $email; } else { $response->addError($this->l('The email address cannot be empty.')); } $custom_variabels_hidden_keys = preg_grep('/^hidden_custom_variable_.*$/', array_keys($_POST)); if (!empty($custom_variabels_hidden_keys)) { $required_message = $this->l('You must fill all the required fields.'); foreach ($custom_variabels_hidden_keys as $variable_name) { $variable_name = str_replace('hidden_', '', $variable_name); $name = str_replace('custom_variable_', '', $variable_name); if (Tools::isSubmit($variable_name)) { $value = Tools::getValue($variable_name); $field = NewsletterProSubscribersCustomField::getInstanceByVariableName($name); if ($field) { if (is_array($value) && NewsletterProSubscribersCustomField::TYPE_CHECKBOX == $field->type) { if (empty($value)) { $response->addError($required_message); } $subscribe->{$name} = Tools::jsonEncode($value); } elseif (is_string($value)) { if ($field->isRequired()) { $tr = Tools::strlen(trim($value)); if (0 == $tr) { $response->addError($required_message); } } $subscribe->{$name} = $value; } } } else { $field = NewsletterProSubscribersCustomField::getInstanceByVariableName($name); if ($field) { if ($field->isRequired()) { $response->addError($required_message); } } } } } $id_lang = $this->context->language->id; if (Tools::isSubmit('id_lang')) { $get_id_lang = Tools::getValue('id_lang'); if ($this->idLangExists($get_id_lang)) { $id_lang = $get_id_lang; } } if (Tools::isSubmit('id_gender')) { $id_gender = Tools::getValue('id_gender'); if ($this->idGenderExists($id_gender)) { $subscribe->id_gender = (int) $id_gender; } } $subscribe->id_lang = (int) $id_lang; $days = trim(Tools::getValue('days')); $months = trim(Tools::getValue('months')); $years = trim(Tools::getValue('years')); if (!empty($days) && !empty($months) && !empty($years)) { $date = new DateTime(); $date->setDate((int) $years, (int) $months, (int) $days); $subscribe->birthday = $date->format('Y-m-d'); } if (Tools::isSubmit('list_of_interest')) { $list_of_interest = (int) Tools::getValue('list_of_interest'); if ($list_of_interest) { $subscribe->list_of_interest = $list_of_interest; } } else { $loi_array = []; $post_keys = array_keys($_POST); $loi_grep = preg_grep('/^list_of_interest_\d+$/', $post_keys); foreach ($loi_grep as $key) { if (Tools::isSubmit($key) && ($value = (int) Tools::getValue($key))) { $loi_array[] = $value; } } $subscribe->list_of_interest = rtrim(implode(',', $loi_array), ','); } $subscrbtion_template = NewsletterProSubscriptionTpl::getActiveTemplateInstance(); // check if the user is already registered to the newsletter if ($subscrbtion_template->allow_multiple_time_subscription) { $tables = [ 'customer' => ['primary' => 'id_customer', 'active' => 'newsletter'], 'newsletter_pro_subscribers' => ['primary' => 'id_newsletter_pro_subscribers', 'active' => 'active'], ]; if ((bool) pqnp_config('SUBSCRIPTION_ACTIVE')) { $tables['newsletter_pro_email'] = ['primary' => 'id_newsletter_pro_email', 'active' => 'active']; } if (NewsletterProTools::tableExists('newsletter')) { $tables['newsletter'] = ['primary' => 'id', 'active' => 'active']; } foreach ($tables as $table_name => $data) { $sql = 'SELECT `'.pSQL($data['primary']).'` FROM `'._DB_PREFIX_.pSQL($table_name).'` WHERE `email` = "'.pSQL($subscribe->email).'" AND `'.pSQL($data['active']).'` = 1'; if (Db::getInstance()->getValue($sql)) { $response->addError($this->l('The email address is already subscribed at our newsletter.')); } } } if (null != $subscrbtion_template->mandatory_fields) { $mandatory_fields = NewsletterProTools::unSerialize($subscrbtion_template->mandatory_fields); if (!empty($mandatory_fields)) { if (in_array('firstname', $mandatory_fields)) { $fn = trim($subscribe->firstname); if (empty($fn) || !Validate::isName($fn)) { $response->addError($this->l('The First Name field is required.')); } } if (in_array('lastname', $mandatory_fields)) { $ln = trim($subscribe->lastname); if (empty($ln) || !Validate::isName($ln)) { $response->addError($this->l('The Last Name field is required.')); } } } } $voucher = $subscrbtion_template->getVoucher(); if ($response->success()) { if (pqnp_config('SUBSCRIPTION_SECURE_SUBSCRIBE')) { $subscribe_temp = new NewsletterProSubscribersTemp(); $subscribe_temp->id_newsletter_pro_subscription_tpl = $subscrbtion_template->id; if (!$subscribe_temp->saveTemp($subscribe)) { $response->mergeErrors($subscribe_temp->getErrors()); } else { $link = $this->context->link->getModuleLink('newsletterpro', 'subscribeconfirmation', ['token' => $subscribe_temp->token]); $subscrbtion_template->extendVars([ 'firstname' => htmlentities(Tools::getValue('firstname')), 'lastname' => htmlentities(Tools::getValue('lastname')), 'email_confirmation_link' => $link, 'email_confirmation' => ''.$this->l('here').'', ]); $secure_subscribe_msg = trim($subscrbtion_template->renderEmailSubscribeConfirmationMessage((int) $this->context->language->id)); $secure_subscribe_msg_strip = trim(strip_tags($secure_subscribe_msg)); $email_title = $this->l('Newsletter Subscription Confirmation'); $email_body = ''; if (!empty($secure_subscribe_msg_strip)) { $email_body = $secure_subscribe_msg; } else { $file_tpl = dirname(__FILE__).'/views/templates/front/newsletter_subscribe.tpl'; $this->context->smarty->assign([ 'confirmation_link' => $link, ]); $content = $this->context->smarty->fetch($file_tpl); $template = NewsletterProTemplate::newString(['', $content], $subscribe->email)->load(); $message = $template->message(); $email_title = $message['title']; $email_body = $message['body']; } if (pqnp_config('DEBUG_MODE')) { $send = NewsletterProSendManager::getInstance()->sendNewsletter($email_title, $email_body, $subscribe_temp->email, [], [], false); } else { $send = @NewsletterProSendManager::getInstance()->sendNewsletter($email_title, $email_body, $subscribe_temp->email, [], [], false); } if (is_array($send)) { $response->addError($this->l('An error occurred when sending the confirmation email.')); } } } else { $id_duplicate = (int) $subscribe->isDuplicateEmail(); if ($id_duplicate) { $subscribe->id = $id_duplicate; if (!$subscribe->update()) { $response->mergeErrors($subscribe->getErrors()); } else { // if the customer is not logged it the consent_date will be null NewsletterProSubscriptionConsent::newInstance()->set($subscribe->email, (bool) $subscribe->active, $this->context->customer->isLogged())->add(); } } else { if (!$subscribe->add()) { $response->mergeErrors($subscribe->getErrors()); } else { // if the customer is not logged it the consent_date will be null NewsletterProSubscriptionConsent::newInstance()->set($subscribe->email, (bool) $subscribe->active, $this->context->customer->isLogged())->add(); } } } } if ($response->success()) { if (!pqnp_config('SUBSCRIPTION_SECURE_SUBSCRIBE')) { $subscribe_msg = trim($subscrbtion_template->renderSubscribeMessage((int) $this->context->language->id)); $subscribe_msg_strip = trim(strip_tags($subscribe_msg)); if ($subscrbtion_template->display_subscribe_message && !empty($subscribe_msg_strip)) { $response->set('displaySubscribeMessage', true); $response->set('msg', $subscribe_msg); } elseif (!empty($subscribe_msg_strip)) { $response->set('msg', $subscribe_msg); } else { $success_msg = $this->l('You have been successfully subscribed to our newsletter.'); if ($voucher) { $response->set('msg', $success_msg.sprintf($this->l('You can use this voucher %s.'), $voucher)); } else { $response->set('msg', $success_msg); } } // send the email with the voucher it the voucher exists if ($voucher) { $subscribe_voucher_msg = trim($subscrbtion_template->renderEmailSubscribeVoucherMessage((int) $this->context->language->id)); $subscribe_voucher_msg_strip = trim(strip_tags($subscribe_voucher_msg)); if (!empty($subscribe_voucher_msg_strip)) { if (pqnp_config('DEBUG_MODE')) { $send = NewsletterProSendManager::getInstance()->sendNewsletter($this->l('Newsletter Subscription Voucher'), $subscribe_voucher_msg, $subscribe->email, [], [], false); } else { $send = @NewsletterProSendManager::getInstance()->sendNewsletter($this->l('Newsletter Subscription Voucher'), $subscribe_voucher_msg, $subscribe->email, [], [], false); } } } } else { if ($subscrbtion_template->display_subscribe_message) { $response->set('displaySubscribeMessage', true); } else { $response->set('displaySubscribeMessage', false); } $response->set('msg', sprintf($this->l('A configuration email has been sent to the email address "%s". To subscribe please click on the link from your email address.'), $subscribe->email)); } } } catch (Exception $e) { NewsletterProLog::writeStrip($e->getMessage(), NewsletterProLog::ERROR_FILE); $response->addError($this->l('An error occurred.')); } $response->errors = array_unique($response->errors); return $response->display(); } /** * Get shop logo. * * @param int $id_shop * * @return string */ public function getShopLogoUrl($id_shop = null) { if (!isset($id_shop)) { $id_shop = (int) $this->context->shop->id; } $theme_logo = Configuration::get('PS_LOGO'); if (isset($theme_logo) && Tools::strlen($theme_logo) > 0 && file_exists(_PS_IMG_DIR_.$theme_logo)) { $shop_logo_url = Tools::getHttpHost(true)._PS_IMG_.$theme_logo; $shop_logo_url = $this->relplaceAdminLink($shop_logo_url); return $shop_logo_url; } $row = Db::getInstance()->getRow(' SELECT `value` FROM `'._DB_PREFIX_.'configuration` WHERE `name`="PS_LOGO_MAIL" AND `id_shop` = '.(int) $id_shop.' '); $ps_logo_mail = isset($row['value']) ? $row['value'] : pqnp_config('PS_LOGO_MAIL'); $shop_logo_url = ''; if (false !== $ps_logo_mail && file_exists(_PS_IMG_DIR_.$ps_logo_mail)) { $shop_logo_url = Tools::getHttpHost(true)._PS_IMG_.$ps_logo_mail; } else { if (file_exists(_PS_IMG_DIR_.'logo.jpg')) { $shop_logo_url = Tools::getHttpHost(true)._PS_IMG_.'logo.jpg'; } } $shop_logo_url = $this->relplaceAdminLink($shop_logo_url); return $shop_logo_url; } /** * Process the ajax requests. * * @return die */ public function ajaxProcess() { $ajax = new NewsletterProAjaxController(); $ajax->processFront(Tools::getValue('submit')); } /** * Check of the availability of the uniform js library. * * @return bool */ public static function isUniformRequired() { return version_compare(_PS_VERSION_, '1.6.0.1', '<'); } /** * Include the uniform js library. * * @param object $controller */ public static function includeUniform($controller) { $module = NewsletterPro::getInstance(); $controller->addCSS($module->uri_location.'views/css/uniform.default.css'); $controller->addJS([ $module->uri_location.'views/js/jquery.uniform.min.js', ]); } /** * Check of the availabillity of the fontawoseme css library. * * @return bool */ public static function isFontAwesomeRequired() { // some of the icons are not displaied on prestashop 1.6.0.6, and I've updated to 1.6.1 return version_compare(_PS_VERSION_, '1.6.1', '<'); } /** * Include the fontawesome js library. * * @param object $controller */ public static function includeFontAwesome($controller) { $module = NewsletterPro::getInstance(); $controller->addCSS($module->uri_location.'views/css/font-awesome.css'); } private function initPopup() { if ((int) pqnp_config('SUBSCRIPTION_ACTIVE')) { if (isset($this->dev_subscription_tpl)) { // for development $this->subscription_tpl = $this->dev_subscription_tpl; } else { $this->subscription_tpl = NewsletterProSubscriptionTpl::getActiveTemplateInstance(); } $this->context->controller->addCSS(NewsletterProTools::getCSS('newsletter_subscribe_block.css'), 'all'); $css_path = $this->getCssPath(); if (self::isUniformRequired()) { self::includeUniform($this->context->controller); } if (self::isFontAwesomeRequired()) { self::includeFontAwesome($this->context->controller); } $this->context->controller->addCSS($this->uri_location.'views/css/'.NewsletterProTools::getVersion().'/'.NewsletterProSubscriptionTpl::CSS_STYLE_GLOBAL_PATH, 'all'); $css_details = $this->subscription_tpl->getSubscriptionCSSLinkWithDetails(); if ($css_details['file_exists']) { $this->context->controller->addCSS($css_details['link']); } else { // cannot add the file with the regular function addCSS $this->context->controller->css_files[$css_details['link']] = 'all'; } $this->context->controller->addCSS($css_path.'front_window.css', 'all'); $this->loadSubscriptionControllerTemplate(); NewsletterProAppStorage::extend([ 'subscription_tpl_loader_better' => (bool) $this->subscription_tpl->render_loader, // 'subscription_tpl_loader_better' => true, 'subscription_tpl' => $this->subscription_tpl->getJSData(), 'subscription_tpl_render' => $this->subscription_tpl->render((int) $this->context->language->id), ]); } } private function loadSubscriptionControllerTemplate() { $templateId = (int) pqnp_config_get('SUBSCRIPTION_CONTROLLER_TEMPLATE_ID', 0); $template = new NewsletterProSubscriptionTpl($templateId); if (Validate::isLoadedObject($template)) { $css_details = $template->getSubscriptionCSSLinkWithDetails(); if ($css_details['file_exists']) { $this->context->controller->addCSS($css_details['link']); } else { // cannot add the file with the regular function addCSS $this->context->controller->css_files[$css_details['link']] = 'all'; } NewsletterProAppStorage::extend([ 'subscription_controller_tpl_render' => $template->render((int) $this->context->language->id), ]); } } /** * Hook display top. * * @param array $params * * @return string */ public function hookDisplayTop($params) { $output = []; try { if (pqnp_config('SUBSCRIPTION_ACTIVE') && isset($this->subscription_tpl)) { if (NewsletterProSubscriptionTpl::RENDER_LOADER_BETTER === (int) $this->subscription_tpl->render_loader) { return ''; } $this->context->smarty->assign([ 'display_in_footer' => true, 'tpl_location' => $this->dir_location.'views/', 'render_template' => $this->subscription_tpl->render((int) $this->context->language->id), 'subscription_template_front_info' => pqnp_addcslashes(Tools::jsonEncode($this->subscription_tpl->getJSData())), ]); $output[] = $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/hook/newsletter_subscribe.tpl')); } } catch (Exception $e) { NewsletterProLog::writeStrip($e->getMessage(), NewsletterProLog::ERROR_FILE); } // $this->restoreJqueryIfNeeded('displayTop'); return implode('', $output); } /** * Get languages. * * @return array */ public function getLanguages() { $languages = Language::getLanguages(true, $this->context->shop->id); foreach ($languages as &$lang) { if ($lang['id_lang'] == $this->context->language->id) { $lang['selected'] = true; } else { $lang['selected'] = false; } } return $languages; } /** * Hook display left column. * * @param array $params * * @return string */ public function hookDisplayLeftColumn($params) { return (new NewsletterProSubscriptionHook())->display('displayLeftColumn'); } /** * Hook display right column. * * @param array $params * * @return string */ public function hookDisplayRightColumn($params) { return (new NewsletterProSubscriptionHook())->display('displayRightColumn'); } /** * Hook display footer column. * * @param array $params * * @return string */ public function hookFooter($params) { return (new NewsletterProSubscriptionHook())->display('displayFooter'); } public function hookDisplayFooter($params) { return (new NewsletterProSubscriptionHook())->display('displayFooter'); } public function hookDisplayFooterBefore($params) { return (new NewsletterProSubscriptionHook())->display('displayFooterBefore'); } /** * Hook action shop data duplicate. * * @param array $params * * @return string */ public function hookActionShopDataDuplication($params) { try { $old_id_shop = (int) $params['old_id_shop']; $new_id_shop = (int) $params['new_id_shop']; if (!$old_id_shop) { $old_id_shop = Configuration::get('PS_SHOP_DEFAULT'); } $deleted = false; $asso_tables = array_merge( NewsletterProSubscriptionTpl::getAssoTables(), NewsletterProListOfInterest::getAssoTables() ); foreach ($asso_tables as $table_name => $row) { $id = 'id_'.$row['type']; if ('fk_shop' == $row['type'] || preg_match('/_lang$/', $table_name)) { $id = 'id_shop'; } else { $table_name .= '_'.$row['type']; } if (!$deleted) { $res = Db::getInstance()->getRow('SELECT * FROM `'._DB_PREFIX_.$table_name.'` WHERE `'.$id.'` = '.(int) $old_id_shop); if ($res) { unset($res[$id]); if (isset($row['primary'])) { unset($res[$row['primary']]); } $keys = implode('`, `', array_keys($res)); $sql = 'INSERT IGNORE INTO `'._DB_PREFIX_.$table_name.'` (`'.$keys.'`, '.$id.') (SELECT `'.$keys.'`, '.(int) $new_id_shop.' FROM '._DB_PREFIX_.$table_name.' WHERE `'.$id.'` = '.(int) $old_id_shop.')'; } Db::getInstance()->execute($sql); } } } catch (Exception $e) { NewsletterProLog::writeStrip($e->getMessage(), NewsletterProLog::ERROR_FILE); if (_PS_MODE_DEV_) { exit(Tools::displayError($e->getMessage())); } } } public function hookBackOfficeHeader() { if ('AdminNewsletterPro' == $this->context->controller->controller_name) { // for prestashop 1.5 if (!method_exists('Media', 'addJsDef') || version_compare('1.6.0.9', _PS_VERSION_, '==')) { return NewsletterProTools::getJsDefScript([ 'NewsletterProAppStorage' => NewsletterProAppStorage::get('app'), 'NewsletterProAppTranslate' => NewsletterProAppTranslate::get('app'), ]); } } } public function hookActionAdminControllerSetMedia() { if ('AdminNewsletterPro' == $this->context->controller->controller_name) { } } private function getJSData() { $data = [ 'ajax_url' => Context::getContext()->link->getModuleLink($this->name, 'ajax', []), 'isPS17' => NewsletterProTools::is17(), 'psVersion' => NewsletterProTools::getVersion(), 'configuration' => [ 'CROSS_TYPE_CLASS' => pqnp_config('CROSS_TYPE_CLASS'), ], ]; if ($this->context->controller && $this->context->controller instanceof NewsletterProMyAccountModuleFrontController) { $tree = NewsletterProCategoryTree::newInstance((int) $this->context->customer->id); $data['home_category'] = $tree->home($this->context->language->id, $this->context->shop->id); } $js_data = [ 'NewsletterProAppStorage' => NewsletterProAppStorage::get('app_front'), 'NewsletterProAppTranslate' => NewsletterProAppTranslate::get('app_front'), 'NewsletterPro_Data' => $data, 'NPRO_AJAX_URL' => [ 'ajax_url' => $data['ajax_url'], ], ]; return $js_data; } private function initJSData(&$output) { $js_data = $this->getJSData(); if (method_exists('Media', 'addJsDef')) { Media::addJsDef($js_data); $output .= NewsletterProTools::getJsDefScript(null, ' '.Tools::file_get_contents($this->dir_location.'views/js/ready.js').' '); } else { // for prestashop 1.5 $output .= NewsletterProTools::getJsDefScript($js_data, ' NewsletterPro.dataStorage.addObject(NewsletterPro_Data); '.Tools::file_get_contents($this->dir_location.'views/js/ready.js').' '); } } /** * Hook display header. * * @return string */ public function hookHeader() { $output = ''; $css_path = $this->getCssPath(); $this->context->controller->addCSS($css_path.'newsletterpro_front.css', 'all'); // $this->context->controller->addCSS($this->uri_location.'views/css/newsletterpro_cross.css', 'all'); $this->restore_jquery = false; if (version_compare(_PS_JQUERY_VERSION_, '1.7.2', '<')) { $this->restore_jquery = true; } $this->context->controller->addCSS($this->uri_location.'views/css/'.NewsletterProTools::getMin('app_front.css'), 'all'); $this->context->controller->addJS([ $this->uri_location.'views/js/'.NewsletterProTools::getMin('app_front.js'), ]); if ((int) pqnp_config('SUBSCRIPTION_ACTIVE')) { $this->initPopup(); } $this->context->controller->addCSS(NewsletterProTools::getCSS('display_customer_account_form.css'), 'all'); $this->initJSData($output); if (Tools::isSubmit('newsletterpro_source') && 'newsletter' == Tools::getValue('newsletterpro_source') && Tools::isSubmit('id_product')) { try { $id_product = (int) Tools::getValue('id_product'); $product_exists = 'SELECT COUNT(*) FROM `'._DB_PREFIX_.'product` WHERE `id_product` = '.(int) $id_product.''; if (Db::getInstance()->getValue($product_exists) > 0) { $cookie = new NewsletterProCookie('statistics_products', time() + 259200); if (!$cookie->get('products_id')) { $cookie->set('products_id', []); } $products_id = $cookie->get('products_id'); if (!in_array($id_product, $products_id)) { $cookie->append('products_id', $id_product); if (Tools::isSubmit('id_newsletter')) { $id_history = (int) Tools::getValue('id_newsletter'); $history_sql = 'SELECT `clicks` FROM `'._DB_PREFIX_.'newsletter_pro_tpl_history` WHERE `id_newsletter_pro_tpl_history` = '.(int) $id_history.''; $history = Db::getInstance()->getRow($history_sql); if ($history && isset($history['clicks'])) { $h_clicks = (int) $history['clicks']; ++$h_clicks; Db::getInstance()->update('newsletter_pro_tpl_history', [ 'clicks' => (int) $h_clicks, ], '`id_newsletter_pro_tpl_history`='.(int) $id_history); } } $need_update = 'SELECT `clicks` FROM `'._DB_PREFIX_.'newsletter_pro_statistics` WHERE `id_product` = '.(int) $id_product.''; $clicks = Db::getInstance()->getValue($need_update); if (false !== $clicks) { ++$clicks; Db::getInstance()->update('newsletter_pro_statistics', [ 'clicks' => (int) $clicks, ], '`id_product`='.(int) $id_product); } else { Db::getInstance()->insert('newsletter_pro_statistics', [ 'id_product' => (int) $id_product, 'clicks' => 1, ]); } } } } catch (Exception $e) { NewsletterProLog::writeStrip($e->getMessage(), NewsletterProLog::ERROR_FILE); } } if (Version::isLower('1.5.2.0') && isset($this->context->cookie->id_customer) && isset($this->context->cookie->id_lang)) { $id_lang = (int) $this->context->cookie->id_lang; $this->updateCustomerLanguage($id_lang); } if ((bool) pqnp_config('GOOGLE_ANALYTICS_ACTIVE')) { if ((bool) pqnp_config('GOOGLE_UNIVERSAL_ANALYTICS_ACTIVE')) { $google_analytics = pqnp_template_path($this->dir_location.'views/templates/admin/analyticstracking_new.tpl'); } else { $google_analytics = pqnp_template_path($this->dir_location.'views/templates/admin/analyticstracking_old.tpl'); } if (file_exists($google_analytics)) { $c_params = $this->getCampaignSubmition(); $this->context->smarty->assign($c_params); $this->context->smarty->assign([ 'CAMPAIGN_ACTIVE' => (bool) pqnp_config('CAMPAIGN_ACTIVE'), 'GOOGLE_ANALYTICS_ID' => pqnp_config('GOOGLE_ANALYTICS_ID'), 'HOST' => Tools::getHttpHost(false), ]); $output .= $this->context->smarty->fetch($google_analytics); } } elseif ((bool) pqnp_config('CAMPAIGN_ACTIVE')) { $this->context->smarty->assign(['NEWSLETTER_CAMPAIGN' => self::getCampaignScript()]); } // $this->restoreJqueryIfNeeded('displayHeader'); return $output; } public static function getNewsletterCampaign() { $output = ''; if (Module::isInstalled('newsletterpro')) { $module = NewsletterPro::getInstance(); if (!(bool) pqnp_config('GOOGLE_ANALYTICS_ACTIVE') && (bool) pqnp_config('CAMPAIGN_ACTIVE')) { $output = self::getCampaignScript(); } } return $output; } /** * Get google campaign script. * * @return string */ public static function getCampaignScript() { $module = NewsletterPro::getInstance(); $c_params = $module->getCampaignSubmition(); $script = ''; if ((bool) pqnp_config('GOOGLE_UNIVERSAL_ANALYTICS_ACTIVE')) { // The new version of the Google Analytics API if (isset($c_params['utm_source'])) { $script .= 'ga(\'set\', \'campaignSource\', \'('.$c_params['utm_source'].')\');'."\n"; } if (isset($c_params['utm_medium'])) { $script .= 'ga(\'set\', \'campaignMedium\', \'('.$c_params['utm_medium'].')\');'."\n"; } if (isset($c_params['utm_campaign'])) { $script .= 'ga(\'set\', \'campaignName\', \'('.$c_params['utm_campaign'].')\');'."\n"; } if (isset($c_params['utm_content'])) { $script .= 'ga(\'set\', \'campaignContent\', \'('.$c_params['utm_content'].')\');'."\n"; } } else { // The old version of the Google Analytics API $script .= '_gaq.push([\'_setCampaignTrack\', true]);'."\n"; if (isset($c_params['utm_source'])) { $script .= '_gaq.push([\'_setCampSourceKey\', \''.$c_params['utm_source'].'\']);'."\n"; } if (isset($c_params['utm_medium'])) { $script .= '_gaq.push([\'_setCampMediumKey\', \''.$c_params['utm_medium'].'\']);'."\n"; } if (isset($c_params['utm_campaign'])) { $script .= '_gaq.push([\'_setCampNameKey\', \''.$c_params['utm_campaign'].'\']);'."\n"; } if (isset($c_params['utm_content'])) { $script .= '_gaq.push([\'_setCampContentKey\', \''.$c_params['utm_content'].'\']);'."\n"; } } if ('testCampaign' == Tools::getValue('utm_source')) { http_response_code(205); } if (Tools::isSubmit('testCampaign')) { if ('script' == Tools::getValue('testCampaign')) { ddd($script); } } return $script; } /** * Get campaign post fields. * * @return array */ public function getCampaignSubmition() { $params = []; $params_values = array_keys($this->getCampaignParamsArray()); foreach ($params_values as $param) { if (Tools::isSubmit($param)) { // can replace addcslashes with Tools::safeOutput( from prestashop but first I need to check that $params[$param] = addcslashes(Tools::getValue($param), "'"); } } if ('testCampaign' == Tools::getValue('utm_source')) { http_response_code(205); } if (Tools::isSubmit('testCampaign')) { if ('params' == Tools::getValue('testCampaign')) { ddd($params); } } return $params; } /** * Add a restriction on id_shop for multishop lang table. * * @param string $alias * @param Context $context * * @return string */ public static function addSqlRestrictionOnLang($alias = null, $id_shop = null) { if (version_compare(_PS_VERSION_, '1.5.2.0', '>=')) { return Shop::addSqlRestrictionOnLang($alias, $id_shop); } if (is_null($id_shop)) { $id_shop = Context::getContext()->shop->id; } return ' AND '.(($alias) ? $alias.'.' : '').'id_shop = '.$id_shop.' '; } /** * This method allow to return children categories with the number of sub children selected for a product. * * @param int $id_parent * @param int $id_product * @param int $id_lang * * @return array */ public static function getChildrenWithNbSelectedSubCat($id_parent, $selected_cat, $id_lang, Shop $shop = null, $use_shop_context = true) { if (!$shop) { $shop = Context::getContext()->shop; } $id_shop = $shop->id ? $shop->id : Configuration::get('PS_SHOP_DEFAULT'); $selected_cat = explode(',', str_replace(' ', '', $selected_cat)); $sql = ' SELECT c.`id_category`, c.`level_depth`, cl.`name`, IF(( SELECT COUNT(*) FROM `'._DB_PREFIX_.'category` c2 WHERE c2.`id_parent` = c.`id_category` ) > 0, 1, 0) AS has_children, '.($selected_cat ? '( SELECT count(c3.`id_category`) FROM `'._DB_PREFIX_.'category` c3 WHERE c3.`nleft` > c.`nleft` AND c3.`nright` < c.`nright` AND c3.`id_category` IN ('.implode(',', array_map('intval', $selected_cat)).') )' : '0').' AS nbSelectedSubCat FROM `'._DB_PREFIX_.'category` c LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (c.`id_category` = cl.`id_category` '.NewsletterPro::addSqlRestrictionOnLang('cl', (int) $id_shop).') LEFT JOIN `'._DB_PREFIX_.'category_shop` cs ON (c.`id_category` = cs.`id_category` AND cs.`id_shop` = '.(int) $id_shop.') WHERE `id_lang` = '.(int) $id_lang.' AND c.`active` = 1 AND c.`id_parent` = '.(int) $id_parent; if (Shop::CONTEXT_SHOP == Shop::getContext() && $use_shop_context) { $sql .= ' AND cs.`id_shop` = '.(int) $shop->id; } if (!Shop::isFeatureActive() || Shop::CONTEXT_SHOP == Shop::getContext() && $use_shop_context) { $sql .= ' ORDER BY cs.`position` ASC'; } return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); } /** * Explode the campaign params into an array. * * @return array */ public function getCampaignParamsArray() { $params_str = Configuration::get('NEWSLETTER_PRO_CAMPAIGN'); $params_exp = explode("\n", $params_str); $params = []; foreach ($params_exp as $key => $param) { $param_exp = explode('=', $param); if (isset($param_exp[0], $param_exp[1])) { $params[trim($param_exp[0])] = trim($param_exp[1]); } } $utm = []; $utm_db = pqnp_config('CAMPAIGN'); foreach ($utm_db as $key => $value) { $utm[Tools::strtolower($key)] = $value; } $return = array_merge($params, $utm); return $return; } /** * Hook create account. * * @param array $params * * @return string */ public function hookCreateAccount($params) { if (isset($params['newCustomer']) && Validate::isLoadedObject($params['newCustomer'])) { /** @var Customer */ $customer = $params['newCustomer']; if (Tools::isSubmit('pqnp_newsletter')) { $customer->newsletter = true; $customer->update(); } } if ((bool) pqnp_config('SEND_NEWSLETTER_ON_SUBSCRIBE')) { if (isset($params['newCustomer']) && Validate::isLoadedObject($params['newCustomer'])) { $customer = $params['newCustomer']; try { $this->sendLastNewsletter((string) $customer->email); } catch (Exception $e) { NewsletterProLog::writeStrip($e->getMessage(), NewsletterProLog::ERROR_FILE); } } } if (Version::isLower('1.5.4.0')) { if (isset($this->context->cookie->id_customer) && isset($this->context->cookie->id_lang)) { $id_lang = (int) $this->context->cookie->id_lang; $this->updateCustomerLanguage($id_lang); } } // fix the bug for some shops if (!isset($this->context->cart)) { $this->context->cart = new Cart(); } } /** * Send the last newsletter to the new customer subscribed. * * @param string $email */ public function sendLastNewsletter($email) { $id_history = $this->getLastSendNewsletterIdHisotry(); if ($id_history > 0) { $template = NewsletterProTemplate::newHistory((int) $id_history, $email)->load(); $message = $template->message(); $send_manager = NewsletterProSendManager::getInstance(); $send_manager->setTemplateNameForAttachment($template->name); $send_manager->sendNewsletter($message['title'], $message['body'], $template->user->to(), [ 'user' => $template->user, ]); } } /** * Get the last newsletter id sent from the hisotry. * * @return int */ public function getLastSendNewsletterIdHisotry() { $send_count = 10; $sql = 'SELECT MAX(`id_newsletter_pro_tpl_history`) AS `id_newsletter_pro_tpl_history`, `date` FROM `'._DB_PREFIX_.'newsletter_pro_send` WHERE `emails_completed` >= '.(int) $send_count; $send = Db::getInstance()->getRow($sql); $send_date = $send['date']; $sql = 'SELECT MAX(`id_newsletter_pro_tpl_history`) AS `id_newsletter_pro_tpl_history`, `date_start` FROM `'._DB_PREFIX_.'newsletter_pro_task` WHERE `emails_completed` >= '.(int) $send_count; $task = Db::getInstance()->getRow($sql); $task_date = $task['date_start']; $id_newsletter_pro_tpl_history = 0; if (!isset($send_date) && isset($task_date)) { $id_newsletter_pro_tpl_history = (int) $task['id_newsletter_pro_tpl_history']; } elseif (isset($send_date) && !isset($task_date)) { $id_newsletter_pro_tpl_history = (int) $send['id_newsletter_pro_tpl_history']; } elseif (isset($send_date) && isset($task_date)) { if (strtotime($send_date) < strtotime($task_date)) { $id_newsletter_pro_tpl_history = (int) $task['id_newsletter_pro_tpl_history']; } elseif (strtotime($send_date) > strtotime($task_date)) { $id_newsletter_pro_tpl_history = (int) $send['id_newsletter_pro_tpl_history']; } elseif ((int) $send['id_newsletter_pro_tpl_history'] < (int) $task['id_newsletter_pro_tpl_history']) { $id_newsletter_pro_tpl_history = (int) $task['id_newsletter_pro_tpl_history']; } else { $id_newsletter_pro_tpl_history = (int) $send['id_newsletter_pro_tpl_history']; } } else { $id_newsletter_pro_tpl_history = 0; } return $id_newsletter_pro_tpl_history; } /** * Update customer language. * * @param int $id_lang */ public function updateCustomerLanguage($id_lang) { $sql = 'SELECT count(*) AS count FROM `'._DB_PREFIX_.'lang` where `id_lang` = '.(int) $id_lang.' AND `active` = 1'; $count = Db::getInstance()->executeS($sql); if (!empty($count) && isset($count[0]['count']) && $count[0]['count'] >= 1) { Db::getInstance()->execute(' UPDATE `'._DB_PREFIX_.'customer` SET `id_lang` = '.(int) $id_lang.' WHERE `id_customer` = '.(int) $this->context->cookie->id_customer.' LIMIT 1; '); } } /** * Install the database field id_lang for the oder versions of prestashop. * * @param string $column_name * * @return bool */ public function installLang($column_name = 'id_lang') { $sql = "SELECT COUNT(*) AS `count` FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '"._DB_NAME_."' AND TABLE_NAME='"._DB_PREFIX_."customer' AND COLUMN_NAME = '".pSQL($column_name)."';"; $count = Db::getInstance()->executeS($sql); if (!empty($count) && isset($count[0]['count']) && 0 == $count[0]['count']) { $sql = 'ALTER TABLE `'._DB_PREFIX_.'customer` ADD COLUMN `'.pSQL($column_name).'` INT(10) UNSIGNED NULL DEFAULT NULL;'; if (!Db::getInstance()->execute($sql)) { $this->_errors[] = $this->l('Cannot create the field "id_lang" into the table "customer".'); return false; } $id_default_lang = (int) Configuration::get('PS_LANG_DEFAULT'); $sql = 'UPDATE `'._DB_PREFIX_.'customer` SET `'.pSQL($column_name).'` = '.(int) $id_default_lang.';'; if (!Db::getInstance()->execute($sql)) { $this->_errors[] = $this->l('Cannot update the language for the existing customers into the table "customer".'); return false; } } if (!$this->registerHook('createAccount')) { $this->_errors[] = $this->l('The module cannot be registered to hook "createAccount".'); return false; } return true; } /** * Fix the prestashop problem shop name in single store. * * @param string $shop_name * * @return bool */ public function updateShopName($shop_name) { $sql = 'UPDATE `'._DB_PREFIX_.'shop` SET `name` = "'.pSQL($shop_name).'" WHERE `id_shop` = '.(int) $this->context->shop->id.' LIMIT 1;'; if (!Db::getInstance()->execute($sql)) { $this->_errors[] = $this->l('Cannot update the shop name.'); } return true; } /** * Is prestashop 1.6 version. * * @return bool */ public function isPS16() { return Version::isHigher('1.5.9.9'); } /** * Install the module configuration. * * @return bool */ public function installConfiguration() { if (!Configuration::updateValue('NEWSLETTER_PRO_CAMPAIGN', '', false, 0, 0)) { $this->_errors[] = sprintf($this->l('The configuration "%s" cannot be installed into "%s" table.'), 'NEWSLETTER_PRO_CAMPAIGN', _DB_PREFIX_.'configuration'); return false; } if (!Config::install()) { $this->_errors[] = sprintf($this->l('The configuration "%s" cannot be installed into "%s" table.'), Config::NAME, _DB_PREFIX_.'configuration'); return false; } if (!NewsletterProConfigurationShop::install()) { $this->_errors[] = array_merge($this->_errors, NewsletterProConfigurationShop::getErrors()); return false; } return true; } /** * Uninstall the module configuraion. * * @return bool */ public function uninstallConfiguration() { return Configuration::deleteByName(Config::NAME) && Configuration::deleteByName('NEWSLETTER_PRO_CAMPAIGN') && NewsletterProConfigurationShop::uninstall(); } /** * Initialize configuration. */ public function initConfiguration() { Config::init(); NewsletterProConfigurationShop::init(); } /** * Redirect to the module dashboard if the employee will click on the module config anchor. */ public function getContent() { Tools::redirectAdmin($this->link); } /** * Install module database tables, fields and data. * * @return bool */ public function installDb() { /** @var NewsletterProInstall */ $install = null; require_once _NEWSLETTER_PRO_DIR_.'/sql/install.php'; if (!$install->execute()) { $this->mergeErrors($install->getErrors()); return false; } // add records into the database require_once _NEWSLETTER_PRO_DIR_.'/install/Install-3.1.1.php'; // install the "newsletter_pro_config" table if (!NewsletterProConfig::install()) { $this->mergeErrors(NewsletterProConfig::getErrors()); return false; } return $this->success(); } /** * Add an error to the module. */ public function addError($error) { if (is_array($error)) { foreach ($error as $err) { $this->_errors[] = $err; } } else { $this->_errors[] = $error; } } /** * Check if the module has errors. * * @return bool */ public function success() { return empty($this->_errors); } /** * Add errors as array. * * @param array $errors */ public function mergeErrors($errors) { $this->_errors = array_merge($this->_errors, $errors); } /** * Install the module to the customers menu. * * @param string $tab_class * @param string $tab_name * @param string $tab_parent_name * * @return bool */ public function installModuleTab($tab_class, $tab_name, $tab_parent_name = 'AdminCustomers') { if (NewsletterProTools::is17()) { $tab_parent_name = 'AdminParentCustomer'; } $logo_file = _NEWSLETTER_PRO_DIR_.'/logo.png'; $logo_destination = _PS_IMG_DIR_.'t/'.$tab_class.'.png'; copy($logo_file, $logo_destination); $id = Tab::getIdFromClassName($tab_class); $tab = new Tab((int) $id); foreach (Language::getLanguages(false) as $lang) { $tab->name[$lang['id_lang']] = $tab_name; } $tab->class_name = $tab_class; $tab->module = $this->name; $tab->id_parent = (int) Tab::getIdFromClassName($tab_parent_name); $tab->active = 1; if (version_compare(_PS_VERSION_, '1.5.1.0', '<=')) { if (!$tab->save()) { return (bool) $tab->id; } return true; } else { if (!$tab->save()) { return false; } return true; } } /** * Uninstall the module from the menu. * * @param string $tab_class * * @return bool */ public function uninstallModuleTab($tab_class) { $id_tab = Tab::getIdFromClassName($tab_class); if (0 != $id_tab) { $tab = new Tab($id_tab); $tab->delete(); return true; } return false; } /** * Copy data from the $_POST variable. * * @param object $object * @param string $table */ protected function copyFromPost(&$object, $table) { $post = &$_POST; foreach ($post as $key => $value) { if (array_key_exists($key, $object) && $key != 'id_'.$table) { if ('passwd' == $key && Tools::getValue('id_'.$table) && empty($value)) { continue; } if ('passwd' == $key && !empty($value)) { $value = Tools::encrypt($value); } $object->{$key} = $value; } } $rules = call_user_func([get_class($object), 'getValidationRules'], get_class($object)); if (count($rules['validateLang'])) { $languages = Language::getLanguages(false); foreach ($languages as $language) { foreach (array_keys($rules['validateLang']) as $field) { if (isset($post[$field.'_'.(int) $language['id_lang']])) { $object->{$field}[(int) $language['id_lang']] = $post[$field.'_'.(int) $language['id_lang']]; } } } } } /** * Update asso shop. * * @param int $id_object * @param string $table * * @return int/bool */ public function updateAssoShop($id_object, $table) { if (!Shop::isFeatureActive()) { return; } if (!NewsletterPro::isTableAssociated($table)) { return; } $assos_data = $this->getSelectedAssoShop($table, $id_object); $exclude_ids = $assos_data; foreach (Db::getInstance()->executeS('SELECT id_shop FROM '._DB_PREFIX_.'shop') as $row) { if (!$this->context->employee->hasAuthOnShop($row['id_shop'])) { $exclude_ids[] = $row['id_shop']; } } Db::getInstance()->delete($table.'_shop', '`'.$id_object.'` = '.(int) $id_object.($exclude_ids ? ' AND id_shop NOT IN ('.implode(', ', $exclude_ids).')' : '')); $insert = []; foreach ($assos_data as $id_shop) { $insert[] = [ $id_object => $id_object, 'id_shop' => (int) $id_shop, ]; } return Db::getInstance()->insert($table.'_shop', $insert, false, true, Db::INSERT_IGNORE); } /** * Get asso shop. * * @param string $table * * @return array */ public function getSelectedAssoShop($table) { if (!Shop::isFeatureActive() || !NewsletterPro::isTableAssociated($table)) { return []; } $shops = Shop::getShops(true, null, true); if (1 == count($shops) && isset($shops[0])) { return [$shops[0], 'shop']; } $assos = []; if (Tools::isSubmit('checkBoxShopAsso_'.$table)) { $check = Tools::getValue('checkBoxShopAsso_'.$table); foreach (array_keys($check) as $id_shop) { $assos[] = (int) $id_shop; } } elseif (1 == Shop::getTotalShops(false)) { $assos[] = (int) NewsletterPro::getContextShopID(); } return $assos; } /** * Uninstall the module from the menu. * * @return bool */ public function uninstallFromMenu() { $id_tab = Tab::getIdFromClassName($this->class_name); $tab = new Tab($id_tab); return $tab->delete(); } /** * Uninstall the database. * * @return bool */ private function uninstallDb() { // this option will always be uninstalled $full_uninstall = [ 'newsletter_pro_send', 'newsletter_pro_send_step', 'newsletter_pro_smtp', 'newsletter_pro_task', 'newsletter_pro_task_step', // 3.2.8 'newsletter_pro_email_exclusion', // in 4.0.0 'newsletter_pro_filters_selection', 'newsletter_pro_send_connection', // in 4.0.1 'newsletter_pro_attachment', 'newsletter_pro_subscribers_custom_field', 'newsletter_pro_subscribers_custom_field_lang', 'newsletter_pro_mailchimp_token', ]; // this tables will uninstall only if the option uninstall_all_tables is true $protected_uninstall = [ 'newsletter_pro_email', 'newsletter_pro_tpl_history', 'newsletter_pro_tpl_history_lang', 'newsletter_pro_customer_category', 'newsletter_pro_customer_list_of_interests', 'newsletter_pro_statistics', 'newsletter_pro_unsibscribed', 'newsletter_pro_fwd_unsibscribed', 'newsletter_pro_forward', // 3.1.1 'newsletter_pro_list_of_interest', 'newsletter_pro_list_of_interest_lang', 'newsletter_pro_list_of_interest_shop', 'newsletter_pro_subscribers', 'newsletter_pro_subscribers_temp', 'newsletter_pro_subscription_tpl', 'newsletter_pro_subscription_tpl_lang', 'newsletter_pro_subscription_tpl_shop', // 4.5.5 'newsletter_pro_subscription_consent', ]; foreach ($full_uninstall as $table_name) { if (!Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.$table_name.'`;')) { return false; } } if ($this->uninstall_all_tables) { foreach ($protected_uninstall as $table_name) { if (!Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.$table_name.'`;')) { return false; } } if (!NewsletterProConfig::uninstall()) { return false; } } return true; } private function uninstallAttachments() { $files = NewsletterProTools::getDirectoryIterator($this->tpl_location.'attachments/', '/.*/'); foreach ($files as $file) { if ($file->isFile() && !in_array($file->getFileName(), ['.htaccess', 'index.php'])) { @unlink($file->getPathName()); } } return true; } /** * Get the context shop id. * * @param bool * * @return bool */ public static function getContextShopID($null_value_without_multishop = false) { if (method_exists('Shop', 'getContextShopID')) { return Shop::getContextShopID($null_value_without_multishop); } return Shop::getContextShopIDNewsletterPro($null_value_without_multishop); } /** * Get the context shop group id. * * @param bool $null_value_without_multishop * * @return bool */ public static function getContextShopGroupID($null_value_without_multishop = false) { if (method_exists('Shop', 'getContextShopGroupID')) { return Shop::getContextShopGroupID($null_value_without_multishop); } return Shop::getContextShopGroupIDNewsletterPro($null_value_without_multishop); } /** * Check if the database table is associated. * * @param string $table * * @return bool */ public static function isTableAssociated($table) { if (method_exists('Shop', 'isTableAssociated')) { return Shop::isTableAssociated($table); } return Shop::isTableAssociatedNewsletterPro($table); } /** * Get shops groups. * * @param bool $active * * @return array */ public static function getShopGroups($active = true) { if (class_exists('ShopGroup')) { return ShopGroup::getShopGroups($active); } return GroupShop::getGroupShops($active); } /** * Init content. */ private function initContext() { $this->context = Context::getContext(); // Set Front Office Link $protocol_link = (Configuration::get('PS_SSL_ENABLED') || Tools::usingSecureMode()) ? 'https://' : 'http://'; $use_ssl = ((isset($this->ssl) && $this->ssl && Configuration::get('PS_SSL_ENABLED')) || Tools::usingSecureMode()) ? true : false; $protocol_content = ($use_ssl) ? 'https://' : 'http://'; $link = new Link($protocol_link, $protocol_content); $link->protocol_link = $this->relplaceAdminLink($link->protocol_link); $link->protocol_content = $this->relplaceAdminLink($link->protocol_content); $this->context->link = &$link; if (!isset($this->context->shop->id_shop_group)) { $this->context->shop->id_shop_group = &$this->context->shop->id_group_shop; } if (!Configuration::get('PS_MULTISHOP_FEATURE_ACTIVE')) { $ps_shop_name = Configuration::get('PS_SHOP_NAME'); $ps_shop_default = (int) Configuration::get('PS_SHOP_DEFAULT'); if ($ps_shop_name && $ps_shop_default && ($this->context->shop->name != $ps_shop_name)) { Db::getInstance()->update('shop', [ 'name' => pSQL($ps_shop_name), ], '`id_shop` = '.(int) $ps_shop_default, 1); } } } /** * Save products number per row. * * @param int $number * * @return json */ public function saveProductNumberPerRow($number) { $errors = []; $response = ['status' => false, 'errors' => &$errors]; $template = pqnp_config('PRODUCT_TEMPLATE'); $path = $this->tpl_location.'product/'.$template; if ('default.html' == $template) { $errors[] = $this->l('Save a copy of the default template to change the number of products on row.'); } else { if (file_exists($path)) { $content = Tools::file_get_contents($path); $full_content = preg_replace('/\{columns=\d+\}(\n)?/', '{columns='.$number.'}', $content); if ($handle = fopen($path, 'w')) { fwrite($handle, $full_content); fclose($handle); } else { $errors[] = $this->l('Template cannot be written'); } } else { $errors[] = $this->l('Missing template file'); } } if (empty($errors)) { $response['status'] = true; } return Tools::jsonEncode($response); } /** * Save product template. * * @param string $content * @param int $product_nr * * @return json */ public function saveProductTemplate($content, $product_nr) { $data = []; $template = pqnp_config('PRODUCT_TEMPLATE'); $path = $this->tpl_location.'product/'.$template; if ('default.html' == $template) { $data['message'] = $this->l('You cannot override the default templates. Please save a copy.'); $data['type'] = false; return Tools::jsonEncode($data); } if (file_exists($path)) { if (isset($content) && false != $content) { if (preg_match('//', $content, $match)) { $content = str_replace($match[1], '', $content); } $header = ''; // $header = '\n"; // $header = '\n"; $full_content = $header.$content; if (preg_match('/<(?=\/?img(?=>|\s.*>))\/?.*?>/', $full_content, $img_match)) { $img_match = (string) $img_match[0]; $img_re_match = preg_replace('/\ssrc\="[^"]*"/', ' src="{image_path}"', $img_match); $img_re_match = preg_replace('/\swidth\="[^"]*"/', ' width="{image_width}"', $img_re_match); $img_re_match = preg_replace('/\sheight\="[^"]*"/', ' height="{image_height}"', $img_re_match); $full_content = str_replace($img_match, $img_re_match, $full_content); } if ($handle = fopen($path, 'w')) { fwrite($handle, $full_content); fclose($handle); $data['message'] = $this->l('Update successfully'); $data['type'] = true; $data['content'] = $full_content; } else { $data['message'] = $this->l('Template cannot be written'); $data['type'] = false; } } else { $data['message'] = $this->l('Template not saved'); $data['type'] = false; } } else { $data['message'] = $this->l('Missing template file'); $data['type'] = false; } return Tools::jsonEncode($data); } /** * Save as the product template. * * @param string $name * @param string $content * @param int $product_nr * * @return json */ public function saveAsProductTemplate($name, $content, $product_nr) { $name = preg_replace('/\s+/i', '_', $name); $validate_name = $this->verifyName($name); if (true !== $validate_name) { return '{"status":"'.false.'", "msg":"'.$validate_name.'"}'; } $name = $name.'.html'; $path = $this->tpl_location.'product/'.$name; if (!file_exists($path)) { if (isset($content) && false != $content) { if (preg_match('//', $content, $match)) { $content = str_replace($match[1], '', $content); } $header = ''; // $header = '\n"; $full_content = $header.$content; $header_content = ''; if (preg_match('/\s*?\s*?/', $content, $match)) { $header_content = trim($match['header']); } if (!preg_match('/content\s+=\s+template/', $header_content) && preg_match('/<(?=\/?img(?=>|\s.*>))\/?.*?>/', $full_content, $img_match)) { $img_match = (string) $img_match[0]; $img_re_match = preg_replace('/\ssrc\="[^"]*"/', ' src="{image_path}"', $img_match); $img_re_match = preg_replace('/\swidth\="[^"]*"/', ' width="{image_width}"', $img_re_match); $img_re_match = preg_replace('/\sheight\="[^"]*"/', ' height="{image_height}"', $img_re_match); $full_content = str_replace($img_match, $img_re_match, $full_content); } if ($handle = fopen($path, 'w')) { fwrite($handle, $full_content); fclose($handle); pqnp_config('PRODUCT_TEMPLATE', $name); return Tools::jsonEncode([ 'status' => true, 'msg' => '', 'full_content' => $full_content, ]); } else { return '{"status":"'.false.'", "msg":"'.$this->l('Cannot write the template').'"}'; } } else { return '{"status":"'.false.'", "msg":"'.$this->l('Template was not saved').'"}'; } } else { return '{"status":"'.false.'", "msg":"'.$this->l('This file name already exists').'"}'; } return '{"status":"'.false.'", "msg":"'.$this->l('Saved unsuccessfully').'"}'; } /** * Get all products from category by id category. * * @param int $id_category * * @return json */ public function getProducts($id_category) { $data = []; $id_lang = (int) pqnp_config('LANG'); $order_by_prefix = null; $front = false; $order_by = 'name'; $order_way = 'ASC'; $limit = 1000; $id_supplier = false; $start = 0; $only_active = pqnp_config('ONLY_ACTIVE_PRODUCTS'); if (Version::isBetween('1.5.0.0', '1.5.0.6')) { $sql = 'SELECT p.*, pl.* , t.`rate` AS tax_rate, m.`name` AS manufacturer_name, s.`name` AS supplier_name, i.`id_image`, il.`legend` FROM `'._DB_PREFIX_.'product` p '.$this->context->shop->addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` '.$this->context->shop->addSqlRestrictionOnLang('pl').') LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (p.`id_tax_rules_group` = tr.`id_tax_rules_group` AND tr.`id_country` = '.(int) $this->context->country->id.' AND tr.`id_state` = 0) LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = tr.`id_tax`) LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`) AND i.cover = 1 LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON ( i.`id_image` = il.`id_image`) AND il.`id_lang` = '.(int) $id_lang.' LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON (m.`id_manufacturer` = p.`id_manufacturer`) LEFT JOIN `'._DB_PREFIX_.'supplier` s ON (s.`id_supplier` = p.`id_supplier`)'. ($id_category ? 'LEFT JOIN `'._DB_PREFIX_.'category_product` c ON (c.`id_product` = p.`id_product`)' : '').' WHERE pl.`id_lang` = '.(int) $id_lang. ($id_category ? ' AND c.`id_category` = '.(int) $id_category : ''). ($only_active ? ' AND p.`active` = 1' : '').' GROUP BY p.`id_product` ORDER BY '.(isset($order_by_prefix) ? pSQL($order_by_prefix).'.' : '').'`'.pSQL($order_by).'` '.pSQL($order_way). ($limit > 0 ? ' LIMIT '.(int) $start.','.(int) $limit : ''); } elseif (Version::isBetween('1.5.0.4', '1.5.0.18')) { $sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, product_attribute_shop.`id_product_attribute`, pl.`description`, pl.`description_short`, pl.`available_now`, pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image`, il.`legend`, m.`name` AS manufacturer_name, tl.`name` AS tax_name, t.`rate`, cl.`name` AS category_default, DATEDIFF(product_shop.`date_add`, DATE_SUB(NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY)) > 0 AS new, (product_shop.`price` * IF(t.`rate`,((100 + (t.`rate`))/100),1)) AS orderprice FROM `'._DB_PREFIX_.'category_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = cp.`id_product` '.Shop::addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (p.`id_product` = pa.`id_product`) '.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.`default_on` = 1').' '.Product::sqlStock('p', 'product_attribute_shop', false, $this->context->shop).' LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (product_shop.`id_category_default` = cl.`id_category` AND cl.`id_lang` = '.(int) $id_lang.Shop::addSqlRestrictionOnLang('cl').') LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int) $id_lang.Shop::addSqlRestrictionOnLang('pl').') LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`)'. Shop::addSqlAssociation('image', 'i', false, 'i.cover=1').' LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (image_shop.`id_image` = il.`id_image` AND il.`id_lang` = '.(int) $id_lang.') LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (product_shop.`id_tax_rules_group` = tr.`id_tax_rules_group` AND tr.`id_country` = '.(int) $this->context->country->id.' AND tr.`id_state` = 0 AND tr.`zipcode_from` = 0) LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = tr.`id_tax`) LEFT JOIN `'._DB_PREFIX_.'tax_lang` tl ON (t.`id_tax` = tl.`id_tax` AND tl.`id_lang` = '.(int) $id_lang.') LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON m.`id_manufacturer` = p.`id_manufacturer` WHERE product_shop.`id_shop` = '.(int) $this->context->shop->id.' AND (pa.id_product_attribute IS NULL OR product_attribute_shop.id_shop='.(int) $this->context->shop->id.') AND (i.id_image IS NULL OR image_shop.id_shop='.(int) $this->context->shop->id.') AND cp.`id_category` = '.(int) $id_category .($only_active ? ' AND product_shop.`active` = 1' : '') .($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '') .($id_supplier ? ' AND p.id_supplier = '.(int) $id_supplier : '') .' GROUP BY p.`id_product` ORDER BY `'.pSQL($order_by).'` '.pSQL($order_way).' LIMIT 0,'.(int) $limit.';'; } else { $sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, product_attribute_shop.`id_product_attribute`, pl.`description`, pl.`description_short`, pl.`available_now`, pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image`, il.`legend`, m.`name` AS manufacturer_name, tl.`name` AS tax_name, t.`rate`, cl.`name` AS category_default, DATEDIFF(product_shop.`date_add`, DATE_SUB(NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY)) > 0 AS new, (product_shop.`price` * IF(t.`rate`,((100 + (t.`rate`))/100),1)) AS orderprice FROM `'._DB_PREFIX_.'category_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = cp.`id_product` '.Shop::addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (p.`id_product` = pa.`id_product` ) '.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.`default_on` = 1').' '.Product::sqlStock('p', 'product_attribute_shop', false, $this->context->shop).' LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (product_shop.`id_category_default` = cl.`id_category` AND cl.`id_lang` = '.(int) $id_lang.Shop::addSqlRestrictionOnLang('cl').') LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int) $id_lang.Shop::addSqlRestrictionOnLang('pl').') LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`)'. Shop::addSqlAssociation('image', 'i', false, 'image_shop.cover=1').' LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (image_shop.`id_image` = il.`id_image` AND il.`id_lang` = '.(int) $id_lang.') LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (product_shop.`id_tax_rules_group` = tr.`id_tax_rules_group` AND tr.`id_country` = '.(int) $this->context->country->id.' AND tr.`id_state` = 0 AND tr.`zipcode_from` = 0) LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = tr.`id_tax`) LEFT JOIN `'._DB_PREFIX_.'tax_lang` tl ON (t.`id_tax` = tl.`id_tax` AND tl.`id_lang` = '.(int) $id_lang.') LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON m.`id_manufacturer` = p.`id_manufacturer` WHERE product_shop.`id_shop` = '.(int) $this->context->shop->id.' AND (pa.id_product_attribute IS NULL OR product_attribute_shop.id_shop='.(int) $this->context->shop->id.') AND (i.id_image IS NULL OR image_shop.id_shop='.(int) $this->context->shop->id.') AND cp.`id_category` = '.(int) $id_category .($only_active ? ' AND product_shop.`active` = 1' : '') .($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '') .($id_supplier ? ' AND p.id_supplier = '.(int) $id_supplier : '') .' GROUP BY p.`id_product` ORDER BY `'.pSQL($order_by).'` '.pSQL($order_way).' LIMIT 0,'.(int) $limit.';'; } if ((int) pqnp_ini_config('get_category_products_prestashop')) { $category = new Category($id_category); $products = $category->getProducts($id_lang, 1, 999999, $order_by, $order_way, false, false); } else { $products = Db::getInstance()->executeS($sql); } if (empty($products)) { $data['products'] = $products; return Tools::jsonEncode($data); } $data['products'] = $this->getProductsAttributes($id_lang, $products); return Tools::jsonEncode($data); } /** * Setup a new context. */ public function setRelatedContext() { $this->context->currency = new Currency((int) pqnp_config('CURRENCY')); $this->context->language = new Language((int) pqnp_config('LANG')); } /** * Get products attributes. * * @param int $id_lang * @param array $pr * @param int $id_currency * * @return array */ public function getProductsAttributes($id_lang, $pr, $id_currency = null, $productProperties = false) { $this->setRelatedContext(); $prop = $this->getNewProperties(null, $id_currency); if ($productProperties) { // this instance will create the prestashop cache $products = NewsletterProProductProperties::getProductsProperties($id_lang, $pr); } else { $products = Product::getProductsProperties($id_lang, $pr); } foreach ($products as &$product) { $this->createProductTemplateVars($id_lang, $product, $prop); } return $products; } /** * Get product attributes. * * @param int $id_lang * @param array $pr * * @return array */ public function getProductAttributes($id_lang, $pr) { $this->setRelatedContext(); $prop = $this->getNewProperties(); $product = Product::getProductProperties($id_lang, $pr); $this->createProductTemplateVars($id_lang, $product, $prop); return $product; } /** * The the products new properties. * * @param string $image_type * @param int $id_currency * * @return array */ public function getNewProperties($image_type = null, $id_currency = null) { $prop = []; if (!isset($image_type)) { $image_type = (string) pqnp_config('IMAGE_TYPE'); } $image = Image::getSize($image_type); if (false == $image) { $sql = 'SELECT `id_image_type` as `id`, `name`, `width`, `height` FROM `'._DB_PREFIX_.'image_type` WHERE `products` = 1 AND width > 150 ORDER BY `width` ASC LIMIT 1;'; $image = Db::getInstance()->executeS($sql); $image = isset($image[0]) ? $image[0] : null; } $image_thumb_type = ''; $type_cart = 'cart'; $type_small = 'small'; if ($this->isPS16()) { $image_thumb_type = $type_cart.'_default'; } else { $image_thumb_type = (Version::isLower('1.5.1.0') ? 'small' : $type_small.'_default'); } if ($images_types = ImageType::getImagesTypes('products')) { $smallest = []; foreach ($images_types as $img) { if (empty($smallest)) { $smallest = $img; } elseif ($img['width'] < $smallest['width']) { $smallest = $img; } } if (isset($smallest['name'])) { $image_thumb_type = $smallest['name']; } } $image_thumb = Image::getSize($image_thumb_type); if (false == $image_thumb) { $sql = 'SELECT `id_image_type` as `id`, `name`, `width`, `height` FROM `'._DB_PREFIX_.'image_type` WHERE `products` = 1 AND width > 1 ORDER BY `width` ASC LIMIT 1;'; $image_thumb = Db::getInstance()->executeS($sql); $image_thumb = isset($image_thumb[0]) ? $image_thumb[0] : null; } if (null == $image || null == $image_thumb) { return false; } $prop['image_type'] = $image_type; $prop['image_thumb_type'] = $image_thumb_type; $prop['width'] = $image['width']; $prop['height'] = $image['height']; $prop['thumb_width'] = $image_thumb['width']; $prop['thumb_height'] = $image_thumb['height']; $prop['current_currency'] = isset($id_currency) ? Currency::getCurrency((int) $id_currency) : Currency::getCurrency(pqnp_config('CURRENCY')); $prop['mod_rewrite'] = pqnp_config('PS_REWRITING_SETTINGS'); return $prop; } /** * Convert the url's to SSL protocol. * * @param string $url * * @return string */ public function convertToSSL($url) { return $url; } /** * Returns a link to a product image for display * Note: the new image filesystem stores product images in subdirectories of img/p/. * * @param string $name rewrite link of the image * @param string $ids id part of the image filename - can be "id_product-id_image" (legacy support, recommended) or "id_image" (new) * @param string $type */ public function getImageLink($name, $ids, $type = null) { $link = $this->context->link->getImageLink($name, $ids, $type); $link = $this->relplaceAdminLink($link); $link = $this->convertToSSL($link); return $link; } /** * Create a link to a product. * * @param mixed $product Product object (can be an ID product, but deprecated) * @param string $alias * @param string $category * @param string $ean13 * @param int $id_lang * @param int $id_shop (since 1.5.0) ID shop need to be used when we generate a product link for a product in a cart * @param int $ipa ID product attribute * * @return string */ public function getProductLink($product, $alias = null, $category = null, $ean13 = null, $id_lang = null, $id_shop = null, $ipa = 0, $force_routes = false) { $link = $this->context->link->getProductLink($product, $alias, $category, $ean13, $id_lang, $id_shop, $ipa, $force_routes); $link = $this->relplaceAdminLink($link); return $link; } /** * Generate a product link. * * @param int $id_product * @param int $id_lang * * @return string */ public function makeProductLink($id_product, $id_lang) { $link = $this->getShopUrl().'index.php?id_product='.$id_product.'&controller=product&id_lang='.$id_lang; $link = $this->relplaceAdminLink($link); return $link; } /** * Create and sanitize products template variables. * * @param int $id_lang * @param array $product * @param array $prop */ public function createProductTemplateVars($id_lang, &$product, $prop) { $rewrite = []; foreach (Product::getUrlRewriteInformations($product['id_product']) as $item) { $rewrite[$item['id_lang']] = $item['link_rewrite']; } $link_rewrite = $rewrite[$id_lang]; $image_id = array_key_exists('cover_image_id', $product) ? $product['cover_image_id'] : $product['id_image']; $product['image_path'] = $this->getImageLink($link_rewrite, $image_id, $prop['image_type']); $product['image_width'] = $prop['width']; $product['image_height'] = $prop['height']; if ($prop['mod_rewrite'] && (bool) pqnp_config('PRODUCT_LINK_REWRITE')) { $product['link'] = $this->getProductLink((int) $product['id_product']); } else { $product['link'] = $this->makeProductLink((int) $product['id_product'], (int) $id_lang); } if (pqnp_config('CAMPAIGN_ACTIVE')) { $product['link'] = $this->setCampaignVariables($product['link'], ['product_name' => $product['name']]); } $product['link'] = $this->setStatisticsVariables($product['link']); $decimals = 2; $product['thumb_path'] = $this->getImageLink($link_rewrite, $image_id, $prop['image_thumb_type']); $product['thumb_width'] = $prop['thumb_width']; $product['thumb_height'] = $prop['thumb_height']; if (array_key_exists('sign', $prop['current_currency'])) { $product['currency'] = $prop['current_currency']['sign']; } else { $product['currency'] = $prop['current_currency']['iso_code']; } if (isset($product['specific_prices']['reduction_type']) && 'amount' === $product['specific_prices']['reduction_type']) { $product['discount'] = number_format(abs((((float) $product['specific_prices']['reduction'] / (float) $product['price_without_reduction']) * 100)), $decimals).'%'; } elseif (isset($product['specific_prices']['reduction_type'])) { $product['discount'] = number_format(abs($product['specific_prices']['reduction'] * 100), $decimals).'%'; } $product['price_convert'] = ( pqnp_ini_config('price_convert') ? Tools::convertPrice((float) $product['price'], (int) $prop['current_currency']['id_currency']) : (float) $product['price'] ); $product['price_display'] = Tools::displayPrice((float) $product['price_convert'], (int) $prop['current_currency']['id_currency']); $product['price_without_reduction'] = $product['price_without_reduction']; $product['price_without_reduction_convert'] = ( pqnp_ini_config('price_convert') ? Tools::convertPrice((float) $product['price_without_reduction'], (int) $prop['current_currency']['id_currency']) : (float) $product['price_without_reduction'] ); $product['price_without_reduction_display'] = Tools::displayPrice((float) $product['price_without_reduction_convert'], (int) $prop['current_currency']['id_currency']); $product['price_tax_exc'] = $product['price_tax_exc']; $product['price_tax_exc_convert'] = ( pqnp_ini_config('price_convert') ? Tools::convertPrice((float) $product['price_tax_exc'], (int) $prop['current_currency']['id_currency']) : (float) $product['price_tax_exc'] ); $product['price_tax_exc_display'] = Tools::displayPrice((float) $product['price_tax_exc_convert'], (int) $prop['current_currency']['id_currency']); $product['wholesale_price'] = $product['wholesale_price']; $product['wholesale_price_convert'] = ( pqnp_ini_config('price_convert') ? Tools::convertPrice((float) $product['wholesale_price'], (int) $prop['current_currency']['id_currency']) : (float) $product['wholesale_price'] ); $product['wholesale_price_display'] = Tools::displayPrice((float) $product['wholesale_price_convert'], (int) $prop['current_currency']['id_currency']); $unit_price = (float) $product['price']; $unit_price_tax_exc = (float) $product['price_tax_exc']; if ((float) $product['unit_price_ratio'] > 0) { $unit_price = (float) $product['price'] / (float) $product['unit_price_ratio']; $unit_price_tax_exc = (float) $product['price_tax_exc'] / (float) $product['unit_price_ratio']; } $product['unit_price'] = number_format($unit_price, $decimals); $product['unit_price_convert'] = number_format( pqnp_ini_config('price_convert') ? Tools::convertPrice($unit_price, (int) $prop['current_currency']['id_currency']) : $unit_price, $decimals ); $product['unit_price_display'] = Tools::displayPrice($unit_price, (int) $prop['current_currency']['id_currency']); $product['unit_price_tax_exc'] = number_format($unit_price_tax_exc, $decimals); $product['unit_price_tax_exc_convert'] = number_format( pqnp_ini_config('price_convert') ? Tools::convertPrice($unit_price_tax_exc, (int) $prop['current_currency']['id_currency']) : $unit_price_tax_exc, $decimals ); $product['unit_price_tax_exc_display'] = Tools::displayPrice($unit_price_tax_exc, (int) $prop['current_currency']['id_currency']); $product['pre_tax_retail_price'] = (float) $product['price_tax_exc'] + (float) $product['reduction']; $unity = (int) $product['unity'] <= 0 ? 1 : (int) $product['unity']; $unit_price_bo = (float) $product['pre_tax_retail_price'] / $unity; $product['unit_price_bo'] = number_format($unit_price_bo, $decimals); $product['unit_price_bo_convert'] = number_format( pqnp_ini_config('price_convert') ? Tools::convertPrice($unit_price_bo, (int) $prop['current_currency']['id_currency']) : $unit_price_bo, $decimals ); $product['unit_price_bo_display'] = Tools::displayPrice($unit_price_bo, (int) $prop['current_currency']['id_currency']); // {$price_display|EUR} // {$name|12|...|en} // force langauge to english // the array will fill later in NewsletterProTemplate.php $product['dynamic_vars'] = []; } /** * Get the campaign statistics params as string. * * @return string */ public function getCampaignParams() { $params = $this->getCampaignParamsArray(); $string = ''; foreach ($params as $key => $line) { $string .= '&'.$key.'='.$line; } $string = str_replace("\n", '', $string); $string = preg_replace('/(?<=\w)\s(?=\w)/', '+', $string); $string = str_replace(' ', '', $string); return $string; } /** * Append google campaign variables to the link. * * @param string $link * @param array $campaign_vars * * @return string */ public function setCampaignVariables($link, $campaign_vars) { $params = $this->getCampaignParams(); foreach ($campaign_vars as &$var) { $var = urlencode($var); } $link = trim($link); $linkParts = explode('#', $link); $link = array_shift($linkParts); $last_letter = Tools::substr($link, Tools::strlen($link) - 1, Tools::strlen($link)); if (preg_match('/\?/', $link)) { if ('?' === $last_letter) { $link = $link.Tools::substr($params, 1); } else { $link = $link.$params; } } else { $link = $link.'?'.Tools::substr($params, 1); } $link = $this->replaceVars($link, $campaign_vars); $link = preg_replace('/\?\&/', '?', $link); if (count($linkParts) > 0) { return $link.'#'.join('#', $linkParts); } return $link; } /** * Set campagin statistics variables. * * @param string $link * @param array $tpl_vars */ public function setStatisticsVariables($link, $tpl_vars = []) { $params = $this->getStatisticsParams(); $link = trim($link); $exp = explode('#', $link); $tail = ''; if (count($exp) > 1) { $link = $exp[0]; $tail = '#'.$exp[1]; } $last_letter = Tools::substr($link, Tools::strlen($link) - 1, Tools::strlen($link)); if (preg_match('/\?/', $link)) { if ('?' === $last_letter) { $link = $link.Tools::substr($params, 1); } else { $link = $link.$params; } } else { if ('?' === $last_letter) { $link = $link.'?'.Tools::substr($params, 1); } else { $link = $link.'?'.$params; } } $link = $this->replaceVars($link, $tpl_vars); $link = preg_replace('/\?\&/', '?', $link); return $link.$tail; } /** * Get the campaign statistics variables as string. * * @return string */ public function getStatisticsParams() { $params = [ 'newsletterpro_source' => 'newsletter', 'id_newsletter' => '{id_newsletter_pro_tpl_history}', ]; $string = ''; foreach ($params as $key => $line) { $string .= '&'.$key.'='.$line; } $string = str_replace("\n", '', $string); $string = preg_replace('/(?<=\w)\s(?=\w)/', '+', $string); $string = str_replace(' ', '', $string); return $string; } /** * Replace the newsletter template variables. * * @param string $template * @param array $variables * * @return string */ public function replaceVars($template, $variables) { self::$replace_vars = $variables; $template = preg_replace_callback( '/{(?P[^}]+)}/', [$this, 'replaceCallback'], $template ); return $template; } /** * Replace the newsletter template variables callback. * * @param array $matches * * @return string */ public function replaceCallback($matches) { $tag = $matches[1]; // tag return isset(self::$replace_vars[$tag]) ? str_replace(' ', '+', trim(self::$replace_vars[$tag])) : '{'.$tag.'}'; } /** * Search product by name, reference, category. * * @param string $query * @param int $id_lang * @param int $id_currency * * @return json */ public function searchProducts($query, $id_lang = null, $id_currency = null) { $data = []; $id_category = (int) Tools::getValue('get_products'); if (!isset($id_lang)) { $id_lang = (int) pqnp_config('LANG'); } $order_by_prefix = null; $front = false; $order_by = '`name`'; $order_way = 'ASC'; $limit = 1000; $id_supplier = false; $start = 0; $only_active = pqnp_config('ONLY_ACTIVE_PRODUCTS'); $query_new_products = $this->l('new products'); $query_price_drop = $this->l('price drop'); $datetime = date('Y-m-d H:i:s'); $sql = ''; if (Version::isBetween('1.5.0.0', '1.5.0.6')) { $sql = 'SELECT p.*, pl.* , t.`rate` AS tax_rate, m.`name` AS manufacturer_name, s.`name` AS supplier_name, i.`id_image`, il.`legend`, cl.`name` AS category_default FROM `'._DB_PREFIX_.'product` p '.$this->context->shop->addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` '.$this->context->shop->addSqlRestrictionOnLang('pl').') LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (p.`id_tax_rules_group` = tr.`id_tax_rules_group` AND tr.`id_country` = '.(int) $this->context->country->id.' AND tr.`id_state` = 0) LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = tr.`id_tax`) LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`) AND i.cover = 1 LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON ( i.`id_image` = il.`id_image`) AND il.`id_lang` = '.(int) $id_lang.' LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON (m.`id_manufacturer` = p.`id_manufacturer`) LEFT JOIN `'._DB_PREFIX_.'supplier` s ON (s.`id_supplier` = p.`id_supplier`) LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON( cl.`id_lang` = pl.`id_lang` AND p.`id_category_default` = cl.`id_category` ) '. ($id_category ? 'LEFT JOIN `'._DB_PREFIX_.'category_product` c ON (c.`id_product` = p.`id_product`)' : ''); if (preg_match('/^(\s+)?'.$query_price_drop.'(\s+)?$/i', $query, $price_drop)) { $sql .= ' INNER JOIN `'._DB_PREFIX_.'specific_price` sp ON ( sp.`id_product` = p.`id_product` AND ((sp.`from` <= "'.$datetime.'" AND sp.`to` >= "'.$datetime.'") OR sp.`to` = "0000-00-00 00:00:00") ) '; } $sql .= 'WHERE pl.`id_lang` = '.(int) $id_lang. ($id_category ? ' AND c.`id_category` = '.(int) $id_category : ''). ($only_active ? ' AND p.`active` = 1' : ''); if (preg_match('/^(\s+)?'.$query_new_products.'(\s+)?$/i', $query) && empty($price_drop)) { $order_by = 'p.`date_add`'; $order_way = 'DESC'; $sql .= ' AND ( DATEDIFF( p.`date_add`, DATE_SUB( NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY ) ) > 0 ) = 1 '; } elseif (empty($price_drop)) { $sql .= ' AND ( pl.`name` LIKE "%'.pSQL($query).'%" OR cl.`name` LIKE "%'.pSQL($query).'%" OR p.`reference` LIKE "%'.pSQL($query).'%" )'; } $sql .= ' GROUP BY p.`id_product` ORDER BY '.(isset($order_by_prefix) ? pSQL($order_by_prefix).'.' : '').''.pSQL($order_by).' '.pSQL($order_way). ($limit > 0 ? ' LIMIT '.(int) $start.','.(int) $limit : ''); } elseif (Version::isBetween('1.5.0.4', '1.5.0.18')) { $sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, product_attribute_shop.`id_product_attribute`, pl.`description`, pl.`description_short`, pl.`available_now`, pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image`, il.`legend`, m.`name` AS manufacturer_name, tl.`name` AS tax_name, t.`rate`, cl.`name` AS category_default, DATEDIFF(product_shop.`date_add`, DATE_SUB(NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY)) > 0 AS new, (product_shop.`price` * IF(t.`rate`,((100 + (t.`rate`))/100),1)) AS orderprice FROM `'._DB_PREFIX_.'category_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = cp.`id_product` '.Shop::addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (p.`id_product` = pa.`id_product`) '.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.`default_on` = 1').' '.Product::sqlStock('p', 'product_attribute_shop', false, $this->context->shop).' LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (product_shop.`id_category_default` = cl.`id_category` AND cl.`id_lang` = '.(int) $id_lang.Shop::addSqlRestrictionOnLang('cl').' ) LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int) $id_lang.Shop::addSqlRestrictionOnLang('pl').' ) LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`)'. Shop::addSqlAssociation('image', 'i', false, 'i.cover=1').' LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (image_shop.`id_image` = il.`id_image` AND il.`id_lang` = '.(int) $id_lang.') LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (product_shop.`id_tax_rules_group` = tr.`id_tax_rules_group` AND tr.`id_country` = '.(int) $this->context->country->id.' AND tr.`id_state` = 0 AND tr.`zipcode_from` = 0) LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = tr.`id_tax`) LEFT JOIN `'._DB_PREFIX_.'tax_lang` tl ON (t.`id_tax` = tl.`id_tax` AND tl.`id_lang` = '.(int) $id_lang.') LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON m.`id_manufacturer` = p.`id_manufacturer`'; if (preg_match('/^(\s+)?'.$query_price_drop.'(\s+)?$/i', $query, $price_drop)) { $sql .= ' INNER JOIN `'._DB_PREFIX_.'specific_price` sp ON ( sp.`id_product` = p.`id_product` AND ((sp.`from` <= "'.pSQL($datetime).'" AND sp.`to` >= "'.pSQL($datetime).'") OR sp.`to` = "0000-00-00 00:00:00") ) '; } $sql .= 'WHERE product_shop.`id_shop` = '.(int) $this->context->shop->id.' AND (pa.id_product_attribute IS NULL OR product_attribute_shop.id_shop='.(int) $this->context->shop->id.') AND (i.id_image IS NULL OR image_shop.id_shop='.(int) $this->context->shop->id.')' .($only_active ? ' AND product_shop.`active` = 1' : '') .($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '') .($id_supplier ? ' AND p.id_supplier = '.(int) $id_supplier : ''); if (preg_match('/^(\s+)?'.$query_new_products.'(\s+)?$/i', $query) && empty($price_drop)) { $order_by = 'product_shop.`date_add`'; $order_way = 'DESC'; $sql .= ' AND ( DATEDIFF( product_shop.`date_add`, DATE_SUB( NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY ) ) > 0 ) = 1 '; } elseif (empty($price_drop)) { $sql .= ' AND ( pl.`name` LIKE "%'.pSQL($query).'%" OR cl.`name` LIKE "%'.pSQL($query).'%" OR p.`reference` LIKE "%'.pSQL($query).'%" )'; } $sql .= ' GROUP BY p.`id_product` ORDER BY '.pSQL($order_by).' '.pSQL($order_way).' LIMIT 0,'.(int) $limit.';'; } else { $sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, product_attribute_shop.`id_product_attribute`, pl.`description`, pl.`description_short`, pl.`available_now`, pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image`, il.`legend`, m.`name` AS manufacturer_name, tl.`name` AS tax_name, t.`rate`, cl.`name` AS category_default, DATEDIFF(product_shop.`date_add`, DATE_SUB(NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY)) > 0 AS new, (product_shop.`price` * IF(t.`rate`,((100 + (t.`rate`))/100),1)) AS orderprice FROM `'._DB_PREFIX_.'category_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = cp.`id_product` '.Shop::addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (p.`id_product` = pa.`id_product`) '.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.`default_on` = 1').' '.Product::sqlStock('p', 'product_attribute_shop', false, $this->context->shop).' LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (product_shop.`id_category_default` = cl.`id_category` AND cl.`id_lang` = '.(int) $id_lang.Shop::addSqlRestrictionOnLang('cl').' ) LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int) $id_lang.Shop::addSqlRestrictionOnLang('pl').' ) LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`)'. Shop::addSqlAssociation('image', 'i', false, 'image_shop.cover=1').' LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (image_shop.`id_image` = il.`id_image` AND il.`id_lang` = '.(int) $id_lang.') LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (product_shop.`id_tax_rules_group` = tr.`id_tax_rules_group` AND tr.`id_country` = '.(int) $this->context->country->id.' AND tr.`id_state` = 0 AND tr.`zipcode_from` = 0) LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = tr.`id_tax`) LEFT JOIN `'._DB_PREFIX_.'tax_lang` tl ON (t.`id_tax` = tl.`id_tax` AND tl.`id_lang` = '.(int) $id_lang.') LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON m.`id_manufacturer` = p.`id_manufacturer`'; if (preg_match('/^(\s+)?'.$query_price_drop.'(\s+)?$/i', $query, $price_drop)) { $sql .= ' INNER JOIN `'._DB_PREFIX_.'specific_price` sp ON ( sp.`id_product` = p.`id_product` AND ((sp.`from` <= "'.pSQL($datetime).'" AND sp.`to` >= "'.pSQL($datetime).'") OR sp.`to` = "0000-00-00 00:00:00") ) '; } $sql .= ' WHERE product_shop.`id_shop` = '.(int) $this->context->shop->id.' AND (pa.id_product_attribute IS NULL OR product_attribute_shop.id_shop='.(int) $this->context->shop->id.') AND (i.id_image IS NULL OR image_shop.id_shop='.(int) $this->context->shop->id.')' .($only_active ? ' AND product_shop.`active` = 1' : '') .($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '') .($id_supplier ? ' AND p.id_supplier = '.(int) $id_supplier : ''); if (preg_match('/^(\s+)?'.$query_new_products.'(\s+)?$/i', $query) && empty($price_drop)) { $order_by = 'product_shop.`date_add`'; $order_way = 'DESC'; $sql .= ' AND ( DATEDIFF( product_shop.`date_add`, DATE_SUB( NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY ) ) > 0 ) = 1 '; } elseif (empty($price_drop)) { $sql .= ' AND ( pl.`name` LIKE "%'.pSQL($query).'%" OR cl.`name` LIKE "%'.pSQL($query).'%" OR p.`reference` LIKE "%'.pSQL($query).'%" )'; } $sql .= ' GROUP BY p.`id_product` ORDER BY '.pSQL($order_by).' '.pSQL($order_way).' LIMIT 0,'.(int) $limit.';'; } if ((int) pqnp_ini_config('get_category_products_prestashop')) { $products = Product::searchByName($id_lang, $query); } else { $products = Db::getInstance()->executeS($sql); } if (empty($products)) { $data['products'] = $products; return Tools::jsonEncode($data); } $data['products'] = $this->getProductsAttributes($id_lang, $products, $id_currency); return Tools::jsonEncode($data); } /** * Sort products id's. * * @param array $products * @param int $ids * * @return array */ private function sortProductsIds($products, $ids) { $products_sorted = []; foreach ($products as $product) { $id_product = $product['id_product']; if (($search = array_search($id_product, $ids)) !== false) { $products_sorted[$search] = $product; } } ksort($products_sorted); return array_values($products_sorted); } /** * Get product image. * * @param int $id * @param string $image_type * * @return json */ public function getImageOfProduct($id, $image_type) { $errors = []; $product = []; $response = ['status' => false, 'errors' => &$errors, 'product' => []]; if (!$id) { $response['status'] = true; return Tools::jsonEncode($response); } if ($image_size = Image::getSize($image_type)) { $id_lang = (int) pqnp_config('LANG'); $prod = new Product($id, false, $id_lang); $id_image = (int) $prod->getCoverWs(); $src = $this->getImageLink($prod->link_rewrite, $id_image, $image_type); $product['id_product'] = (int) $prod->id; $product['src'] = $src; $product['width'] = $image_size['width']; $product['height'] = $image_size['height']; } else { $errors[] = $this->l('Invalid image type!'); } if (!$product) { $errors[] = $this->l('Invalid product!'); } if (empty($errors)) { $response['status'] = true; $response['product'] = $product; } return Tools::jsonEncode($response); } /** * Get products images. * * @param int $ids * @param string $image_type * * @return json */ public function getImagesOfProducts($ids, $image_type) { $errors = []; $products = []; $response = ['status' => false, 'errors' => &$errors, 'products' => $products]; if (!$ids) { $response['status'] = true; return Tools::jsonEncode($response); } if ($image_size = Image::getSize($image_type)) { $sql = $this->getProductsByIdSql($ids); $prod = Db::getInstance()->executeS($sql); foreach ($prod as $product) { $id_product = (int) $product['id_product']; $products[$id_product]['id_product'] = $id_product; $products[$id_product]['src'] = $this->getImageLink($product['link_rewrite'], $product['id_image'], $image_type); $products[$id_product]['width'] = $image_size['width']; $products[$id_product]['height'] = $image_size['height']; } } else { $errors[] = $this->l('Invalid image type!'); } if (empty($errors)) { $response['status'] = true; $response['products'] = $products; } return Tools::jsonEncode($response); } /** * Get products sql. * * @param array $ids * @param int $id_lang * * @return string */ private function getProductsByIdSql($ids, $id_lang = null) { if (!$ids) { return ''; } $ids_implode = trim(implode(',', $ids), ','); $id_category = (int) Tools::getValue('get_products'); if (!isset($id_lang)) { $id_lang = (int) pqnp_config('LANG'); } $order_by_prefix = null; $front = false; $order_by = '`name`'; $order_way = 'ASC'; $limit = 1000; $id_supplier = false; $start = 0; $only_active = pqnp_config('ONLY_ACTIVE_PRODUCTS'); $sql = ''; if (Version::isBetween('1.5.0.0', '1.5.0.6')) { $sql = 'SELECT p.*, pl.* , t.`rate` AS tax_rate, m.`name` AS manufacturer_name, s.`name` AS supplier_name, i.`id_image`, il.`legend`,cl.`name` AS category_default FROM `'._DB_PREFIX_.'product` p '.$this->context->shop->addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` '.$this->context->shop->addSqlRestrictionOnLang('pl').') LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (p.`id_tax_rules_group` = tr.`id_tax_rules_group` AND tr.`id_country` = '.(int) $this->context->country->id.' AND tr.`id_state` = 0) LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = tr.`id_tax`) LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`) AND i.cover = 1 LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON ( i.`id_image` = il.`id_image`) AND il.`id_lang` = '.(int) $id_lang.' LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON (m.`id_manufacturer` = p.`id_manufacturer`) LEFT JOIN `'._DB_PREFIX_.'supplier` s ON (s.`id_supplier` = p.`id_supplier`) LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON( cl.`id_lang` = pl.`id_lang` AND p.`id_category_default` = cl.`id_category` ) '. ($id_category ? 'LEFT JOIN `'._DB_PREFIX_.'category_product` c ON (c.`id_product` = p.`id_product`)' : ''); $sql .= 'WHERE pl.`id_lang` = '.(int) $id_lang. ($id_category ? ' AND c.`id_category` = '.(int) $id_category : ''). ($only_active ? ' AND p.`active` = 1' : ''); $sql .= ' AND (p.`id_product` IN ('.$ids_implode.')) '; $sql .= ' GROUP BY p.`id_product` ORDER BY '.(isset($order_by_prefix) ? pSQL($order_by_prefix).'.' : '').''.pSQL($order_by).' '.pSQL($order_way). ($limit > 0 ? ' LIMIT '.(int) $start.','.(int) $limit : ''); } elseif (Version::isBetween('1.5.0.4', '1.5.0.18')) { $sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, product_attribute_shop.`id_product_attribute`, pl.`description`, pl.`description_short`, pl.`available_now`, pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image`, il.`legend`, m.`name` AS manufacturer_name, tl.`name` AS tax_name, t.`rate`, cl.`name` AS category_default, DATEDIFF(product_shop.`date_add`, DATE_SUB(NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY)) > 0 AS new, (product_shop.`price` * IF(t.`rate`,((100 + (t.`rate`))/100),1)) AS orderprice FROM `'._DB_PREFIX_.'category_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = cp.`id_product` '.Shop::addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (p.`id_product` = pa.`id_product`) '.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.`default_on` = 1').' '.Product::sqlStock('p', 'product_attribute_shop', false, $this->context->shop).' LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (product_shop.`id_category_default` = cl.`id_category` AND cl.`id_lang` = '.(int) $id_lang.Shop::addSqlRestrictionOnLang('cl').' ) LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int) $id_lang.Shop::addSqlRestrictionOnLang('pl').' ) LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`)'. Shop::addSqlAssociation('image', 'i', false, 'i.cover=1').' LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (image_shop.`id_image` = il.`id_image` AND il.`id_lang` = '.(int) $id_lang.') LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (product_shop.`id_tax_rules_group` = tr.`id_tax_rules_group` AND tr.`id_country` = '.(int) $this->context->country->id.' AND tr.`id_state` = 0 AND tr.`zipcode_from` = 0) LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = tr.`id_tax`) LEFT JOIN `'._DB_PREFIX_.'tax_lang` tl ON (t.`id_tax` = tl.`id_tax` AND tl.`id_lang` = '.(int) $id_lang.') LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON m.`id_manufacturer` = p.`id_manufacturer`'; $sql .= 'WHERE product_shop.`id_shop` = '.(int) $this->context->shop->id.' AND (pa.id_product_attribute IS NULL OR product_attribute_shop.id_shop='.(int) $this->context->shop->id.') AND (i.id_image IS NULL OR image_shop.id_shop='.(int) $this->context->shop->id.')' .($only_active ? ' AND product_shop.`active` = 1' : '') .($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '') .($id_supplier ? ' AND p.id_supplier = '.(int) $id_supplier : ''); $sql .= ' AND (p.`id_product` IN ('.$ids_implode.')) '; $sql .= ' GROUP BY p.`id_product` ORDER BY '.pSQL($order_by).' '.pSQL($order_way).' LIMIT 0,'.(int) $limit.';'; } else { $sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, product_attribute_shop.`id_product_attribute`, pl.`description`, pl.`description_short`, pl.`available_now`, pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image`, il.`legend`, m.`name` AS manufacturer_name, tl.`name` AS tax_name, t.`rate`, cl.`name` AS category_default, DATEDIFF(product_shop.`date_add`, DATE_SUB(NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY)) > 0 AS new, (product_shop.`price` * IF(t.`rate`,((100 + (t.`rate`))/100),1)) AS orderprice FROM `'._DB_PREFIX_.'category_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = cp.`id_product` '.Shop::addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (p.`id_product` = pa.`id_product`) '.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.`default_on` = 1').' '.Product::sqlStock('p', 'product_attribute_shop', false, $this->context->shop).' LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (product_shop.`id_category_default` = cl.`id_category` AND cl.`id_lang` = '.(int) $id_lang.Shop::addSqlRestrictionOnLang('cl').' ) LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int) $id_lang.Shop::addSqlRestrictionOnLang('pl').' ) LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`)'. Shop::addSqlAssociation('image', 'i', false, 'image_shop.cover=1').' LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (image_shop.`id_image` = il.`id_image` AND il.`id_lang` = '.(int) $id_lang.') LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (product_shop.`id_tax_rules_group` = tr.`id_tax_rules_group` AND tr.`id_country` = '.(int) $this->context->country->id.' AND tr.`id_state` = 0 AND tr.`zipcode_from` = 0) LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = tr.`id_tax`) LEFT JOIN `'._DB_PREFIX_.'tax_lang` tl ON (t.`id_tax` = tl.`id_tax` AND tl.`id_lang` = '.(int) $id_lang.') LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON m.`id_manufacturer` = p.`id_manufacturer`'; $sql .= ' WHERE product_shop.`id_shop` = '.(int) $this->context->shop->id.' AND (pa.id_product_attribute IS NULL OR product_attribute_shop.id_shop='.(int) $this->context->shop->id.') AND (i.id_image IS NULL OR image_shop.id_shop='.(int) $this->context->shop->id.')' .($only_active ? ' AND product_shop.`active` = 1' : '') .($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '') .($id_supplier ? ' AND p.id_supplier = '.(int) $id_supplier : ''); $sql .= ' AND (p.`id_product` IN ('.$ids_implode.')) '; $sql .= ' GROUP BY p.`id_product` ORDER BY '.pSQL($order_by).' '.pSQL($order_way).' LIMIT 0,'.(int) $limit.';'; } return $sql; } /** * Get products by id's. * * @param array $ids * * @return json */ public function getProductsById($ids) { $data = []; $sql = $this->getProductsByIdSql($ids); if (!$sql) { return Tools::jsonEncode(['products' => []]); } $products = Db::getInstance()->executeS($sql); $products = $this->sortProductsIds($products, $ids); if (empty($products)) { $data['products'] = $products; return Tools::jsonEncode($data); } $id_lang = (int) pqnp_config('LANG'); $data['products'] = $this->getProductsAttributes($id_lang, $products); return Tools::jsonEncode($data); } /** * Get product by id. * * @param int $id * @param int $id_lang * * @return bool */ public function getProductById($id, $id_lang = null, $productProperties = false) { $sql = $this->getProductsByIdSql([$id], $id_lang); if (!$sql) { return false; } $products = Db::getInstance()->executeS($sql); if (empty($products)) { return false; } if (!isset($id_lang)) { $id_lang = (int) pqnp_config('LANG'); } $products = $this->getProductsAttributes($id_lang, $products, null, $productProperties); if (isset($products[0])) { return $products[0]; } return false; } /** * Get shop url. * * @param int $id_shop * * @return string */ public function getShopUrl($id_shop = null) { if (!isset($id_shop)) { $id_shop = (int) $this->context->shop->id; } $base_uri = __PS_BASE_URI__; $default_shop_url = Tools::getHttpHost(true).$base_uri; $shop_url = ''; if ((bool) Configuration::get('PS_MULTISHOP_FEATURE_ACTIVE') && ($shop = Shop::getShop((int) $id_shop))) { $shop_url = $this->context->shop->getBaseURL(); } else { $shop_url = $default_shop_url; } $len = Tools::strlen($shop_url); if (isset($shop_url[$len - 1])) { $char = $shop_url[$len - 1]; if ('/' !== $char) { $shop_url .= '/'; } } $shop_url = $this->relplaceAdminLink($shop_url); return $shop_url; } /** * Prepare emails for sending newsletters. * * @return json */ public function prepareEmails($content = null, $emails_json = null) { $emails = Tools::jsonEncode([]); $post = &$_POST; if (isset($post['prepareEmails'])) { $emails = $post['prepareEmails']; } NewsletterProLog::clearSend(); NewsletterProSendConnection::clearAll(); $emails = Tools::jsonDecode($emails); if (isset($emails_json)) { $emails = array_merge($emails, Tools::jsonDecode($emails_json)); } $response = NewsletterProAjaxResponse::newInstance(); try { $prepare = NewsletterProSendManager::newInstance()->prepare; if (isset($content) && $content) { $template = NewsletterProTemplate::newString(['', $content])->load(); $prepare->setTemplate($template); } else { $template = NewsletterProTemplate::newFile(pqnp_config('NEWSLETTER_TEMPLATE'))->load(); $prepare->setTemplate($template); } $prepare->setEmails($emails)->add(); $response->set('count_emails', count($prepare->emails)); } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } /** * Unserialize a string. * * @param string $serialized * * @return array */ public static function unSerialize($serialized) { if (is_string($serialized) && preg_match('/a:[0-9]+:\{.*\}/', $serialized)) { return @unserialize($serialized); } return []; } /** * Select all customers. * * @return json */ public function selectAllCustomers() { $sql_shops_id = ''; $get_active_shops_id = NewsletterProTools::getActiveShopsId(); foreach ($get_active_shops_id as $key => $id_shop) { $sql_shops_id .= 'c.`id_shop` = '.(int) $id_shop.(end($get_active_shops_id) == $id_shop ? '' : ' OR '); } $sql = 'SELECT c.`id_customer` AS `id`, c.`email` FROM `'._DB_PREFIX_.'customer` c WHERE( '.$sql_shops_id.' ) ORDER BY c.`id_customer` DESC;'; $userlist = Db::getInstance()->executeS($sql); foreach (array_keys($userlist) as $key) { $userlist[$key]['user_type'] = 'customer'; } return Tools::jsonEncode($userlist); } public function leftMenuActive($val) { $response = NewsletterProAjaxResponse::newInstance(); if (!pqnp_config('LEFT_MENU_ACTIVE', $val)) { $response->addError($this->l('The menu layout has not been changed in database.')); } return $response->display(); } /** * Change settings view active only. * * @param bool $val * * @return json */ public function viewActiveOnly($val) { if (pqnp_config('VIEW_ACTIVE_ONLY', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings convert css to inline style. * * @param bool $val * * @return json */ public function convertCssToInlineStyle($val) { if (pqnp_config('CONVERT_CSS_TO_INLINE_STYLE', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings rum multiple tasks. * * @param bool $val * * @return json */ public function runMultimpleTasks($val) { if (pqnp_config('RUN_MULTIPLE_TASKS', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings. * * @param bool $val * * @return json */ public function displayCustomerAccountSettings($val) { if (pqnp_config('DISPLYA_MY_ACCOUNT_NP_SETTINGS', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings subscribe by category. * * @param bool $val * * @return json */ public function subscribeByCategory($val) { if (pqnp_config('SUBSCRIBE_BY_CATEGORY', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings subscribe by list of interests. * * @param bool $val * * @return json */ public function subscribeByCListOfInterest($val) { if (pqnp_config('CUSTOMER_SUBSCRIBE_BY_LOI', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings subscribe by list of interests. * * @param bool $val * * @return json */ public function subscribeByCAListOfInterest($val) { if (pqnp_config('CUSTOMER_ACCOUNT_SUBSCRIBE_BY_LOI', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * @param bool $val * * @return json */ public function devMode($val) { if (pqnp_config('DEV_MODE', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings send newsletter on subscribe. * * @param bool $val * * @return json */ public function sendNewsletterOnSubscribe($val) { if (pqnp_config('SEND_NEWSLETTER_ON_SUBSCRIBE', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings forward feature active. * * @param bool $val * * @return json */ public function forwardingFeatureActive($val) { if (pqnp_config('FWD_FEATURE_ACTIVE', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings forward feature active. * * @param bool $val * * @return json */ public function sendEmbededImagesActive($val) { $response = NewsletterProAjaxResponse::newInstance([]); if (ini_get('allow_url_fopen')) { if (!pqnp_config('SEND_EMBEDED_IMAGES', $val)) { $response->addError($this->l('An error occurred.')); } } else { pqnp_config('SEND_EMBEDED_IMAGES', 0); $response->addError($this->l('You can embed files from a URL if allow_url_fopen is on in php.ini.')); } return $response->display(); } /** * Change settings forward feature active. * * @param bool $val * * @return json */ public function sendEmailMimeText($val) { if (pqnp_config('EMAIL_MIME_TEXT', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings view active products. * * @param bool $val * * @return json */ public function chimpSyncUnsubscribed($val) { if (pqnp_config('CHIMP_SYNC_UNSUBSCRIBED', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings view active products. * * @param bool $val * * @return json */ public function displayOnliActiveProducts($val) { if (pqnp_config('ONLY_ACTIVE_PRODUCTS', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings product link rewrite. * * @param bool $val * * @return json */ public function productFriendlyURL($val) { if (pqnp_config('PRODUCT_LINK_REWRITE', $val)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings debug mode. * * @param bool $val * * @return json */ public function debugMode($bool) { if (pqnp_config('DEBUG_MODE', $bool)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } public function loadMinified($bool) { if (pqnp_config('LOAD_MINIFIED', (bool) $bool)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Change settings subscription secure subscribe. * * @param bool $val * * @return json */ public function subscriptionSecureSubscribe($bool) { if (pqnp_config('SUBSCRIPTION_SECURE_SUBSCRIBE', $bool)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } public function subscriptionControllerEnabled($bool) { if (pqnp_config('SUBSCRIPTION_CONTROLLER_ENABLED', $bool)) { return Tools::jsonEncode(['status' => true]); } else { return Tools::jsonEncode(['status' => false]); } } /** * Clear the secure subscribed temporary email addresses. * * @param bool $val * * @return json */ public function clearSubscribersTemp() { $errors = []; $response = ['status' => false, 'errors' => &$errors, 'msg' => '']; $sql = 'DELETE FROM `'._DB_PREFIX_.'newsletter_pro_subscribers_temp` WHERE `date_add` < "'.date('Y-m-d H:i:s', strtotime('-1 weeks')).'"'; if (!Db::getInstance()->execute($sql)) { $errors[] = $this->l('The emails has not been cleared.'); } if (empty($errors)) { $response['msg'] = $this->l('The emails has been cleared successfully.'); $response['status'] = true; } return Tools::jsonEncode($response); } /** * Imprt email addresses from the blcok newsletter module. * * @return json */ public function importEmailsFromBlockNewsletter($newsletter_date_add = null) { $id_default_shop = (int) pqnp_config('PS_SHOP_DEFAULT'); $errors = []; $response = ['status' => false, 'errors' => &$errors, 'msg' => '']; $bn_info = $this->getBlockNewsletterInfo(); $cout_success = 0; $cout_errors = 0; if ($bn_info['isInstalled']) { $emails_to_import = Db::getInstance()->executeS(' SELECT * FROM `'._DB_PREFIX_.NewsletterProDefaultNewsletterTable::getTableName().'` '.(isset($newsletter_date_add) ? ' WHERE newsletter_date_add >= "'.pSQL($newsletter_date_add).'"' : '').' '); if ($emails_to_import) { foreach ($emails_to_import as $row) { try { $id_shop = isset($row['id_shop']) ? $row['id_shop'] : $id_default_shop; $id_shop_group = isset($row['id_shop_group']) ? $row['id_shop_group'] : $id_default_shop; $email = $row['email']; $newsletter_date_add = isset($row['newsletter_date_add']) ? $row['newsletter_date_add'] : date('Y-m-d H:i:s'); $ip_registration_newsletter = isset($row['ip_registration_newsletter']) ? $row['ip_registration_newsletter'] : ''; $active = isset($row['active']) ? $row['active'] : 1; $id = NewsletterProSubscribers::getIdByEmail($email); // check if the email not exists if (!$id) { $subscriber = new NewsletterProSubscribers(); $subscriber->id_shop = (int) $id_shop; $subscriber->id_shop_group = (int) $id_shop_group; $subscriber->email = $email; $subscriber->newsletter_date_add = $newsletter_date_add; $subscriber->ip_registration_newsletter = $ip_registration_newsletter; $subscriber->active = (int) $active; if ($subscriber->add()) { ++$cout_success; } else { ++$cout_errors; } } } catch (Exception $e) { ++$cout_errors; } } } } if (empty($errors)) { if ($cout_success > 0 && 0 == $cout_errors) { $response['msg'] = sprintf($this->l('(%s) emails has been imported successfully.'), $cout_success); } elseif ($cout_success > 0 && $cout_errors > 0) { $response['msg'] = sprintf($this->l('(%s) emails has been imported successfully and at (%s) emails an error occurred.'), $cout_success, $cout_errors); } elseif (0 == $cout_success && $cout_errors > 0) { $response['msg'] = sprintf($this->l('An error occurred at (%s) emails.'), $cout_errors); } elseif (!empty($emails_to_import)) { $response['msg'] = $this->l('All the emails are imported.'); } else { $response['msg'] = $this->l('There are no emails to import.'); } $response['status'] = true; } return Tools::jsonEncode($response); } public function importEmailsFromBlockNewsletterCron($newsletter_date_add) { return $this->importEmailsFromBlockNewsletter($newsletter_date_add); } /** * Get newsletter pro subscription info. * * @return array */ public function getNewsletterProSubscriptionInfo() { $hooks = []; $popupTypesHooks = pqnp_config('SUBSCRIPTION_HOOK_POPUP_TYPE'); foreach (NewsletterProSubscriptionHook::$hooks as $key => $hook) { $id_hook = Hook::getIdByName($hook); $hooks[$key]['id_hook'] = $id_hook; $hooks[$key]['name'] = $hook; $hooks[$key]['isRegistred'] = false; $hooks[$key]['position'] = 0; $hooks[$key]['popup_type'] = 0; $upperHook = Tools::strtoupper($hook); if (array_key_exists($upperHook, $popupTypesHooks)) { $hooks[$key]['popup_type'] = (int) $popupTypesHooks[$upperHook]; } if ($this->isRegisteredInHook($hook) && $this->isHookableOn($hook)) { $hooks[$key]['isRegistred'] = true; $hooks[$key]['position'] = $this->getModulePosition($this, $id_hook); } } return [ 'name' => $this->name, 'isInstalled' => true, 'isEnabled' => true, 'hooks' => $hooks, ]; } /** * Get newsletter pro info. * * @return array */ public function getNewsletterProInfo() { $hooks = []; foreach ($this->getHooksList() as $key => $hook) { $id_hook = Hook::getIdByName($hook); $hooks[$key]['id_hook'] = $id_hook; $hooks[$key]['name'] = $hook; $hooks[$key]['isRegistred'] = false; $hooks[$key]['position'] = 0; if ($this->isRegisteredInHook($hook) && $this->isHookableOn($hook)) { $hooks[$key]['isRegistred'] = true; $hooks[$key]['position'] = $this->getModulePosition($this, $id_hook); } } return [ 'name' => $this->name, 'isInstalled' => true, 'isEnabled' => true, 'hooks' => $hooks, ]; } /** * Get module position. * * @param object $obj * @param int $id_hook * * @return int */ public function getModulePosition($obj, $id_hook) { if (method_exists($obj, 'getPosition')) { return $obj->getPosition($id_hook); } else { if (isset(Hook::$preloadModulesFromHooks)) { if (isset(Hook::$preloadModulesFromHooks[$id_hook])) { if (isset(Hook::$preloadModulesFromHooks[$id_hook]['module_position'][$obj->id])) { return Hook::$preloadModulesFromHooks[$id_hook]['module_position'][$obj->id]; } else { return 0; } } } $result = Db::getInstance()->getRow(' SELECT `position` FROM `'._DB_PREFIX_.'hook_module` WHERE `id_hook` = '.(int) $id_hook.' AND `id_module` = '.(int) $obj->id.' AND `id_shop` = '.(int) Context::getContext()->shop->id); return (int) $result['position']; } } /** * Get block newsletter info. * * @return array */ public function getBlockNewsletterInfo() { $hooks = []; $modules = ['ps_emailsubscription', 'blocknewsletter']; $name = 'ps_emailsubscription'; foreach ($modules as $moduleName) { if (Module::isInstalled($moduleName)) { $name = $moduleName; break; } } $is_installed = Module::isInstalled($name); if ($is_installed) { $blocknewsletter = Module::getInstanceByName($name); foreach (NewsletterProSubscriptionHook::$hooks as $key => $hook) { $id_hook = Hook::getIdByName($hook); $hooks[$key]['id_hook'] = $id_hook; $hooks[$key]['name'] = $hook; $hooks[$key]['isRegistred'] = false; $hooks[$key]['position'] = 0; if ($blocknewsletter && $blocknewsletter->isRegisteredInHook($hook) && $blocknewsletter->isHookableOn($hook)) { $hooks[$key]['isRegistred'] = true; $hooks[$key]['position'] = $this->getModulePosition($blocknewsletter, $id_hook); } } } return [ 'name' => $name, 'isInstalled' => $is_installed, 'isEnabled' => NewsletterPro::isModuleEnabled($name), 'hooks' => $hooks, ]; } /** * Check if the module is enabled. * * @param string $name * * @return bool */ public static function isModuleEnabled($name) { if (method_exists('Module', 'isEnabled')) { return Module::isEnabled($name); } else { if (!Cache::isStored('Module::isEnabled'.$name)) { $active = false; $id_module = Db::getInstance()->getValue('SELECT `id_module` FROM `'._DB_PREFIX_.'module` WHERE `name` = \''.pSQL($name).'\''); if (Db::getInstance()->getValue('SELECT `id_module` FROM `'._DB_PREFIX_.'module_shop` WHERE `id_module` = '.(int) $id_module.' AND `id_shop` = '.(int) Context::getContext()->shop->id)) { $active = true; } Cache::store('Module::isEnabled'.$name, (bool) $active); } return Cache::retrieve('Module::isEnabled'.$name); } } /** * Get module google analytics info. * * @return array */ public function getGAnalyticsModuleInfo() { $hooks = []; $name = 'ganalytics'; $is_installed = Module::isInstalled($name); if ($is_installed) { $module = Module::getInstanceByName($name); foreach (['displayHeader', 'displayFooter', 'displayOrderConfirmation'] as $key => $hook) { $id_hook = Hook::getIdByName($hook); $hooks[$key]['id_hook'] = $id_hook; $hooks[$key]['name'] = $hook; $hooks[$key]['isRegistred'] = false; $hooks[$key]['position'] = 0; if ($module->isRegisteredInHook($hook) && $module->isHookableOn($hook)) { $hooks[$key]['isRegistred'] = true; $hooks[$key]['position'] = $this->getModulePosition($module, $id_hook); } } } return [ 'name' => $name, 'isInstalled' => $is_installed, 'isEnabled' => NewsletterPro::isModuleEnabled($name), 'hooks' => $hooks, ]; } /** * Get block newsletter registred hooks. * * @return array */ public function getBlockNewsletterHooksRegistered() { $hooks = []; $bn_info = $this->getBlockNewsletterInfo(); foreach ($bn_info['hooks'] as $hook) { if ($hook['isRegistred']) { $hooks[] = $hook; } } return $hooks; } /** * Get newsletter pro subscription hooks. * * @return array */ public function getNewsletterProSubscriptionHooks() { $np_hooks = $this->getNewsletterProSubscriptionInfo(); return $np_hooks['hooks']; } private function buildRegisteredHooks($hooks, $bn_hooks = []) { $register_hooks = []; $start_hooks = $hooks; foreach ($bn_hooks as $bn_hook) { foreach ($start_hooks as $key => $hook) { if ($bn_hook['isRegistred'] && $bn_hook['name'] == $hook) { $register_hooks[] = [ 'id_hook' => $bn_hook['id_hook'], 'name' => $hook, 'hasPosition' => true, 'position' => $bn_hook['position'], ]; unset($start_hooks[$key]); } } } foreach ($start_hooks as $hook) { $register_hooks[] = [ 'id_hook' => Hook::getIdByName($hook), 'name' => $hook, 'hasPosition' => false, 'position' => 0, ]; } return $register_hooks; } /** * Build unregistred hooks. * * @param array $hooks * @param array $bn_hooks * * @return array */ public function buildUnregistredHooks($hooks, $bn_hooks = []) { $bn_hooks_names = []; foreach ($bn_hooks as $hook) { $bn_hooks_names[] = $hook['name']; } return array_diff($bn_hooks_names, $hooks); } /** * Check if the module is registred in a hook. * * @param string $hook * * @return bool */ public function isRegisteredInHook($hook) { if ('header' == $hook) { $hook_name = Db::getInstance()->getValue(' SELECT `name` FROM `'._DB_PREFIX_.'hook_alias` WHERE `alias` = "'.pSQL($hook).'" '); if ($hook_name) { $hook = $hook_name; } } return parent::isRegisteredInHook($hook); } /** * Enable the newsletter pro subscription * The module will be registered in the hook displayTop. * * @param array $hooks Regsitrer module to the hooks, leave it empty if you want to copy the hooks from the blocknewsletter module * * @return null */ public function updateNewsletterProSubscription($hooks = []) { $removeHooks = array_diff(NewsletterProSubscriptionHook::$hooks, $hooks); foreach (['displayTop', 'displayHeader'] as $hookName) { if (!$this->isRegisteredInHook($hookName)) { $this->registerHook($hookName); } } $bn_info = $this->getBlockNewsletterInfo(); $np_info = $this->getNewsletterProSubscriptionInfo(); if ($bn_info['isInstalled']) { $blocknewsletter = Module::getInstanceByName($bn_info['name']); if ($bn_info['isEnabled']) { $blocknewsletter->disable(); } $register_hooks = $this->buildRegisteredHooks($hooks, $bn_info['hooks']); if (!empty($register_hooks)) { foreach ($register_hooks as $hook) { $this->registerHook($hook['name']); if ($hook['hasPosition']) { $this->updatePosition($hook['id_hook'], 0, $hook['position']); } } } else { // copy the hooks from the blocknewsletter module foreach ($bn_info['hooks'] as $hook) { if ($hook['isRegistred']) { $this->registerHook($hook['name']); $this->updatePosition($hook['id_hook'], 0, $hook['position']); } } } $unregister_hooks = $this->buildUnregistredHooks($hooks, $np_info['hooks']); if (!empty($unregister_hooks)) { foreach ($unregister_hooks as $hook_name) { $this->unregisterHook($hook_name); } } foreach ($removeHooks as $removeHook) { if (!$this->isRegisteredInHook($removeHook)) { $this->unregisterHook($removeHook); } } } else { if (!empty($hooks)) { foreach ($hooks as $hook) { $this->registerHook($hook); } } } } /** * Register/Unregister hooks by hooks info. * * @param array $hooks_info * * @return bool */ public static function executeHooksByInfo($hooks_info) { $module = NewsletterPro::getInstance(); $success = []; foreach ($hooks_info as $hook) { if ($hook['isRegistred']) { $success[] = $module->registerHook($hook['name']); $module->updatePosition($hook['id_hook'], 0, ++$hook['position']); } else { $success[] = $module->unregisterHook($hook['name']); } } return true; } /** * Disable newsletter pro subscription option. */ public function disableNewsletterProSubscription() { $bn_info = $this->getBlockNewsletterInfo(); $np_info = $this->getNewsletterProSubscriptionInfo(); if ($bn_info['isInstalled']) { $blocknewsletter = Module::getInstanceByName($bn_info['name']); if (!$bn_info['isEnabled']) { $blocknewsletter->enable(); } foreach ($bn_info['hooks'] as $hook) { if ($hook['isRegistred']) { $blocknewsletter->registerHook($hook['name']); $blocknewsletter->updatePosition($hook['id_hook'], 0, $hook['position']); } } } foreach ($np_info['hooks'] as $hook) { if ($hook['isRegistred']) { $this->unregisterHook($hook['id_hook']); } } } /** * Setup the newsletter pro subscription. * * @param bool $bool Enable/Disable the newsletter pro subscription * @param array $hooks Regsitrer module to the hooks, leave it empty if you want to copy the hooks from the blocknewsletter module * * @return null */ public function newsletterproSubscriptionActive($bool, $hooks = []) { $popupTypes = $this->request->get('popupTypes', []); pqnp_config('SUBSCRIPTION_HOOK_POPUP_TYPE', NewsletterProSubscriptionHook::convertToUpper($popupTypes)); pqnp_config('SUBSCRIPTION_ACTIVE', (int) $bool); if ($bool) { $this->updateNewsletterProSubscription($hooks); } else { $this->disableNewsletterProSubscription(); } return $this->response->json(); } public function changeSubscriptionControllerTemplate() { $templateId = (int) $this->request->get('templateId', -1); if (0 == $templateId) { pqnp_config('SUBSCRIPTION_CONTROLLER_TEMPLATE_ID', $templateId); return $this->response->json(); } $subscriptionTpl = new NewsletterProSubscriptionTpl($templateId); if (!Validate::isLoadedObject($subscriptionTpl)) { $this->response->error($this->l('Invalid template id.')); return $this->response->json(); } pqnp_config('SUBSCRIPTION_CONTROLLER_TEMPLATE_ID', $templateId); return $this->response->json(); } public function getSubscriptionControllerTemplates() { $templates = NewsletterProSubscriptionTpl::getControllerTemplates(); return $this->response->setData([ 'templates' => $templates, ])->json(); } /** * Change newsletter template. * * @param string $template * * @return json */ public function changeNewsletterTemplate($template) { $path = $this->tpl_location.'newsletter/'.$template; if (preg_match('/^.*.html$/', $template) && file_exists($path)) { pqnp_config('NEWSLETTER_TEMPLATE', $template); return Tools::jsonEncode(['status' => true, 'msg' => '']); } else { return Tools::jsonEncode(['status' => false, 'msg' => $this->l('Invalid template')]); } } /** * Change product template. * * @param string $template * * @return json */ public function changeProductTemplate($template) { $path = $this->tpl_location.'product/'.$template; if (preg_match('/^.*.html$/', $template) && file_exists($path)) { pqnp_config('PRODUCT_TEMPLATE', $template); return Tools::jsonEncode(['status' => true, 'msg' => '']); } else { return Tools::jsonEncode(['status' => false, 'msg' => $this->l('Invalid template')]); } } /** * Change produt image size. * * @param string $image_size * * @return json */ public function changeProductImageSize($image_size) { $errors = []; if (false != Image::getSize($image_size)) { pqnp_config('IMAGE_TYPE', trim($image_size)); } else { $errors[] = $this->l('Invalid image type!'); } return Tools::jsonEncode($errors); } /** * Change product currency. * * @param int $get_currency * * @return json */ public function changeProductCurrency($get_currency) { $errors = []; $currencies = Currency::getCurrencies(); $currency_exists = false; foreach ($currencies as $currency) { if ((int) $currency['id_currency'] == (int) $get_currency) { $currency_exists = true; break; } } $get_currency = (true == $currency_exists) ? (int) $get_currency : (int) pqnp_config('PS_CURRENCY_DEFAULT'); if (!pqnp_config('CURRENCY', $get_currency)) { $errors[] = $this->l('Currency not changed'); } return Tools::jsonEncode($errors); } /** * Change product language. * * @param int $id * * @return json */ public function changeProductLanguage($id) { $errors = []; $languages = Language::getLanguages(true, $this->context->shop->id); $id_lang_exists = false; foreach ($languages as $language) { if ((int) $language['id_lang'] == (int) $id) { $id_lang_exists = true; break; } } $id = (true == $id_lang_exists) ? (int) $id : (int) pqnp_config('PS_LANG_DEFAULT'); if (!pqnp_config('LANG', $id)) { $errors[] = $this->l('Language not changed'); } return Tools::jsonEncode($errors); } /** * Get product template content. * * @param array $data * @param bool $readcontent * * @return json */ public function getProductTemplateContent($data, $readcontent) { $errors = []; $content = ''; $columns = 0; $render = ''; $response = [ 'status' => false, 'errors' => &$errors, 'content' => &$content, 'render' => &$render, 'columns' => &$columns, ]; $name = $data['filename']; $path = $data['path']; if (file_exists($path)) { if ((Tools::file_get_contents($path)) !== false) { if (!pqnp_config('PRODUCT_TEMPLATE', $name)) { $errors[] = $this->l('Error on creating the configuration!'); } else { if (pqnp_config('DEBUG_MODE')) { $content = $this->getProductContent(); } else { $content = @$this->getProductContent(); } $columns = $this->getProductColumns(); if ($readcontent) { try { if (pqnp_config('DEBUG_MODE')) { $render = $this->getProductContent(true); } else { $render = @$this->getProductContent(true); } } catch (Exception $e) { $errors[] = $e->getMessage(); } } } } else { $errors[] = $this->l('The file cannot be read, check the CHMOD !'); } } else { $errors[] = $this->l('File not exists!'); } if (empty($errors)) { $response['status'] = true; } return Tools::jsonEncode($response); } /** * Get product content. * * @param bool $view * * @return string */ public function getProductContent($view = false) { $template = pqnp_config('PRODUCT_TEMPLATE'); $path = $this->tpl_location.'product/'.$template; if (file_exists($path)) { $content = Tools::file_get_contents($path); if (false == $view) { return $content; } // remove comments // $content = preg_replace('//', '', $content); // remove columns for the old templates // $content = preg_replace('/\{columns=\d+\}/', '', $content); $image_type = (string) pqnp_config('IMAGE_TYPE'); $img_name = (string) $this->context->language->iso_code.'-default-'.$image_type.'.jpg'; $image_path = _PS_PROD_IMG_DIR_.$img_name; if (file_exists($image_path)) { $image_path = Tools::getHttpHost(true)._THEME_PROD_DIR_.$img_name; } elseif (file_exists(_PS_PROD_IMG_DIR_.(string) $this->context->language->iso_code.'.jpg')) { $image_path = Tools::getHttpHost(true)._THEME_PROD_DIR_.(string) $this->context->language->iso_code.'.jpg'; } else { $files = scandir(_PS_PROD_IMG_DIR_); $files = preg_grep('/^('.$this->context->language->iso_code.').*'.$image_type.'.*.jpg$/', $files); $img_name = array_values($files); $image_path = isset($img_name[0]) ? $img_name[0] : ''; $image_path = Tools::getHttpHost(true)._THEME_PROD_DIR_.$image_path; } $size = Image::getSize($image_type); $header_content = ''; if (preg_match('/\s*?\s*?/', $content, $match)) { $header_content = trim($match['header']); } if (!preg_match('/content\s+=\s+template/', $header_content)) { $content = str_replace(['{image_path}', '{image_width}', '{image_height}'], [$image_path, $size['width'], $size['height']], $content); } return $content; } return false; } /** * Get product columns. * * @return int */ public function getProductColumns() { $template = pqnp_config('PRODUCT_TEMPLATE'); $path = $this->tpl_location.'product/'.$template; if (file_exists($path)) { $content = Tools::file_get_contents($path); if (preg_match('/\{columns=(?P\d+)\}/', $content, $match)) { return (int) $match['number']; } } return 0; } /** * Delete images. * * @param array $data * * @return json */ public function deleteImage($data) { $errors = []; $response = ['status' => 0, 'errors' => &$errors]; $name = $data['filename']; $path = $data['path']; $thumb_filename = $data['thumb_filename']; $thumb_path = $data['thumb_path']; if (file_exists($path)) { if (!unlink($path)) { $errors[] = sprintf($this->l('You cannot delete the image "%s", please check the CHMOD !'), $name); } } else { $errors[] = sprintf($this->l('The image thumbnail "%s" file not exists!'), $name); } if (file_exists($thumb_path)) { if (!unlink($thumb_path)) { $errors[] = sprintf($this->l('You cannot delete the image thumbnail "%s", please check the CHMOD !'), $thumb_filename); } } else { $errors[] = sprintf($this->l('The image thumbnail "%s" file not exists!'), $thumb_filename); } if (empty($errors)) { $response['status'] = 1; } return Tools::jsonEncode($response); } /** * Get send history. * * @return json */ public function getSendHistory() { $sql = 'SELECT s.`id_newsletter_pro_send`, s.`id_newsletter_pro_tpl_history`, s.`active`, s.`emails_count`, s.`emails_success`, s.`emails_error`, s.`emails_completed`, s.`error_msg`, s.`date`, s.`template`, ss.`id_newsletter_pro_send_step`, h.`clicks`, h.`opened`, h.`unsubscribed`, h.`fwd_unsubscribed`, GROUP_CONCAT(ss.`id_newsletter_pro_send_step`) AS `steps` FROM `'._DB_PREFIX_.'newsletter_pro_send` s LEFT JOIN `'._DB_PREFIX_.'newsletter_pro_send_step` ss ON (ss.`id_newsletter_pro_send` = s.`id_newsletter_pro_send`) LEFT JOIN `'._DB_PREFIX_.'newsletter_pro_tpl_history` h ON (s.`id_newsletter_pro_tpl_history` = h.`id_newsletter_pro_tpl_history`) WHERE s.`active` = 0 GROUP BY s.`id_newsletter_pro_send` ORDER BY s.`date` DESC;'; if ($histories = Db::getInstance()->executeS($sql)) { foreach ($histories as &$history) { $error_msg_db = Db::getInstance()->executeS(' SELECT `error_msg` FROM `'._DB_PREFIX_.'newsletter_pro_send_step` WHERE `id_newsletter_pro_send` = '.(int) $history['id_newsletter_pro_send'].' '); $error_msg = []; foreach ($error_msg_db as $value) { $value['error_msg'] = trim($value['error_msg']); if (!empty($value['error_msg'])) { $em = unserialize($value['error_msg']); foreach ($em as $val) { foreach (array_keys($val) as $error) { $error_msg[] = $error; } } } } $history['date'] = date('Y-m-d', strtotime($history['date'])); $history['error_msg'] = array_unique($error_msg); $history['template'] = Tools::ucfirst(pathinfo($history['template'], PATHINFO_FILENAME)); } return Tools::jsonEncode($histories); } else { return Tools::jsonEncode([]); } } /** * Get forwarders list. * * @return json */ public function getForwardList() { $sql = 'SELECT `id_newsletter_pro_forward`, `from`, `to`, `date_add`, COUNT(*) as `count` FROM `'._DB_PREFIX_.'newsletter_pro_forward` GROUP BY `from`'; if ($result = Db::getInstance()->executeS($sql)) { return Tools::jsonEncode($result); } else { return Tools::jsonEncode([]); } } /** * Search forwarder. * * @param string $value * * @return json */ public function searchForwarder($value) { $sql = 'SELECT `id_newsletter_pro_forward`, `from`, `to`, `date_add`, COUNT(*) as `count` FROM `'._DB_PREFIX_.'newsletter_pro_forward` WHERE `from` LIKE "%'.pSQL($value).'%" OR `to` LIKE "%'.pSQL($value).'%" GROUP BY `from`'; if ($result = Db::getInstance()->executeS($sql)) { return Tools::jsonEncode($result); } else { return Tools::jsonEncode([]); } } /** * Sleep newsletter. * * @param int $seconds * * @return json */ public function sleepNewsletter($seconds) { if (pqnp_config('SLEEP', $seconds)) { return Tools::jsonEncode(['status' => true, 'msg' => $this->l('Updated')]); } else { return Tools::jsonEncode(['status' => false, 'msg' => $this->l('Update error')]); } } /** * Verify template filename. * * @param string $name * * @return bool */ public function verifyName($name) { // frech characters àâçéèêëîïôûùüÿñæœ // turkey characters İıÖöÜüÇçĞğŞş₤ if ('' == $name) { return $this->l('Please insert the name'); } elseif (Tools::strlen($name) < 4) { return $this->l('Name must contain at least 4 characters'); } elseif (!preg_match('/^[a-zA-Z0-9\-_\.\%àâçéèêëîïôûùüÿñæœčšđžćČŠĐĆŽİıÖöÜüÇçĞğŞş₤]+$/i', $name)) { return $this->l('Name contain illegal characters'); } elseif (preg_match('/\.html$/', $name)) { return $this->l('Do not use .html extension'); } return true; } /** * Show newsletter help template. * * @return string */ public function showNewsletterHelp() { include_once dirname(__FILE__).'/classes/NewsletterProExtendTemplateVars.php'; $external_vars = NewsletterProExtendTemplateVars::$external_vars; $help_vars = []; foreach ($external_vars as $path => $to_load) { if ($to_load) { $path = dirname(__FILE__).'/'.$path; $variable_name = pathinfo($path, PATHINFO_FILENAME); $help = pqnp_template_path($this->dir_location.'views/templates/admin/variables_help/'.$variable_name.'.tpl'); if (file_exists($help) && is_file($help)) { $help_vars[] = $this->context->smarty->fetch($help); } } } $this->context->smarty->assign('help_vars', $help_vars); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/help_newsletter.tpl')); } /** * Show product help template. * * @return string */ public function showProductHelp() { $languages = Language::getLanguages(false); $languages_iso = []; foreach ($languages as $language) { $languages_iso[$language['id_lang']] = $language['iso_code']; } $currencies = NewsletterPro::getCurrenciesByIdShop($this->context->shop->id); $currencies_iso = []; foreach ($currencies as $currency) { $currencies_iso[$currency['id_currency']] = $currency['iso_code']; } $this->context->smarty->assign([ 'lang_iso' => trim(implode(', ', $languages_iso)), 'currencies_iso' => trim(implode(', ', $currencies_iso)), ]); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/help_product.tpl')); } /** * Get currencies by is shop. * * @param int $id_shop * * @return array */ public static function getCurrenciesByIdShop($id_shop = 0) { // if there is a problem with the currencies, uncomment this line // return Currency::getCurrencies(false, true); $context = Context::getContext(); if (method_exists('Currency', 'getCurrenciesByIdShop')) { return Currency::getCurrenciesByIdShop($context->shop->id); } else { return Db::getInstance()->executeS(' SELECT * FROM `'._DB_PREFIX_.'currency` c LEFT JOIN `'._DB_PREFIX_.'currency_shop` cs ON (cs.`id_currency` = c.`id_currency`) '.($id_shop ? ' WHERE cs.`id_shop` = '.(int) $id_shop : '').' ORDER BY `name` ASC '); } } /** * Search emails. * * @return json */ public function searchEmails() { $query = Tools::getValue('search_emails'); $sql = 'SELECT c.`id_customer`, c.`firstname`, c.`lastname`, c.`email`, gl.`name` AS `group_name`, l.`name` AS `lang_name`, s.`name` AS `shop_name` FROM `'._DB_PREFIX_.'customer` c LEFT JOIN `'._DB_PREFIX_.'group_lang` gl ON ( gl.`id_group` = c.`id_default_group` ) AND gl.`id_lang` = '.(int) $this->context->language->id.' LEFT JOIN `'._DB_PREFIX_.'lang` l ON ( l.`id_lang` = c.`id_lang` ) LEFT JOIN `'._DB_PREFIX_.'shop` s ON ( s.`id_shop` = c.`id_shop` ) WHERE c.`firstname` LIKE "%'.pSQL($query).'%" OR c.`lastname` LIKE "%'.pSQL($query).'%" OR c.`email` LIKE "%'.pSQL($query).'%" OR gl.`name` LIKE "%'.pSQL($query).'%" OR l.`name` LIKE "%'.pSQL($query).'%" OR s.`name` LIKE "%'.pSQL($query).'%"'; $result = Db::getInstance()->executeS($sql); $costomers_id = []; if (!empty($result)) { foreach ($result as $customer) { $costomers_id[] = $customer['id_customer']; } } return Tools::jsonEncode($costomers_id); } /** * Display produt image. * * @param bool $boolean * * @return json */ public function displayProductImage($boolean) { $data = []; $boolean = ('true' == $boolean) ? 1 : 0; if (pqnp_config('DISPLAY_PRODUCT_IMAGE', $boolean)) { $data['status'] = true; $data['msg'] = ''; } else { $data['status'] = false; $data['msg'] = $this->l('The field cannot be updated'); } return Tools::jsonEncode($data); } /** * Clear prestashop cache. * * @return bool */ public function clearCache() { if (method_exists('Tools', 'clearSmartyCache')) { if (Version::isLower('1.6')) { if (method_exists('Tools', 'clearSmartyCache')) { Tools::clearSmartyCache(); } if (method_exists('Media', 'clearCache')) { Media::clearCache(); } $autoload = Autoload::getInstance(); if (method_exists($autoload, 'generateIndex')) { $autoload->generateIndex(); } } else { if (method_exists('Tools', 'clearSmartyCache')) { Tools::clearSmartyCache(); } if (method_exists('Tools', 'clearXMLCache')) { Tools::clearXMLCache(); } if (method_exists('Media', 'clearCache')) { Media::clearCache(); } if (method_exists('Tools', 'generateIndex')) { Tools::generateIndex(); } } return true; } return false; } /** * Clear newsletter history. * * @return json */ public function clearHistory() { $response = ['status' => false]; $sql = 'SELECT `id_newsletter_pro_tpl_history` AS `id` FROM `'._DB_PREFIX_.'newsletter_pro_send` WHERE `id_newsletter_pro_tpl_history` > 0;'; if ($ids = Db::getInstance()->executeS($sql)) { foreach ($ids as $id) { Db::getInstance()->delete('newsletter_pro_tpl_history', '`id_newsletter_pro_tpl_history`='.(int) $id['id']); Db::getInstance()->delete('newsletter_pro_unsibscribed', '`id_newsletter_pro_tpl_history`='.(int) $id['id']); } } if (Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'newsletter_pro_send` WHERE 1')) { $response['status'] = true; } else { $response['status'] = false; } return Tools::jsonEncode($response); } /** * Save smtp configuration. * * @param array $data * * @return json */ public function saveSMTP($data) { $response = ['status' => false, 'errors' => []]; if ((int) pqnp_ini_config('demo_mode')) { $name = Tools::strtolower(trim($data['name'])); $name_demo = Tools::strtolower(pqnp_demo_mode('demo_freeze_smtp_name')); if ($name == $name_demo) { $response['status'] = false; $response['errors'][] = $this->l('This is a demo, you cannot override this SMTP connection.'); return Tools::jsonEncode($response); } } if (!trim($data['name'])) { $this->_errors[] = $this->l('The SMTP "Name" field is required.'); } if (!trim($data['from_email'])) { $this->_errors[] = $this->l('The "From email" field is required.'); } else { $sql = 'SELECT `name` FROM `'._DB_PREFIX_.'newsletter_pro_smtp` WHERE `id_newsletter_pro_smtp`='.(int) $data['id_newsletter_pro_smtp'].''; $name = Db::getInstance()->getValue($sql); if ($name !== $data['name']) { $sql = 'SELECT count(*) FROM `'._DB_PREFIX_.'newsletter_pro_smtp` WHERE `name` = "'.pSQL($data['name']).'" AND `id_newsletter_pro_smtp`!='.(int) $data['id_newsletter_pro_smtp'].''; if (Db::getInstance()->getValue($sql)) { $this->_errors[] = $this->l('Duplicate SMTP name.'); } } } if (empty($this->_errors)) { $mail = new NewsletterProMail((int) $data['id_newsletter_pro_smtp']); $mail->name = $data['name']; $mail->method = $data['method']; $mail->from_name = $data['from_name']; $mail->from_email = $data['from_email']; $mail->reply_to = $data['reply_to']; $mail->domain = $data['domain']; $mail->server = $data['server']; $mail->user = $data['user']; $mail->passwd = ('' == trim($data['passwd']) ? $mail->passwd : $data['passwd']); $mail->encryption = Tools::strtolower($data['encryption']); $mail->port = $data['port']; $mail->list_unsubscribe_active = (int) $data['list_unsubscribe_active']; $mail->list_unsubscribe_email = trim($data['list_unsubscribe_email']); if (Validate::isLoadedObject($mail) && $mail->update() && pqnp_config('SMTP', $mail->id)) { $response['obj'] = $data; $response['status'] = true; } else { $response['status'] = false; } } else { $response['errors'] = $this->_errors; $response['status'] = false; } return Tools::jsonEncode($response); } /** * Delete smtp configuration. * * @param int $id * * @return json */ public function deleteSMTP($id) { $response = NewsletterProAjaxResponse::newInstance([ 'status' => false, 'msg' => '', 'count' => 0, ]); try { $sql = 'SELECT count(*) FROM `'._DB_PREFIX_.'newsletter_pro_task` WHERE `id_newsletter_pro_smtp`='.(int) $id.' AND `done` = 0;'; if ($count = Db::getInstance()->getValue($sql)) { $response->addError($this->l('The SMTP cannot be deleted because is used in').' '.$count.' '.$this->l('tasks. Change the tasks SMTP or delete them.')); $response->set('count', $count); } else { $mail = NewsletterProMail::newInstance((int) $id); if (!Validate::isLoadedObject($mail)) { return $response->addError(sprintf($this->l('Invalid connection id "%s"'), $id))->display(); } if ((int) pqnp_ini_config('demo_mode')) { $demo_return = NewsletterProDemoMode::deleteSMTP($mail->name); if ($demo_return) { return $demo_return; } } $error_msg = $this->l('An error occurred when deleting the connection.'); if (!$mail->delete()) { $response->addError($error_msg); } else { if (!NewsletterProSendConnection::deleteBySmtpId((int) $id)) { $response->addError($error_msg); } } if (!$this->countSMTP()) { pqnp_config('SMTP', '0'); } $response->set('status', true); $response->set('count', Db::getInstance()->Affected_Rows()); } } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } /** * Count smtp connections. * * @return int */ public function countSMTP() { $sql = 'SELECT count(*) FROM `'._DB_PREFIX_.'newsletter_pro_smtp` WHERE 1'; return Db::getInstance()->getValue($sql); } /** * Add a new smtp connection. * * @param array $data */ public function addSMTP($data) { $response = ['status' => false, 'errors' => []]; if (!trim($data['name'])) { $this->_errors[] = $this->l('The SMTP "Name" is required.'); } if (!trim($data['from_email'])) { $this->_errors[] = $this->l('The "From email" field is required.'); } else { $sql = 'SELECT count(*) FROM `'._DB_PREFIX_.'newsletter_pro_smtp` WHERE `name` = "'.pSQL($data['name']).'"'; if (Db::getInstance()->getValue($sql)) { $this->_errors[] = $this->l('Duplicate name.'); } } if (!trim($data['user']) && NewsletterProMail::METHOD_SMTP == (int) $data['method']) { $this->_errors[] = $this->l('The "SMTP user" is required.'); } if (!$this->_errors) { $mail = new NewsletterProMail(); $mail->name = trim($data['name']); $mail->method = (int) $data['method']; $mail->from_name = trim($data['from_name']); $mail->from_email = trim($data['from_email']); $mail->reply_to = trim($data['reply_to']); $mail->domain = trim($data['domain']); $mail->server = trim($data['server']); $mail->user = trim($data['user']); $mail->passwd = trim($data['passwd']); $mail->encryption = Tools::strtolower($data['encryption']); $mail->port = $data['port']; $mail->list_unsubscribe_active = (int) $data['list_unsubscribe_active']; $mail->list_unsubscribe_email = trim($data['list_unsubscribe_email']); if ($mail->add()) { if ($mail->id && pqnp_config('SMTP', $mail->id)) { $sql = 'SELECT * FROM `'._DB_PREFIX_.'newsletter_pro_smtp` WHERE `id_newsletter_pro_smtp`='.(int) $mail->id.''; $last_row = Db::getInstance()->getRow($sql); $response['obj'] = $last_row; $response['status'] = true; } else { $response['status'] = false; } } else { $response['status'] = false; } } else { $response['errors'] = $this->_errors; $response['status'] = false; } return Tools::jsonEncode($response); } /** * Change smtp. * * @param int $id * * @return json */ public function changeSMTP($id) { $response = ['status' => false, 'msg' => '']; if (pqnp_config('SMTP', $id)) { $response['status'] = true; } else { $response['msg'] = $this->l('The SMTP cannot be changed.'); $response['status'] = false; } return Tools::jsonEncode($response); } /** * Change newsletter pro smtp active configuration. * * @param bool $bool * * @return json */ public function smtpActive($bool) { $bool = 'true' == $bool ? 1 : 0; $response = ['status' => false]; if (pqnp_config('SMTP_ACTIVE', $bool)) { $response['status'] = true; } else { $response['status'] = false; } return Tools::jsonEncode($response); } /** * Replace admin link. * * @param string $path * * @return string */ public static function relplaceAdminLink($path) { if (self::REPLACE_ADMIN_PATH) { $module = NewsletterPro::getInstance(); if (!empty($module->admin_name)) { $name = str_replace($module->admin_name.'/', '', $path); return $name; } else { return $path; } } return $path; } /** * Empty the personal list with email addresses. * * @return json */ public function emptyAddedEmails() { $response = ['status' => false]; if (Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'newsletter_pro_email` WHERE 1')) { $response['status'] = true; } return Tools::jsonEncode($response); } /** * Update the google analytics id. * * @param int $g_analytics_id * * @return json */ public function updateGAnalyticsID($g_analytics_id) { $response = ['status' => false]; if (pqnp_config('GOOGLE_ANALYTICS_ID', $g_analytics_id)) { $response['status'] = true; } return Tools::jsonEncode($response); } /** * Activate google analytics configuration. * * @param bool $bool * * @return json */ public function activeGAnalytics($bool) { $bool = 'true' == $bool ? 1 : 0; $response = ['status' => false]; if (pqnp_config('GOOGLE_ANALYTICS_ACTIVE', $bool)) { $response['status'] = true; } return Tools::jsonEncode($response); } /** * Activate universal analytics option. * * @param bool $bool * * @return json */ public function universalAnaliytics($bool) { $bool = 'true' == $bool ? 1 : 0; $response = ['status' => false]; if (pqnp_config('GOOGLE_UNIVERSAL_ANALYTICS_ACTIVE', $bool)) { $response['status'] = true; } return Tools::jsonEncode($response); } /** * Activate google analytics campaign. * * @param bool $bool * * @return json */ public function activeCampaign($bool) { $ga_info = $this->getGAnalyticsModuleInfo(); if ($ga_info['isInstalled']) { $header_hook = false; foreach ($ga_info['hooks'] as $hook) { if (('displayHeader' == $hook['name'] || 'header' == $hook['name']) && $hook['isRegistred']) { $header_hook = $hook; break; } } if ($header_hook) { $np_position = (int) $this->getModulePosition($this, $header_hook['id_hook']); $ga_position = (int) $header_hook['position']; if ($ga_position <= $np_position) { $this->updatePosition($header_hook['id_hook'], 0, $ga_position); } } } $bool = 'true' == $bool ? 1 : 0; $response = ['status' => false]; if (pqnp_config('CAMPAIGN_ACTIVE', $bool)) { $response['status'] = true; } return Tools::jsonEncode($response); } /** * Create image thumbnail. * * @param string $path * @param string $temp_path * @param string $name * @param string $thumb_height * * @return int */ public function createImageThumb($path, $temp_path, $name, $thumb_height) { list(, , $image_type) = getimagesize($temp_path); $new_image = null; if (IMAGETYPE_JPEG == $image_type) { $new_image = imagecreatefromjpeg($temp_path); } elseif (IMAGETYPE_GIF == $image_type) { $new_image = imagecreatefromgif($temp_path); } elseif (IMAGETYPE_PNG == $image_type) { $new_image = imagecreatefrompng($temp_path); } $get_width = imagesx($new_image); $get_height = imagesy($new_image); $ratio = $thumb_height / $get_height; $thumb_width = $get_width * $ratio; $thumb = imagecreatetruecolor($thumb_width, $thumb_height); imagecopyresampled($thumb, $new_image, 0, 0, 0, 0, $thumb_width, $thumb_height, $get_width, $get_height); $thumb_name = 'thumb_'.$name; $thumb_path = $path.'thumb/'.$thumb_name; if (IMAGETYPE_JPEG == $image_type) { imagejpeg($thumb, $thumb_path, 100); } elseif (IMAGETYPE_GIF == $image_type) { imagegif($thumb, $thumb_path); } elseif (IMAGETYPE_PNG == $image_type) { imagepng($thumb, $thumb_path); } } /** * Upload image. * * @param array $image * @param int $img_width * * @return json */ public function uploadImage($image, $img_width) { $errors = []; $response = ['status' => false, 'errors' => &$errors]; if (!empty($image)) { $path = $this->dir_location.'images/'; $validate_file = $this->verifyFileErros($image); if (true === $validate_file) { if (preg_match('/\.jpg|\.jpeg|\.gif|\.png$/i', $image['name'])) { if (!file_exists($path)) { $errors[] = $this->l('Images path does not exist'); } else { $image_ext = pathinfo($image['name'], PATHINFO_EXTENSION); $name = uniqid().'.'.$image_ext; $name = str_replace(' ', '-', $name); $temp_path = $image['tmp_name']; $full_path = $path.$name; if ((int) $img_width > 0 && Tools::strlen((string) $img_width) <= 4) { list(, , $image_type) = getimagesize($temp_path); $new_image = null; if (IMAGETYPE_JPEG == $image_type) { $new_image = imagecreatefromjpeg($temp_path); } elseif (IMAGETYPE_GIF == $image_type) { $new_image = imagecreatefromgif($temp_path); } elseif (IMAGETYPE_PNG == $image_type) { $new_image = imagecreatefrompng($temp_path); } $get_width = imagesx($new_image); $get_height = imagesy($new_image); $ratio = $img_width / $get_width; $img_height = $get_height * $ratio; $img = imagecreatetruecolor($img_width, $img_height); imagecopyresampled($img, $new_image, 0, 0, 0, 0, $img_width, $img_height, $get_width, $get_height); $img_path = $path.$name; if (IMAGETYPE_JPEG == $image_type) { imagejpeg($img, $img_path, 100); } elseif (IMAGETYPE_GIF == $image_type) { imagegif($img, $img_path); } elseif (IMAGETYPE_PNG == $image_type) { imagepng($img, $img_path); } $this->createImageThumb($path, $temp_path, $name, 50); $response['status'] = true; } else { if (move_uploaded_file($temp_path, $full_path)) { $this->createImageThumb($path, $full_path, $name, 50); $response['status'] = true; } else { $errors[] = $this->l('Image was not uploaded, please check the CHMOD.'); } } } } else { $errors[] = $this->l('The file extension is not allowed'); } } else { $errors[] = $validate_file; } } else { $errors[] = $this->l('No file was uploaded'); } return Tools::jsonEncode($response); } /** * Upload a csv file. * * @param string $file * * @return json */ public function uploadCSV($file) { $response = ['status' => false, 'msg' => '', 'data' => []]; $validate = $this->verifyFileErros($file); if (true === $validate) { $csv_path = 'csv/import/'; $path = $this->dir_location.$csv_path; $name = $file['name']; $tmp_name = $file['tmp_name']; $extension = pathinfo($name, PATHINFO_EXTENSION); if (preg_match('/csv/i', $extension)) { $unique_name = $this->uniqueName($name); $full_path = $path.$unique_name; if (file_exists($path) && move_uploaded_file($tmp_name, $full_path)) { $response['status'] = true; $response['data']['name'] = $unique_name; $response['data']['uri'] = $this->uri_location.$unique_name; $response['data']['url'] = $this->url_location.$unique_name; } else { $response['msg'] = $this->l('The file cannot be uploaded.'); } } else { $response['msg'] = $this->l('The file extension is not allowed.'); } } else { $response['msg'] = $validate; } return Tools::jsonEncode($response); } /** * Get an unique name. * * @param string $name * * @return string */ public function uniqueName($name) { $name = preg_replace('/[\s]/', '_', trim($name)); return uniqid().'_'.$name; } /** * Verify upload file errors. * * @param string $file * * @return string */ public function verifyFileErros($file) { $message = ''; if (UPLOAD_ERR_OK == $file['error'] && 0 != $file['size']) { return true; } elseif (UPLOAD_ERR_INI_SIZE == $file['error']) { $message = $this->l('The uploaded file exceeds the upload_max_filesize directive in php.ini'); } elseif (UPLOAD_ERR_PARTIAL == $file['error']) { $message = $this->l('The uploaded file was only partially uploaded'); } elseif (UPLOAD_ERR_NO_FILE == $file['error']) { $message = $this->l('No file was uploaded'); } elseif (UPLOAD_ERR_NO_TMP_DIR == $file['error']) { $message = $this->l('Missing a temporary folder'); } elseif (UPLOAD_ERR_CANT_WRITE == $file['error']) { $message = $this->l('Failed to write file to disk'); } elseif (UPLOAD_ERR_EXTENSION == $file['error']) { $message = $this->l('A PHP extension stopped the file upload'); } else { $message = $this->l('File error'); } return $message; } /** * Delete the csv file by name. * * @param string $name * * @return json */ public function deleteCSVByName($name) { $response = ['status' => false, 'msg' => '']; $path = $this->dir_location.'csv/import/'.$name; if (file_exists($path) && unlink($path)) { $response['status'] = true; } else { $response['msg'] = $this->l('The file cannot be deleted.'); } return Tools::jsonEncode($response); } /** * Get the csv file line info. * * @param array/null $line * * @return array */ private function getCSVLineInfo($line) { $from = 1; $to = 0; if (isset($line) && is_array($line) && isset($line['from'], $line['to'])) { $from = (int) $line['from'] < 1 ? 1 : (int) $line['from']; $to = (int) $line['to'] < 0 ? 0 : (int) $line['to']; } return [ 'from' => $from, 'to' => $to, ]; } /** * Load a csv file. * * @param string $filename * @param string $delimiter * * @return bool */ public function loadCSV($filename, $delimiter = ',', $line = null) { $full_path = $this->dir_location.'csv/import/'.$filename; $line_info = $this->getCSVLineInfo($line); $from = $line_info['from']; $to = $line_info['to']; if ($data = $this->csvToArray($full_path, $delimiter, $from, $to)) { $db_fields = [ 'email' => 'Email', 'firstname' => 'First Name', 'lastname' => 'Last Name', 'id_lang' => 'Language ID', 'id_shop' => 'Shop ID', 'id_shop_group' => 'Shop Group ID', 'ip_registration_newsletter' => 'Registration IP Address', 'active' => 'Active', ]; $count = null; $header = null; $rows = null; extract($data); $this->context->smarty->assign([ 'count' => $count - 1, 'header' => $header, 'rows' => $rows, 'db_fields' => $db_fields, ]); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/preview_details.tpl')); } return false; } /** * Sanitize utf8. * * @param string $value * * @return string */ public function sanitizeUTF8($value) { return preg_replace('/[^(\x20-\x7F)]*/', '', trim($value, " \t\n\r\0\x0B,;")); } /** * Import emails from a csv file. * * @param string $filename * @param string $delimiter * @param array $fields_get * * @return bool */ public function importCSV($filename, $delimiter = ',', $fields_get = [], $line = null, $filter_name = null) { $line_info = $this->getCSVLineInfo($line); $from = $line_info['from']; $to = $line_info['to']; $full_path = $this->dir_location.'csv/import/'.$filename; if ($data = $this->csvToArray($full_path, $delimiter, $from, $to)) { $count = null; $header = null; $rows = null; extract($data); $fields = []; foreach ($fields_get as $field) { $fields[$field['db_field']] = $field['csv_field']; } if (!isset($fields['email'])) { $this->context->smarty->assign([ 'status' => false, 'msg' => $this->l('You have to set the email field!'), ]); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/import_details.tpl')); } $valid_rows = []; if (!empty($rows)) { foreach ($rows as $key => $row) { if (isset($fields['email'], $row[$fields['email']]) && Validate::isEmail($this->sanitizeUTF8($row[$fields['email']]))) { $valid_rows[$key]['email'] = $this->sanitizeUTF8($row[$fields['email']]); $valid_rows[$key]['date_add'] = date('Y:m:d H:i:s'); $valid_rows[$key]['firstname'] = null; $valid_rows[$key]['lastname'] = null; $valid_rows[$key]['id_lang'] = (int) $this->context->language->id; $valid_rows[$key]['id_shop'] = (int) $this->context->shop->id; $valid_rows[$key]['id_shop_group'] = (int) $this->context->shop->id_shop_group; $valid_rows[$key]['ip_registration_newsletter'] = null; $valid_rows[$key]['active'] = 1; if (isset($fields['firstname'], $row[$fields['firstname']])) { $valid_rows[$key]['firstname'] = $row[$fields['firstname']]; } if (isset($fields['lastname'], $row[$fields['lastname']])) { $valid_rows[$key]['lastname'] = $row[$fields['lastname']]; } if (isset($fields['id_lang'], $row[$fields['id_lang']]) && 0 != $row[$fields['id_lang']]) { $valid_rows[$key]['id_lang'] = $row[$fields['id_lang']]; } if (isset($fields['id_shop'], $row[$fields['id_shop']]) && 0 != $row[$fields['id_shop']]) { $valid_rows[$key]['id_shop'] = $row[$fields['id_shop']]; } if (isset($fields['id_shop_group'], $row[$fields['id_shop_group']]) && 0 != $row[$fields['id_shop_group']]) { $valid_rows[$key]['id_shop_group'] = $row[$fields['id_shop_group']]; } if (isset($fields['ip_registration_newsletter'], $row[$fields['ip_registration_newsletter']])) { $valid_rows[$key]['ip_registration_newsletter'] = $row[$fields['ip_registration_newsletter']]; } if (isset($fields['active'], $row[$fields['active']])) { $valid_rows[$key]['active'] = $row[$fields['active']]; } } } } if (empty($valid_rows)) { $this->context->smarty->assign([ 'status' => false, 'msg' => $this->l('The column with emails was not found!'), ]); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/import_details.tpl')); } $newsletter_pro_email = Db::getInstance()->executeS('SELECT `email`, `active` FROM `'._DB_PREFIX_.'newsletter_pro_email`'); if (self::CSV_IMPORT_STRICT) { $newsletter = []; if (Db::getInstance()->getValue(" SELECT COUNT(*) AS `count` FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '"._DB_NAME_."' AND TABLE_NAME = '"._DB_PREFIX_."newsletter' ")) { $newsletter = Db::getInstance()->executeS('SELECT `email`, `active` FROM `'._DB_PREFIX_.'newsletter`'); } } if (self::CSV_IMPORT_STRICT) { $customer = Db::getInstance()->executeS('SELECT `email`, `newsletter` AS `active` FROM `'._DB_PREFIX_.'customer` WHERE `newsletter` = 1'); } else { $customer = []; } $emails_db = array_merge($newsletter, $customer); foreach ($emails_db as $key => $email) { $emails_db[$key] = trim($email['email']); } foreach ($newsletter_pro_email as $key => $email) { $newsletter_pro_email[$key] = trim($email['email']); } foreach ($valid_rows as $key => $row) { $row['email'] = trim($row['email']); if (in_array($row['email'], $emails_db)) { unset($valid_rows[$key]); } elseif (in_array($row['email'], $newsletter_pro_email)) { $update_sql = 'UPDATE `'._DB_PREFIX_.'newsletter_pro_email` SET '; $update_sql .= '`firstname` = '.(null == $row['firstname'] ? 'NULL' : '"'.pSQL($row['firstname']).'"').', '; $update_sql .= '`lastname` = '.(null == $row['lastname'] ? 'NULL' : '"'.pSQL($row['lastname']).'"').', '; $update_sql .= '`filter_name` = '.(!isset($filter_name) ? 'NULL' : '"'.pSQL(trim($filter_name)).'"').', '; $update_sql .= '`id_lang` = '.(int) $row['id_lang'].', '; $update_sql .= '`id_shop` = '.(int) $row['id_shop'].', '; $update_sql .= '`id_shop_group` = '.(int) $row['id_shop_group'].', '; $update_sql .= '`ip_registration_newsletter` = '. (null == $row['ip_registration_newsletter'] ? 'NULL' : '"'.(int) $row['ip_registration_newsletter'].'"'). ', '; $update_sql .= '`date_add` = "'.pSQL($row['date_add']).'", '; $update_sql .= '`active` = '.(int) $row['active']; $update_sql .= ' WHERE `email` = "'.pSQL($row['email']).'" ;'; Db::getInstance()->execute($update_sql); } elseif (Validate::isEmail($row['email'])) { $sql = 'INSERT INTO `'._DB_PREFIX_.'newsletter_pro_email` (`email`, `firstname`, `lastname`,`filter_name` ,`id_lang`, `id_shop`, `id_shop_group`, `ip_registration_newsletter`, `active`, `date_add`) VALUES '; $sql .= '('; $sql .= '"'.$row['email'].'", '; $sql .= (null == $row['firstname'] ? 'NULL,' : '"'.pSQL($row['firstname']).'", '); $sql .= (null == $row['lastname'] ? 'NULL,' : '"'.pSQL($row['lastname']).'", '); $sql .= (!isset($filter_name) ? 'NULL,' : '"'.pSQL(trim($filter_name)).'", '); $sql .= (int) $row['id_lang'].', '; $sql .= (int) $row['id_shop'].', '; $sql .= (int) $row['id_shop_group'].', '; $sql .= (null == $row['ip_registration_newsletter'] ? 'NULL,' : '"'.(int) $row['ip_registration_newsletter'].'", '); $sql .= (int) $row['active'].', '; $sql .= '"'.pSQL($row['date_add']).'" '; $sql .= ') '; $sql = Tools::substr($sql, 0, -1).';'; Db::getInstance()->execute($sql); } // Fix rows foreach (array_keys($row) as $k) { if (!array_key_exists($k, $fields)) { unset($valid_rows[$key][$k]); } } } if (!empty($valid_rows)) { foreach ($header as $key => $head) { if (!in_array($head, $fields)) { unset($header[$key]); } } // sort items for a proper display $sorted_valid_rows = []; foreach ($valid_rows as $key => $value) { $sorted_value = []; foreach (array_keys($fields) as $fk) { if (array_key_exists($fk, $value)) { $sorted_value[$fk] = $value[$fk]; } } $sorted_valid_rows[$key] = $sorted_value; } $this->context->smarty->assign([ 'count' => $count - 1, 'header' => $header, 'rows' => $sorted_valid_rows, 'valid' => count($valid_rows), ]); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/import_details.tpl')); } else { $this->context->smarty->assign([ 'status' => false, 'msg' => $this->l('No emails imported. Only those emails that are not duplicate can be imported!'), ]); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/import_details.tpl')); } } return false; } /** * Convert csv file to array. * * @param string $filename * @param string $delimiter * * @return array/boolean */ public function csvToArray($filename = '', $delimiter = ',', $from = 2, $to = 0, $has_header = true) { ini_set('auto_detect_line_endings', true); if (!file_exists($filename) || !is_readable($filename)) { return false; } if ($has_header) { $from = $from - 1; $to = $to - 1; } $diff = $to - $from; $current_row_count = 0; $rows = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); foreach ($rows as $key => $value) { // this solve the russian characters plobelm // $value = utf8_encode($value); $rows[$key] = mb_convert_encoding($rows[$key], 'UTF-8', mb_detect_encoding($rows[$key], 'UTF-8, ISO-8859-1, ISO-8859-15', true)); } foreach ($rows as $key => $line) { if (preg_match('/^(,+|\s+?|)$/', $line)) { unset($rows[$key]); } } if (!empty($rows)) { $regex = '/'.$delimiter.'(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/'; $header = null; if ($has_header) { $row_head = rtrim($rows[0], ';, '); $header = preg_split($regex, $row_head, -1, PREG_SPLIT_DELIM_CAPTURE); unset($rows[0]); } $content = []; foreach ($rows as $key => $row) { ++$current_row_count; $row = rtrim($row, ';, '); $row = preg_split($regex, $row, -1, PREG_SPLIT_DELIM_CAPTURE); foreach ($row as $k => $v) { if (isset($header[$k])) { $header[$k] = trim($header[$k]); if (isset($v[0], $v[Tools::strlen($v) - 1]) && '"' == $v[0] && '"' == $v[Tools::strlen($v) - 1]) { $v = Tools::substr($v, 1, -1); } $row[$header[$k]] = str_replace('""', '"', $v); unset($row[$k]); } } if ($diff > 0 && ($current_row_count >= $from && $current_row_count < $to)) { // this will import the renge records $content[$key + 1] = $row; } elseif ($diff <= 0) { // this case will import all the records $content[$key + 1] = $row; } elseif ($current_row_count >= $to) { // this care will break the loop if all the required records has been imported break; } } return ['count' => count($content) + 1, 'header' => $header, 'rows' => $content]; } else { return false; } } /** * Save newsletter campaign parameters. * * @param array $params * * @return bool */ public function saveParameteres($params) { if (Configuration::updateValue('NEWSLETTER_PRO_CAMPAIGN', $params, false, 0, 0)) { return true; } return false; } /** * Save campaign. * * @param array $data * * @return json */ public function saveCampaign($data) { $response = ['status' => false]; if (count($data) > 1) { $campaign = ['UTM_SOURCE' => preg_replace('/[&?]/', '', $data['utm_source']), 'UTM_MEDIUM' => preg_replace('/[&?]/', '', $data['utm_medium']), 'UTM_CAMPAIGN' => preg_replace('/[&?]/', '', $data['utm_campaign']), 'UTM_CONTENT' => preg_replace('/[&?]/', '', $data['utm_content']), ]; if (pqnp_config('CAMPAIGN', $campaign) && $this->saveParameteres($data['params'])) { $response['status'] = true; } } else { $response['status'] = null; } return Tools::jsonEncode($response); } /** * Setup the google analytics campaign default parameters. * * @return json */ public function makeDefaultParameteres() { $response = ['status' => false, 'params' => '', 'campaign' => $this->default_campaign_params]; if (pqnp_config('CAMPAIGN', $this->default_campaign_params) && $this->saveParameteres('')) { $response['status'] = true; } return Tools::jsonEncode($response); } /** * Get task template. * * @return string */ public function getTaskTemplate() { $tpl = pqnp_template_path($this->dir_location.'views/templates/admin/task/template.tpl'); return $this->context->smarty->fetch($tpl); } /** * Transform a date format to a jQuery date format. * * @param string $date_string * * @return string */ public function dateToJQuery($date_string) { $pattern = ['d', 'j', 'l', 'z', 'F', 'M', 'n', 'm', 'Y', 'y']; $replace = [ 'dd', 'd', 'DD', 'o', 'MM', 'M', 'm', 'mm', 'yy', 'y', ]; foreach ($pattern as &$p) { $p = '/'.$p.'/'; } return preg_replace($pattern, $replace, $date_string); } /** * Sort array elements by date. * * @param array $a * @param array $b * * @return array */ private static function sortByDate($a, $b) { return strtotime($a['date']) < strtotime($b['date']); } /** * Get product templates. * * @return json */ public function getProductTemplates() { $list = []; $path = $this->dir_location.'mail_templates/product/'; $result = NewsletterProTools::getDirectoryIterator($path, '/^.+\.html$/i'); $id = 1; $i = 0; foreach ($result as $file) { $list[$i]['id'] = $id; $list[$i]['name'] = Tools::ucfirst(str_replace('_', ' ', pathinfo($file->getFilename(), PATHINFO_FILENAME))); $list[$i]['filename'] = $file->getFilename(); $list[$i]['path'] = $file->getPathName(); $list[$i]['date'] = date($this->context->language->date_format_full, filemtime($file->getPathName())); $list[$i]['selected'] = false; $list[$i]['info'] = []; if (is_readable($file->getPathName())) { $content = Tools::file_get_contents($file->getPathName()); if (preg_match('/[\s\S]*?[\s\S]*?/', $content, $match)) { $header = $match[1]; if (preg_match('/info\s+?=\s+?(.*);/', $header, $m)) { $list[$i]['info'] = Tools::jsonDecode(trim($m[1]), true); } } } if ($list[$i]['filename'] == pqnp_config('PRODUCT_TEMPLATE')) { $list[$i]['selected'] = true; } ++$id; ++$i; } usort($list, [$this, 'sortByDate']); return Tools::jsonEncode($list); } /** * Get images. * * @return json */ public function getImages() { $list = []; $path = $this->dir_location.'images/'; $result = NewsletterProTools::getDirectoryIterator($path, '/\.jpg|\.jpeg|\.png|\.gif$/i'); $id = 1; $i = 0; foreach ($result as $file) { $list[$i]['id'] = $id; $list[$i]['name'] = Tools::ucfirst(str_replace('_', ' ', pathinfo($file->getFilename(), PATHINFO_FILENAME))); $list[$i]['filename'] = $file->getFilename(); $thumb_filename = 'thumb_'.$file->getFilename(); $list[$i]['thumb_filename'] = $thumb_filename; $list[$i]['path'] = $file->getPathName(); $list[$i]['size'] = $file->getSize(); $image_size = getimagesize($file->getPathName()); $width = $image_size[0]; $height = $image_size[1]; $list[$i]['width'] = $width; $list[$i]['height'] = $height; $list[$i]['link'] = $this->url_location.'images/'.$file->getFilename(); $list[$i]['thumb_link'] = $this->url_location.'images/thumb/'.$thumb_filename; $list[$i]['thumb_path'] = null; $thumb_path = $file->getPath().'/thumb/'.$thumb_filename; $list[$i]['thumb_path'] = null; if (file_exists($thumb_path)) { $list[$i]['thumb_path'] = $thumb_path; } $list[$i]['date'] = date($this->context->language->date_format_full, filemtime($file->getPathName())); ++$id; ++$i; } usort($list, [$this, 'sortByDate']); return Tools::jsonEncode($list); } /** * Get added list. * * @param bool $encode * * @return json/array */ public function getAdded($encode = true) { $sql = $this->getAddedSql(); $userlist = Db::getInstance()->executeS($sql); foreach ($userlist as &$user) { $user['img_path'] = $this->getLangImageById($user['id_lang']); } if ($encode) { return Tools::jsonEncode($userlist); } else { return $userlist; } } /** * Get added list sql. * * @param string $and * @param string $end * * @return string */ private function getAddedSql($and = '', $end = '') { $sql_shops_id = ''; $get_active_shops_id = NewsletterProTools::getActiveShopsId(); $subscribed = (int) pqnp_config('VIEW_ACTIVE_ONLY'); foreach ($get_active_shops_id as $id_shop) { $sql_shops_id .= 'n.`id_shop` = '.(int) $id_shop.(end($get_active_shops_id) == $id_shop ? '' : ' OR '); } $sql = 'SELECT n.`id_newsletter_pro_email`, n.`email`, n.`firstname`, n.`lastname`, n.`id_shop`, n.`id_lang`, n.`date_add` AS `newsletter_date_add`, n.`active`, s.`name` AS `shop_name`, l.`name` AS `language` FROM `'._DB_PREFIX_.'newsletter_pro_email` n LEFT JOIN `'._DB_PREFIX_.'lang` l ON (l.`id_lang` = n.`id_lang`) LEFT JOIN `'._DB_PREFIX_.'shop` s ON (s.`id_shop` = n.`id_shop`) WHERE ( '.$sql_shops_id.' ) '; $sql .= ($subscribed ? ' AND n.`active` = '.(int) $subscribed : ''); if (Tools::strlen(trim($and)) > 0) { $sql .= ' AND '.$and.' '; } $sql .= ' ORDER BY n.`id_newsletter_pro_email` ASC '; if (Tools::strlen(trim($end)) > 0) { $sql .= ' '.$end.' '; } $sql .= ';'; return $sql; } /** * Update added email. * * @param int $id * * @return int */ public function updateAdded($id) { parse_str(Tools::file_get_contents('php://input'), $put); $data = [ 'active' => (int) $put['active'], ]; return (int) (Db::getInstance()->update('newsletter_pro_email', $data, '`id_newsletter_pro_email`= '.(int) $id)); } /** * Delete added. * * @param int $id * * @return int */ public function deleteAdded($id) { return (int) Db::getInstance()->delete('newsletter_pro_email', '`id_newsletter_pro_email`= '.(int) $id, 1); } /** * Delete forwarder to email. * * @param string $email * * @return int */ public function deleteForwardToEmail($email) { return (int) Db::getInstance()->delete('newsletter_pro_forward', '`to`="'.pSQL($email).'"'); } /** * Delete forwarder from email. * * @param email $email * * @return int */ public function deleteForwardFromEmail($email) { return (int) Db::getInstance()->delete('newsletter_pro_forward', '`from`="'.pSQL($email).'"'); } /** * Clear forwarders. * * @return int */ public function clearForwarders() { $sql = 'DELETE FROM `'._DB_PREFIX_.'newsletter_pro_forward` WHERE 1'; return (int) Db::getInstance()->execute($sql); } /** * Search in personal list with email addresses. * * @param string $value * * @return json */ public function searchAdded($value) { $search = ' ( n.`email` LIKE "%'.pSQL($value).'%" OR n.`firstname` LIKE "%'.pSQL($value).'%" OR n.`lastname` LIKE "%'.pSQL($value).'%" )'; $sql = $this->getAddedSql($search); $userlist = Db::getInstance()->executeS($sql); foreach ($userlist as &$user) { $user['img_path'] = $this->getLangImageById($user['id_lang']); } return Tools::jsonEncode($userlist); } /** * Filter added. * * @param array $filters * * @return json */ public function filterAdded($filters) { if (is_array($filters) && !empty($filters)) { if (isset($filters['range_selection']['min'], $filters['range_selection']['max'])) { if ($filters['range_selection']['min'] && $filters['range_selection']['max']) { $range_selection = $filters['range_selection']; } unset($filters['range_selection']); } } if (is_array($filters) && !empty($filters) || isset($range_selection)) { $sql = ''; $filters_count = count($filters); $filters_index = 1; foreach ($filters as $type => $ids) { if ('languages' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' n.id_lang = '.(int) $id.' OR '; } else { $sql .= ' n.id_lang = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } elseif ('shops' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' n.id_shop = '.(int) $id.' OR '; } else { $sql .= ' n.id_shop = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } elseif ('csv_name' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' n.`filter_name` = "'.pSQL($id).'" OR '; } else { $sql .= ' n.`filter_name` = "'.pSQL($id).'" '; } ++$ids_index; } $sql .= ' ) '; } elseif ('subscribed' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' n.active = '.(int) $id.' OR '; } else { $sql .= ' n.active = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } if ($filters_index != $filters_count) { $sql .= ' AND '; } ++$filters_index; } if (true == pqnp_config('VIEW_ACTIVE_ONLY') && $filters_count > 0) { $sql .= ' AND n.`active` = 1'; } elseif (true == pqnp_config('VIEW_ACTIVE_ONLY')) { $sql .= ' n.`active` = 1'; } else { $sql .= ''; } $end = ''; if (isset($range_selection)) { $lim_start = (int) $range_selection['min']; if ($lim_start < 0) { $lim_start = 0; } $lim_end = (int) $range_selection['max'] - (int) $range_selection['min']; if ($lim_end < 0) { $lim_end = 0; } $end = ' LIMIT '.(int) $lim_start.', '.(int) $lim_end.' '; } $sql = $this->getAddedSql($sql, $end); $userlist = Db::getInstance()->executeS($sql); foreach ($userlist as &$user) { $user['img_path'] = $this->getLangImageById($user['id_lang']); } return Tools::jsonEncode($userlist); } return $this->getAdded(); } /** * Create added. * * @param array $post * * @return json */ public function createAdded($post) { $errors = []; $response = ['status' => false, 'errors' => &$errors]; $data = [ 'firstname' => pSQL($post['firstname']), 'lastname' => pSQL($post['lastname']), 'email' => pSQL($post['email']), 'id_shop' => (int) $post['id_shop'], 'id_lang' => (int) $post['id_lang'], 'filter_name' => pSQL(trim($post['filter_name'])), ]; if (!Validate::isName($data['firstname'])) { $errors[] = $this->l('Invalid First Name!'); } if (!Validate::isName($data['lastname'])) { $errors[] = $this->l('Invalid Last Name!'); } if (!Validate::isEmail($data['email'])) { $errors[] = $this->l('Invalid email address!'); } $count_email = 'SELECT count(*) FROM `'._DB_PREFIX_.'newsletter_pro_email` WHERE `email` = "'.pSQL($data['email']).'"'; if (Db::getInstance()->getValue($count_email)) { $errors[] = $this->l('Duplicate email address!'); } if (!Validate::isInt($data['id_shop'])) { $errors[] = $this->l('Invalid shop!'); } if (!Validate::isInt($data['id_lang'])) { $errors[] = $this->l('Invalid language!'); } if (!Validate::isString($data['filter_name'])) { $errors[] = $this->l('CSV Name is invalid.'); } if (empty($errors)) { if (Db::getInstance()->insert('newsletter_pro_email', $data)) { $response['status'] = true; } else { $errors[] = $this->l('The email address cannot be added!'); } } return Tools::jsonEncode($response); } public function getCustomSubscriptionColumns() { $custom_columns = pqnp_config('SHOW_CUSTOM_COLUMNS'); $valid_columns = []; if (!empty($custom_columns)) { foreach ($custom_columns as $name) { if (NewsletterProTools::columnExists('newsletter_pro_subscribers', $name)) { $valid_columns[] = $name; } } } return $valid_columns; } public function getVisitorsNpColumns() { $columns = NewsletterProTools::getDbColumns('newsletter_pro_subscribers'); foreach ($columns as $key => $column) { if ('id_newsletter_pro_subscribers' == $column) { unset($columns[$key]); } } return array_values($columns); } /** * Get newsletter pro visitors subscribed sql. * * @param string $and * @param string $end * * @return string */ private function getVisitorsNPSql($and = '', $end = '') { $sql_shops_id = ''; $get_active_shops_id = NewsletterProTools::getActiveShopsId(); $subscribed = (int) pqnp_config('VIEW_ACTIVE_ONLY'); foreach ($get_active_shops_id as $id_shop) { $sql_shops_id .= 'n.`id_shop` = '.(int) $id_shop.(end($get_active_shops_id) == $id_shop ? '' : ' OR '); } $valid_columns = $this->getCustomSubscriptionColumns(); $valid_columns_sql = ''; foreach ($valid_columns as $name) { $valid_columns_sql .= 'n.`'.$name.'`,'; } $sql = 'SELECT n.`id_newsletter_pro_subscribers`, n.`email`, n.`birthday`, n.`firstname`, n.`lastname`, n.`id_shop`, n.`id_lang`, n.`id_gender`, n.`date_add` AS `newsletter_date_add`, n.`active`, s.`name` AS `shop_name`, '.pSQL($valid_columns_sql).' l.`name` AS `language` FROM `'._DB_PREFIX_.'newsletter_pro_subscribers` n LEFT JOIN `'._DB_PREFIX_.'lang` l ON (l.`id_lang` = n.`id_lang`) LEFT JOIN `'._DB_PREFIX_.'shop` s ON (s.`id_shop` = n.`id_shop`) WHERE ( '.$sql_shops_id.' ) '; $sql .= ($subscribed ? ' AND n.`active` = '.(int) $subscribed : ''); if (Tools::strlen(trim($and)) > 0) { $sql .= ' AND '.$and.' '; } $sql .= ' ORDER BY n.`id_newsletter_pro_subscribers` ASC '; if (Tools::strlen(trim($end)) > 0) { $sql .= ' '.$end.' '; } $sql .= ';'; return $sql; } /** * Get newsletter pro visitors subscribed. * * @param bool $encode * * @return json/array */ public function getVisitorsNP($encode = true) { $sql = $this->getVisitorsNPSql(); $userlist = Db::getInstance()->executeS($sql); foreach ($userlist as &$user) { $user['img_path'] = $this->getLangImageById($user['id_lang']); } if ($encode) { return Tools::jsonEncode($userlist); } else { return $userlist; } } /** * Update newsletter pro visitors subscribed. * * @param int $id * * @return int */ public function updateVisitorNP($id) { parse_str(Tools::file_get_contents('php://input'), $put); $data = [ 'active' => (int) $put['active'], ]; return (int) (Db::getInstance()->update('newsletter_pro_subscribers', $data, '`id_newsletter_pro_subscribers`= '.(int) $id)); } /** * Delete newsletter pro visitors subscribed. * * @param int $id * * @return int */ public function deleteVisitorNP($id) { return (int) Db::getInstance()->delete('newsletter_pro_subscribers', '`id_newsletter_pro_subscribers`= '.(int) $id, 1); } /** * Search newsletter pro visitors subscribed. * * @param string $value * * @return json */ public function searchVisitorNP($value, $conditions) { if (is_array($conditions) && !empty($conditions)) { $selected_condition = (int) $conditions['selected_condition']; $selected_field = $conditions['selected_field']; $db_fields = $this->getVisitorsNpColumns(); $search_in_fields = $db_fields; if ('0' != $selected_field && in_array($selected_field, $db_fields)) { $search_in_fields = [$selected_field]; } $search_query = ''; // if the filter is setup to all fields, filter only the below columns if ('0' == $selected_field) { $new_fields = []; if (in_array('firstname', $search_in_fields)) { $new_fields[] = 'firstname'; } if (in_array('lastname', $search_in_fields)) { $new_fields[] = 'lastname'; } if (in_array('email', $search_in_fields)) { $new_fields[] = 'email'; } $search_in_fields = $new_fields; } foreach ($search_in_fields as $field) { if (!in_array($field, $db_fields)) { continue; } $is_int = false; if (in_array($field, ['id_shop', 'id_shop_group', 'id_lang', 'id_gender', 'active'])) { $is_int = true; } else { $is_int = false; } switch ($selected_condition) { case self::SEARCH_CONDITION_CONTAINS: $search_query .= ' n.`'.$field.'` LIKE '.($is_int ? '"%'.(int) $value.'%"' : '"%'.pSQL($value).'%"').' OR'; break; case self::SEARCH_CONDITION_IS: $search_query .= ' n.`'.$field.'` = '.($is_int ? (int) $value : '"'.pSQL($value).'"').' OR'; break; case self::SEARCH_CONDITION_IS_NOT: $search_query .= ' n.`'.$field.'` != '.($is_int ? (int) $value : '"'.pSQL($value).'"').' OR'; break; case self::SEARCH_CONDITION_GREATER: $search_query .= ' n.`'.$field.'` >= '.($is_int ? (int) $value : '"'.pSQL($value).'"').' OR'; break; case self::SEARCH_CONDITION_LESS: $search_query .= ' n.`'.$field.'` <= '.($is_int ? (int) $value : '"'.pSQL($value).'"').' OR'; break; } } $search = '( '.rtrim($search_query, 'OR').' )'; } else { $search = ' ( n.`email` LIKE "%'.pSQL($value).'%" OR n.`firstname` LIKE "%'.pSQL($value).'%" OR n.`lastname` LIKE "%'.pSQL($value).'%" )'; } $sql = $this->getVisitorsNPSql($search); $userlist = Db::getInstance()->executeS($sql); foreach ($userlist as &$user) { $user['img_path'] = $this->getLangImageById($user['id_lang']); } return Tools::jsonEncode($userlist); } /** * Filter newsletter pro visitors subscribed. * * @param array $filters * * @return json */ public function filterVisitorNP($filters) { if (is_array($filters) && !empty($filters)) { if (isset($filters['by_birthday']['from'], $filters['by_birthday']['to'])) { if ('' == trim($filters['by_birthday']['from']) || '' == trim($filters['by_birthday']['to'])) { unset($filters['by_birthday']); } } if (isset($filters['range_selection']['min'], $filters['range_selection']['max'])) { if ($filters['range_selection']['min'] && $filters['range_selection']['max']) { $range_selection = $filters['range_selection']; } unset($filters['range_selection']); } } if (is_array($filters) && !empty($filters) || isset($range_selection)) { $sql = ''; $filters_count = count($filters); $filters_index = 1; foreach ($filters as $type => $ids) { if ('languages' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' n.id_lang = '.(int) $id.' OR '; } else { $sql .= ' n.id_lang = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } elseif ('shops' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' n.id_shop = '.(int) $id.' OR '; } else { $sql .= ' n.id_shop = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } elseif ('gender' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' n.id_gender = '.(int) $id.' OR '; } else { $sql .= ' n.id_gender = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } elseif ('subscribed' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' n.active = '.(int) $id.' OR '; } else { $sql .= ' n.active = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } elseif ('by_interest' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { if (-1 == $id) { $sql .= " n.`list_of_interest` IS NULL OR n.`list_of_interest` = '' OR "; } else { $sql .= ' FIND_IN_SET ('.(int) $id.', n.`list_of_interest`) OR '; // $sql .= ' n.`list_of_interest` = '.(int)$id.' OR '; not ok } } else { if (-1 == $id) { $sql .= " n.`list_of_interest` IS NULL OR n.`list_of_interest` = '' "; } else { $sql .= ' FIND_IN_SET ('.(int) $id.', n.`list_of_interest`) '; // $sql .= ' n.`list_of_interest` = '.(int)$id.' '; not ok } } ++$ids_index; } $sql .= ' ) '; } elseif ('by_birthday' == $type) { $only_month_day = true; if ($only_month_day) { $form = date('m-d', strtotime(str_replace('.', '-', $filters['by_birthday']['from']))); $to = date('m-d', strtotime(str_replace('.', '-', $filters['by_birthday']['to']))); $sql .= ' DATE_FORMAT(n.birthday, "%m-%d") >= "'.pSQL($form).'" AND DATE_FORMAT(n.birthday, "%m-%d") <= "'.pSQL($to).'" '; } else { $form = date('Y-m-d', strtotime(str_replace('.', '-', $filters['by_birthday']['from']))); $to = date('Y-m-d', strtotime(str_replace('.', '-', $filters['by_birthday']['to']))); $sql .= ' n.birthday >= "'.pSQL($form).'" AND n.birthday <= "'.pSQL($to).'" '; } } if ($filters_index != $filters_count) { $sql .= ' AND '; } ++$filters_index; } if (true == pqnp_config('VIEW_ACTIVE_ONLY') && $filters_count > 0) { $sql .= ' AND n.`active` = 1'; } elseif (true == pqnp_config('VIEW_ACTIVE_ONLY')) { $sql .= ' n.`active` = 1'; } else { $sql .= ''; } $end = ''; if (isset($range_selection)) { $lim_start = (int) $range_selection['min']; if ($lim_start < 0) { $lim_start = 0; } $lim_end = (int) $range_selection['max'] - (int) $range_selection['min']; if ($lim_end < 0) { $lim_end = 0; } $end = ' LIMIT '.(int) $lim_start.', '.(int) $lim_end.' '; } $sql = $this->getVisitorsNPSql($sql, $end); $userlist = Db::getInstance()->executeS($sql); foreach ($userlist as &$user) { $user['img_path'] = $this->getLangImageById($user['id_lang']); } return Tools::jsonEncode($userlist); } return $this->getVisitorsNP(); } /** * Get visitors. * * @param bool $encode * * @return json/array */ public function getVisitors($encode = true) { $sql = $this->getVisitorsSql(); if ($sql) { $userlist = Db::getInstance()->executeS($sql); // $default_lang = (int)pqnp_config('PS_LANG_DEFAULT'); foreach ($userlist as &$user) { $user['img_path'] = $this->getLangImageById($user['id_lang']); } if ($encode) { return Tools::jsonEncode($userlist); } else { return $userlist; } } else { if ($encode) { return Tools::jsonEncode([]); } else { return []; } } } /** * Get visitors sql. * * @param string $and * @param string $end * * @return string/boolean */ private function getVisitorsSql($and = '', $end = '') { $table_name = NewsletterProDefaultNewsletterTable::getTableName(); $defaultLang = (int) pqnp_config('PS_LANG_DEFAULT'); if ($table_name) { $sql_shops_id = ''; $get_active_shops_id = NewsletterProTools::getActiveShopsId(); $subscribed = (int) pqnp_config('VIEW_ACTIVE_ONLY'); foreach ($get_active_shops_id as $id_shop) { $sql_shops_id .= 'n.`id_shop` = '.(int) $id_shop.(end($get_active_shops_id) == $id_shop ? '' : ' OR '); } $sql = ' SELECT n.`id`, n.`id_shop`, '.(NewsletterProDefaultNewsletterTable::hasIdLang() ? 'n.`id_lang`' : $defaultLang.' as `id_lang`').', n.`ip_registration_newsletter`, n.`email`, n.`active`, sh.`name` AS `shop_name` FROM `'._DB_PREFIX_.pSQL($table_name).'` n INNER JOIN `'._DB_PREFIX_.'shop` sh ON (n.`id_shop` = sh.`id_shop`) WHERE ('.$sql_shops_id.') '; $sql .= ($subscribed ? ' AND n.`active` = '.(int) $subscribed : ''); if (Tools::strlen(trim($and)) > 0) { $sql .= ' AND '.$and.' '; } $sql .= ' ORDER BY n.`id` ASC '; if (Tools::strlen(trim($end)) > 0) { $sql .= ' '.$end.' '; } $sql .= ';'; return $sql; } else { return false; } } /** * Update visitor subscribed. * * @param int $id * * @return int */ public function updateVisitor($id) { if (!($table_name = NewsletterProDefaultNewsletterTable::getTableName())) { return false; } parse_str(Tools::file_get_contents('php://input'), $put); $data = [ 'active' => (int) $put['active'], ]; return (int) (Db::getInstance()->update($table_name, $data, "`id`={$id}")); } /** * Delete visitor subscribed. * * @param int $id * * @return int */ public function deleteVisitor($id) { $tableName = NewsletterProDefaultNewsletterTable::getTableName(); return (int) Db::getInstance()->delete($tableName, '`id`='.(int) $id, 1); } /** * Search visitors. * * @param string $value * * @return json */ public function searchVisitor($value) { $search = ' ( n.`email` LIKE "%'.pSQL($value).'%" )'; $sql = $this->getVisitorsSql($search); // $default_lang = (int)pqnp_config('PS_LANG_DEFAULT'); $userlist = Db::getInstance()->executeS($sql); foreach ($userlist as &$user) { $user['img_path'] = $this->getLangImageById($user['id_lang']); } return Tools::jsonEncode($userlist); } /** * Filter visitor subscribed. * * @param array $filters * * @return json */ public function filterVisitor($filters) { if (is_array($filters) && !empty($filters)) { if (isset($filters['range_selection']['min'], $filters['range_selection']['max'])) { if ($filters['range_selection']['min'] && $filters['range_selection']['max']) { $range_selection = $filters['range_selection']; } unset($filters['range_selection']); } } if (is_array($filters) && !empty($filters) || isset($range_selection)) { $sql = ''; $filters_count = count($filters); $filters_index = 1; foreach ($filters as $type => $ids) { if ('shops' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' n.id_shop = '.(int) $id.' OR '; } else { $sql .= ' n.id_shop = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } elseif ('subscribed' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' n.active = '.(int) $id.' OR '; } else { $sql .= ' n.active = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } if ($filters_index != $filters_count) { $sql .= ' AND '; } ++$filters_index; } if (true == pqnp_config('VIEW_ACTIVE_ONLY') && $filters_count > 0) { $sql .= ' AND n.`active` = 1'; } elseif (true == pqnp_config('VIEW_ACTIVE_ONLY')) { $sql .= ' n.`active` = 1'; } else { $sql .= ''; } $end = ''; if (isset($range_selection)) { $lim_start = (int) $range_selection['min']; if ($lim_start < 0) { $lim_start = 0; } $lim_end = (int) $range_selection['max'] - (int) $range_selection['min']; if ($lim_end < 0) { $lim_end = 0; } $end = ' LIMIT '.(int) $lim_start.', '.(int) $lim_end.' '; } $sql = $this->getVisitorsSql($sql, $end); // $default_lang = (int)pqnp_config('PS_LANG_DEFAULT'); $userlist = Db::getInstance()->executeS($sql); foreach ($userlist as &$user) { $user['img_path'] = $this->getLangImageById($user['id_lang']); } return Tools::jsonEncode($userlist); } return $this->getVisitors(); } /** * Get customers. * * @param bool $encode * * @return json/array */ public function getCustomers($encode = true) { $sql = $this->getCustomersSql([ 'subscribed' => (int) pqnp_config('VIEW_ACTIVE_ONLY'), ]); $userlist = Db::getInstance()->executeS($sql); foreach ($userlist as &$user) { $user['img_path'] = $this->getLangImageById($user['id_lang']); } if ($encode) { return Tools::jsonEncode($userlist); } return $userlist; } /** * Get customers sql statement. * * @param array $cfg * * @return string */ public function getCustomersSql($cfg = []) { $select = null; $from = null; $join = null; $where = null; $and = null; $end = null; $subscribed = null; extract($cfg); $sql_shops_id = ''; $get_active_shops_id = NewsletterProTools::getActiveShopsId(); foreach ($get_active_shops_id as $id_shop) { $sql_shops_id .= 'c.`id_shop` = '.(int) $id_shop.(end($get_active_shops_id) == $id_shop ? '' : ' OR '); } $sql = 'SELECT c.`firstname`, c.`lastname`, c.`email`, c.`id_customer` AS `id`, c.`id_lang`, c.`id_shop`, c.`id_default_group`, c.`newsletter`, c.`id_gender`, sh.`name` AS `shop_name`, npcc.`categories`, loi.`categories` AS categories_loi, GROUP_CONCAT(cg.`id_group`) AS `id_group` '; $sql .= (isset($select) ? ', '.$select.' ' : ''); $sql .= ' FROM `'._DB_PREFIX_.'customer` c '; $sql .= (isset($from) ? ' '.$from.' ' : ''); $sql .= ' LEFT JOIN `'._DB_PREFIX_.'customer_group` cg ON ( cg.`id_customer` = c.`id_customer` ) LEFT JOIN `'._DB_PREFIX_.'newsletter_pro_customer_category` npcc ON (c.`id_customer` = npcc.`id_customer`) LEFT JOIN `'._DB_PREFIX_.'lang` lg ON (c.`id_lang` = lg.`id_lang`) LEFT JOIN `'._DB_PREFIX_.'newsletter_pro_customer_list_of_interests` loi ON (c.id_customer = loi.id_customer) '.((bool) pqnp_ini_config('filter_customers_by_address') ? 'LEFT JOIN `'._DB_PREFIX_.'address` a ON (c.`id_customer` = a.`id_customer`)' : '').' INNER JOIN `'._DB_PREFIX_.'shop` sh ON (c.`id_shop` = sh.`id_shop`) AND ('.$sql_shops_id.') '; $sql .= (isset($join) ? ' '.$join.' ' : ''); if (isset($where)) { $sql .= (isset($where) ? ' WHERE '.$where.' ' : ' WHERE 1 '); } elseif (isset($subscribed)) { $sql .= ((int) pqnp_config('VIEW_ACTIVE_ONLY') ? ' WHERE c.`newsletter` = '.(int) $subscribed : ' WHERE 1 '); } else { $sql .= ' WHERE 1 '; } $sql .= (isset($and) && trim($and) ? ' AND '.$and.' ' : ''); $sql .= ' GROUP BY c.id_customer ORDER BY c.`id_customer` ASC '; $sql .= (isset($end) && trim($end) ? ' '.$end.' ' : ''); $sql .= ';'; return $sql; } /** * Search customer. * * @param string $value * * @return json */ public function searchCustomer($value) { $search = ' ( c.`email` LIKE "%'.pSQL($value).'%" OR c.`firstname` LIKE "%'.pSQL($value).'%" OR c.`lastname` LIKE "%'.pSQL($value).'%" )'; $sql = $this->getCustomersSql([ 'and' => $search, 'subscribed' => (int) pqnp_config('VIEW_ACTIVE_ONLY'), ]); $userlist = Db::getInstance()->executeS($sql); foreach ($userlist as &$user) { $user['img_path'] = $this->getLangImageById($user['id_lang']); } return Tools::jsonEncode($userlist); } /** * Filter customer. * * @param array $filters * * @return json */ public function filterCustomer($filters) { $countries_ids = []; if (is_array($filters) && !empty($filters)) { if (isset($filters['by_birthday']['from'], $filters['by_birthday']['to'])) { if ('' == trim($filters['by_birthday']['from']) || '' == trim($filters['by_birthday']['to'])) { unset($filters['by_birthday']); } } if (isset($filters['range_selection']['min'], $filters['range_selection']['max'])) { if ($filters['range_selection']['min'] && $filters['range_selection']['max']) { $range_selection = $filters['range_selection']; } unset($filters['range_selection']); } } if ((is_array($filters) && !empty($filters)) || isset($range_selection)) { $sql = ''; $filters_count = count($filters); $filters_index = 1; foreach ($filters as $type => $ids) { if ('groups' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' cg.`id_group` = '.(int) $id.' OR '; // $sql .= ' FIND_IN_SET ('.(int)$id.', cg.`id_group`) OR '; } else { $sql .= ' cg.`id_group` = '.(int) $id.' '; // $sql .= ' FIND_IN_SET ('.(int)$id.', cg.`id_group`) '; } ++$ids_index; } $sql .= ' ) '; } elseif ('languages' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' c.id_lang = '.(int) $id.' OR '; } else { $sql .= ' c.id_lang = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } elseif ('shops' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' c.id_shop = '.(int) $id.' OR '; } else { $sql .= ' c.id_shop = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } elseif ('gender' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' c.id_gender = '.(int) $id.' OR '; } else { $sql .= ' c.id_gender = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } elseif ('subscribed' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { $sql .= ' c.newsletter = '.(int) $id.' OR '; } else { $sql .= ' c.newsletter = '.(int) $id.' '; } ++$ids_index; } $sql .= ' ) '; } elseif ('by_interest' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { if (-1 == $id) { $sql .= " loi.`categories` IS NULL OR loi.`categories` = '' OR "; } else { $sql .= ' FIND_IN_SET ('.(int) $id.', loi.`categories`) OR '; // $sql .= ' n.`list_of_interest` = '.(int)$id.' OR '; not ok } } else { if (-1 == $id) { $sql .= " loi.`categories` IS NULL OR loi.`categories` = '' "; } else { $sql .= ' FIND_IN_SET ('.(int) $id.', loi.`categories`) '; // $sql .= ' n.`list_of_interest` = '.(int)$id.' '; not ok } } ++$ids_index; } $sql .= ' ) '; } elseif ('categories' == $type) { $sql .= ' ( '; $ids_count = count($ids); $ids_index = 1; foreach ($ids as $id) { if ($ids_index != $ids_count) { if (-1 == $id) { $sql .= " npcc.`categories` IS NULL OR npcc.`categories` = '' OR "; } else { $sql .= ' npcc.`categories` = '.(int) $id.' OR '; // $sql .= ' FIND_IN_SET ('.(int)$id.', npcc.`categories`) OR '; } } else { if (-1 == $id) { $sql .= " npcc.`categories` IS NULL OR npcc.`categories` = '' "; } else { $sql .= ' npcc.`categories` = '.(int) $id.' '; // $sql .= ' FIND_IN_SET ('.(int)$id.', npcc.`categories`) '; } } ++$ids_index; } $sql .= ' ) '; } elseif ('purchased_product' == $type) { $start_date = trim($ids['startDate']); $end_date = trim($ids['endDate']); $order_date_sql = ''; if (Tools::strlen($start_date) > 0 && Tools::strlen($end_date) > 0) { $order_date_sql = ' AND o.`date_add` >= "'.pSQL($start_date).'" AND o.`date_add` <= "'.pSQL($end_date).'" '; } elseif (Tools::strlen($start_date) > 0) { $order_date_sql = ' AND o.`date_add` >= "'.pSQL($start_date).'" '; } elseif (Tools::strlen($end_date) > 0) { $order_date_sql = ' AND o.`date_add` <= "'.pSQL($end_date).'" '; } if (array_key_exists('withoutPurchase', $ids) && filter_var($ids['withoutPurchase'], FILTER_VALIDATE_BOOLEAN)) { $sql .= ' ( select count(*) from `'._DB_PREFIX_.'orders` o WHERE o.`id_customer` = c.`id_customer` '.$order_date_sql.' ) = 0 '; } else { $ids = array_key_exists('ids', $ids) ? $ids['ids'] : []; $sql .= ' c.`id_customer` IN ( '; $ids_str = trim(implode(',', $ids), ','); $sql .= ' SELECT o.`id_customer` FROM `'._DB_PREFIX_.'orders` o INNER JOIN `'._DB_PREFIX_.'order_detail` car ON ( o.`id_order` = car.`id_order` AND car.`product_id` IN ('.pSQL($ids_str).') ) WHERE 1 '.$order_date_sql.' '; $sql .= ' ) '; } } elseif ('by_birthday' == $type) { $only_month_day = true; if ($only_month_day) { $form = date('m-d', strtotime(str_replace('.', '-', $filters['by_birthday']['from']))); $to = date('m-d', strtotime(str_replace('.', '-', $filters['by_birthday']['to']))); $sql .= ' DATE_FORMAT(c.birthday, "%m-%d") >= "'.pSQL($form).'" AND DATE_FORMAT(c.birthday, "%m-%d") <= "'.pSQL($to).'" '; } else { $form = date('Y-m-d', strtotime(str_replace('.', '-', $filters['by_birthday']['from']))); $to = date('Y-m-d', strtotime(str_replace('.', '-', $filters['by_birthday']['to']))); $sql .= ' c.birthday >= "'.pSQL($form).'" AND c.birthday <= "'.pSQL($to).'" '; } } elseif ('total_spent' == $type) { $sql .= '( (SELECT SUM(o.`total_paid_real` / o.`conversion_rate`) FROM `'._DB_PREFIX_.'orders` o WHERE o.`id_customer` = c.`id_customer` '.Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o').') >= '.(int) $filters['total_spent']['from'].' AND (SELECT SUM(o.`total_paid_real` / o.`conversion_rate`) FROM `'._DB_PREFIX_.'orders` o WHERE o.`id_customer` = c.`id_customer` '.Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o').') <= '.(int) $filters['total_spent']['to'].' ) '; } elseif ('filter_by_country' == $type) { $ids_count = count($ids); $ids_index = 0; $sql .= ' ( '; foreach ($ids as $iso_code) { if ((bool) pqnp_ini_config('filter_customers_by_address')) { if (!array_key_exists($iso_code, $countries_ids)) { $countries_ids[$iso_code] = (int) Country::getByIso($iso_code); } $countryId = (int) $countries_ids[$iso_code]; if ($ids_index < $ids_count - 1) { $sql .= ' (a.`id_country` = '.(int) $countryId.') OR '; } else { $sql .= ' (a.`id_country` = '.(int) $countryId.') '; } } else { if ($ids_index < $ids_count - 1) { $sql .= ' LOWER(lg.`language_code`) LIKE "%-'.pSQL(Tools::strtolower($iso_code)).'" OR '; } else { $sql .= ' LOWER(lg.`language_code`) LIKE "%-'.pSQL(Tools::strtolower($iso_code)).'" '; } } ++$ids_index; } $sql .= ' ) '; } if ($filters_index != $filters_count) { $sql .= ' AND '; } ++$filters_index; } if (true == pqnp_config('VIEW_ACTIVE_ONLY') && $filters_count > 0) { $sql .= ' AND c.`newsletter` = 1'; } elseif (true == pqnp_config('VIEW_ACTIVE_ONLY')) { $sql .= ' c.`newsletter` = 1'; } else { $sql .= ''; } $sql_filter = [ 'and' => $sql, 'subscribed' => (int) pqnp_config('VIEW_ACTIVE_ONLY'), ]; if (isset($range_selection)) { $lim_start = (int) $range_selection['min']; if ($lim_start < 0) { $lim_start = 0; } $lim_end = (int) $range_selection['max'] - (int) $range_selection['min']; if ($lim_end < 0) { $lim_end = 0; } $sql_filter['end'] = ' LIMIT '.(int) $lim_start.', '.(int) $lim_end.' '; } $sql = $this->getCustomersSql($sql_filter); $userlist = Db::getInstance()->executeS($sql); foreach ($userlist as &$user) { $user['img_path'] = $this->getLangImageById($user['id_lang']); } return Tools::jsonEncode($userlist); } return $this->getCustomers(); } /** * Get language image by id. * * @param int $id * * @return string */ public function getLangImageById($id) { $path = ''; if (file_exists($this->lang_img_dir.$id.'.jpg')) { $path = $this->lang_img_path.$id.'.jpg'; } else { $path = $this->lang_img_path.'none.jpg'; } $path = $this->relplaceAdminLink($path); return $path; } /** * Update customer by id. * * @param int $id * * @return int */ public function updateCustomer($id) { parse_str(Tools::file_get_contents('php://input'), $put); $data = [ 'newsletter' => (int) $put['newsletter'], ]; return (int) (Db::getInstance()->update('customer', $data, '`id_customer`= '.(int) $id)); } /** * Delete customer by id. * * @param int $id * * @return int */ public function deleteCustomer($id) { if ((int) pqnp_ini_config('demo_mode')) { exit('This is a demo, it is not possible to delete the customer.'); } $customer = new Customer($id); if (null != $customer->id) { return (int) $customer->delete(); } return 0; } /** * Get tasks. * * @return json */ public function getTasks() { $sql = 'SELECT * FROM `'._DB_PREFIX_.'newsletter_pro_task` t WHERE `done` = 0 ORDER BY t.`date_start` ASC'; if ($tasks = Db::getInstance()->executeS($sql)) { $current_day_time = strtotime(date('Y-m-d')); foreach ($tasks as &$task) { $status = &$task['status']; $date_start = strtotime($task['date_start']); $task['error_msg'] = NewsletterProTools::unSerialize($task['error_msg']); if (1 === (int) $status) { $status = 1; } elseif ($current_day_time === $date_start) { $status = $this->l('today'); } elseif (($current_day_time + 24 * 60 * 60) === $date_start) { $status = $this->l('tomorrow'); } elseif ($current_day_time > $date_start) { $status = $this->l('in the past'); } else { $status = ''; } } return Tools::jsonEncode($tasks); } else { return Tools::jsonEncode([]); } } public function getSubscriptionConsent() { $results = Db::getInstance()->executeS(' SELECT id_newsletter_pro_subscription_consent, email, subscribed, ip_address, consent_date, date_add, date_upd FROM `'._DB_PREFIX_.'newsletter_pro_subscription_consent` sc WHERE `id_newsletter_pro_subscription_consent` = ( SELECT MAX(`id_newsletter_pro_subscription_consent`) FROM `'._DB_PREFIX_.'newsletter_pro_subscription_consent` msc WHERE msc.`email` = sc.`email` ) '); return Tools::jsonEncode($results); } public function searchSubscriptionConsent($value) { $results = Db::getInstance()->executeS(' SELECT id_newsletter_pro_subscription_consent, email, subscribed, ip_address, consent_date, date_add, date_upd FROM `'._DB_PREFIX_.'newsletter_pro_subscription_consent` sc WHERE `id_newsletter_pro_subscription_consent` = ( SELECT MAX(`id_newsletter_pro_subscription_consent`) FROM `'._DB_PREFIX_.'newsletter_pro_subscription_consent` msc WHERE msc.`email` = sc.`email` AND email LIKE "%'.pSQL($value).'%" OR email = "'.pSQL(Tools::encrypt($value)).'" ) '); return Tools::jsonEncode($results); } public function getSubscriptionConsentDetails($email) { $response = new NewsletterProAjaxResponse([ 'data' => [], ]); $results = Db::getInstance()->executeS(' SELECT * from `'._DB_PREFIX_.'newsletter_pro_subscription_consent` WHERE `email` = "'.pSQL($email).'" ORDER BY `id_newsletter_pro_subscription_consent` desc '); $response->set('data', $results); return $response->display(); } public function deleteSubscriptionConsent($email) { $response = new NewsletterProAjaxResponse([]); NewsletterProSubscriptionConsent::deleteByEmail($email); return $response->display(); } public function searchPrivacyData($email) { $response = new NewsletterProAjaxResponse([ 'data' => null, ]); $privacy_data = new NewsletterProPrivacyData(); $data = $privacy_data->search($email); $response->set('data', $data); return $response->display(); } public function clearPrivacyData($email) { $response = new NewsletterProAjaxResponse([ 'data' => null, ]); $privacy_data = new NewsletterProPrivacyData(); $data = $privacy_data->clear($email); $response->set('data', $data); return $response->display(); } /** * Render the template history. * * @param int $id_history * * @return json */ public function renderTemplateHistory($id_history) { $url = $this->getTemplateHistoryUrl($id_history); // viewInBrowser will remove the opened email tracking if the browser is viewed by admin $url .= '&viewInBrowser=1'; ; return Tools::jsonEncode([ 'downloadUri' => NewsletterProTools::getUri([ 'exportTemplateHistory' => true, 'idTemplateHistory' => (int) $id_history, ]), 'url' => $url, // jQueryNoConflict is important 'content' => Tools::file_get_contents($url.'&jQueryNoConflict'), ]); } /** * Get template history url. * * @param int $id_history * * @return string */ public function getTemplateHistoryUrl($id_history) { return urldecode(Context::getContext()->link->getModuleLink($this->name, 'newsletter', [ 'token_tpl' => $this->getTokenByIdHistory((int) $id_history), 'email' => pqnp_config('PS_SHOP_EMAIL'), ])); } /** * Get token by id hisotry. * * @param int $id_history * * @return int */ public function getTokenByIdHistory($id_history) { return Db::getInstance()->getValue('SELECT `token` FROM `'._DB_PREFIX_.'newsletter_pro_tpl_history` WHERE `id_newsletter_pro_tpl_history` = '.(int) $id_history); } /** * Get hisotry id by token. * * @param string $token * * @return int */ public function getHistoryIdByToken($token) { return (int) Db::getInstance()->getValue('SELECT `id_newsletter_pro_tpl_history` FROM `'._DB_PREFIX_.'newsletter_pro_tpl_history` WHERE `token` = "'.pSQL($token).'"'); } /** * Get task history. * * @return json */ public function getTasksHistory() { $sql = 'SELECT t.`id_newsletter_pro_task`, t.`id_newsletter_pro_smtp`, t.`id_newsletter_pro_tpl_history`, t.`date_start`, t.`active`, t.`template`, t.`status`, t.`sleep`, t.`emails_count`, t.`emails_error`, t.`emails_success`, t.`emails_completed`, t.`done`, t.`error_msg`, h.`clicks`, h.`opened`, h.`unsubscribed`, h.`fwd_unsubscribed`, GROUP_CONCAT(ts.`id_newsletter_pro_task_step`) AS `steps` FROM `'._DB_PREFIX_.'newsletter_pro_task` t LEFT JOIN `'._DB_PREFIX_.'newsletter_pro_task_step` ts ON (ts.`id_newsletter_pro_task` = t.`id_newsletter_pro_task`) LEFT JOIN `'._DB_PREFIX_.'newsletter_pro_tpl_history` h ON (t.`id_newsletter_pro_tpl_history` = h.`id_newsletter_pro_tpl_history`) WHERE t.`done` = 1 GROUP BY t.`id_newsletter_pro_task` ORDER BY t.`date_start` DESC;'; if ($tasks = Db::getInstance()->executeS($sql)) { foreach ($tasks as &$task) { $task['date_start'] = date('Y-m-d', strtotime($task['date_start'])); $task['error_msg'] = unserialize($task['error_msg']); $task['template'] = Tools::ucfirst(pathinfo($task['template'], PATHINFO_FILENAME)); } return Tools::jsonEncode($tasks); } else { return Tools::jsonEncode([]); } } /** * Get unsubscribed details. * * @param int $id_newsletter * * @return string */ public function getUnsubscribedDetails($id_newsletter) { $sql = 'SELECT * FROM `'._DB_PREFIX_.'newsletter_pro_unsibscribed` WHERE `id_newsletter_pro_tpl_history` = '.(int) $id_newsletter; $result = Db::getInstance()->executeS($sql); $this->context->smarty->assign([ 'result' => $result, ]); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/task/unsubscribed_detail.tpl')); } /** * Get the task unsubscribed details. * * @param int $id_newsletter * * @return string */ public function getTaskUnsubscribedDetails($id_newsletter) { return $this->getUnsubscribedDetails($id_newsletter); } /** * Get the task forwarders unsubscribed details. * * @param int $id_newsletter * * @return string */ public function getTaskFwdUnsubscribedDetails($id_newsletter) { return $this->getFwdUnsubscribedDetails($id_newsletter); } /** * Get forwarders subscribed details. * * @param int $id_newsletter * * @return string */ public function getFwdUnsubscribedDetails($id_newsletter) { $sql = 'SELECT * FROM `'._DB_PREFIX_.'newsletter_pro_fwd_unsibscribed` WHERE `id_newsletter_pro_tpl_history` = '.(int) $id_newsletter; $result = Db::getInstance()->executeS($sql); $this->context->smarty->assign([ 'result' => $result, ]); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/task/unsubscribed_detail.tpl')); } /** * Get forwarders details. * * @param string $email * * @return string */ public function getForwarderDetails($email) { $sql = 'SELECT * FROM `'._DB_PREFIX_.'newsletter_pro_forward` WHERE `from` = "'.pSQL($email).'" ;'; $result = Db::getInstance()->executeS($sql); $this->context->smarty->assign([ 'result' => $result, ]); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/task/forwarder_detail.tpl')); } /** * Get tasks history detail. * * @param int $id_step * * @return string */ public function getTasksHistoryDetail($id_step) { $sql = 'SELECT * FROM `'._DB_PREFIX_.'newsletter_pro_task_step` WHERE `id_newsletter_pro_task_step` = '.(int) $id_step; $step = Db::getInstance()->getRow($sql); if ($step) { $step['emails_to_send'] = NewsletterProTools::unSerialize($step['emails_to_send']); $step['emails_sent'] = NewsletterProTools::unSerialize($step['emails_sent']); } $this->context->smarty->assign([ 'step' => $step, ]); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/task/task_history_detail.tpl')); } /** * Get send history details. * * @param int $id_step * * @return string */ public function getSendHistoryDetail($id_step) { $sql = 'SELECT * FROM `'._DB_PREFIX_.'newsletter_pro_send_step` WHERE `id_newsletter_pro_send_step` = '.(int) $id_step; $step = Db::getInstance()->getRow($sql); if ($step) { $step['emails_to_send'] = NewsletterProTools::unSerialize($step['emails_to_send']); $step['emails_sent'] = NewsletterProTools::unSerialize($step['emails_sent']); } $this->context->smarty->assign([ 'step' => $step, ]); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/task/send_history_detail.tpl')); } /** * Clear task history. * * @return json */ public function clearTaskHistory() { $response = ['status' => false, 'msg' => '']; $sql = 'SELECT `id_newsletter_pro_tpl_history` AS `id` FROM `'._DB_PREFIX_.'newsletter_pro_task` WHERE `done` = 1 AND `id_newsletter_pro_tpl_history` > 0;'; if ($ids = Db::getInstance()->executeS($sql)) { foreach ($ids as $id) { Db::getInstance()->delete('newsletter_pro_tpl_history', '`id_newsletter_pro_tpl_history`='.(int) $id['id']); Db::getInstance()->delete('newsletter_pro_unsibscribed', '`id_newsletter_pro_tpl_history`='.(int) $id['id']); } } $sql = 'DELETE t.*, ts.* FROM `'._DB_PREFIX_.'newsletter_pro_task` t LEFT JOIN `'._DB_PREFIX_.'newsletter_pro_task_step` ts ON ts.`id_newsletter_pro_task` = t.`id_newsletter_pro_task` WHERE t.`done` = 1;'; if (Db::getInstance()->execute($sql)) { $response['status'] = true; } else { $response['msg'] = $this->l('The task history cannot be deleted!'); } return Tools::jsonEncode($response); } /** * Clear statistics. * * @return json */ public function clearStatistics() { $errors = []; $response = ['status' => false, 'errors' => &$errors]; $sql = 'DELETE FROM `'._DB_PREFIX_.'newsletter_pro_statistics` WHERE 1'; if (!Db::getInstance()->execute($sql)) { $errors[] = $this->l('The statistics cannot be deleted!'); } if (empty($errors)) { $response['status'] = true; } return Tools::jsonEncode($response); } /** * Clear send history. * * @return json */ public function clearSendHistory() { $response = ['status' => false, 'msg' => '']; $sql = 'DELETE s.*, ss.* FROM `'._DB_PREFIX_.'newsletter_pro_send` s LEFT JOIN `'._DB_PREFIX_.'newsletter_pro_send_step` ss ON ss.`id_newsletter_pro_send` = s.`id_newsletter_pro_send` WHERE s.`active` = 0;'; if (Db::getInstance()->execute($sql)) { $response['status'] = true; } else { $response['msg'] = $this->l('The history cannot be deleted!'); } return Tools::jsonEncode($response); } /** * Delete task by id. * * @param int $id * * @return int */ public function deleteTask($id) { $sql = 'SELECT `id_newsletter_pro_tpl_history` FROM `'._DB_PREFIX_.'newsletter_pro_task` WHERE `id_newsletter_pro_task`='.(int) $id; if ($id_history = Db::getInstance()->getValue($sql)) { Db::getInstance()->delete('newsletter_pro_tpl_history', '`id_newsletter_pro_tpl_history`='.(int) $id_history, 1); Db::getInstance()->delete('newsletter_pro_unsibscribed', '`id_newsletter_pro_tpl_history`='.(int) $id_history, 1); } return (int) (Db::getInstance()->delete('newsletter_pro_task', '`id_newsletter_pro_task`='.(int) $id, 1) && Db::getInstance()->delete('newsletter_pro_task_step', '`id_newsletter_pro_task`='.(int) $id)); } /** * Delete send history by id. * * @param int $id * * @return int */ public function deleteSendHistory($id) { $sql = 'SELECT `id_newsletter_pro_tpl_history` FROM `'._DB_PREFIX_.'newsletter_pro_send` WHERE `id_newsletter_pro_send`='.(int) $id; if ($id_history = Db::getInstance()->getValue($sql)) { Db::getInstance()->delete('newsletter_pro_tpl_history', '`id_newsletter_pro_tpl_history`='.(int) $id_history, 1); Db::getInstance()->delete('newsletter_pro_unsibscribed', '`id_newsletter_pro_tpl_history`='.(int) $id_history, 1); } return (int) (Db::getInstance()->delete('newsletter_pro_send', '`id_newsletter_pro_send`='.(int) $id, 1) && Db::getInstance()->delete('newsletter_pro_send_step', '`id_newsletter_pro_send`='.(int) $id)); } /** * Update task. * * @param int $id * * @return int */ public function updateTask($id) { parse_str(Tools::file_get_contents('php://input'), $put); $data = [ 'id_newsletter_pro_smtp' => (int) $put['id_newsletter_pro_smtp'], 'send_method' => pSQL($put['send_method']), 'date_start' => pSQL($put['date_start']), 'template' => addcslashes($put['template'], "'"), 'active' => (int) $put['active'], ]; $template = NewsletterProTemplate::newFile($put['template'])->load(); $history = NewsletterProTplHistory::newInstance($put['id_newsletter_pro_tpl_history']); $history->template = $template->html(NewsletterProTemplateContent::CONTENT_HTML, true); $history->active = (bool) $put['active']; $history->template_name = $template->name; return (int) (Db::getInstance()->update('newsletter_pro_task', $data, '`id_newsletter_pro_task`= '.(int) $id) && $history->update()); } /** * Remove duplicate emails. * * @param string $emails * * @return array */ public function removeDuplicateEmails($emails) { $emails_return = []; foreach ($emails as $email) { if (!in_array($email, $emails_return)) { $emails_return[] = $email; } } return $emails_return; } /** * Create a new task. * * @param json $data */ public function addTask($data) { $post = &$_POST; $emails = Tools::jsonEncode([]); if (isset($post['emails'])) { $emails = $post['emails']; } $emails = Tools::jsonDecode($emails); $response = ['status' => false, 'errors' => &$this->_errors]; $time = (int) strtotime($data['mysql_date']); if (0 == $time) { $this->_errors[] = $this->l('The date is not valid!'); } if (empty($emails)) { $this->_errors[] = $this->l('No email was selected!'); } if (!trim($data['template'])) { $this->_errors[] = $this->l('Invalid template!'); } if (!(int) $data['id_newsletter_pro_smtp'] && 'smtp' == $data['send_method']) { $this->_errors[] = $this->l('The smtp does not exists!'); } if ((int) $data['sleep'] < 0) { $this->_errors[] = $this->l('Sleep time is not a valid integer!'); } $emails = $this->removeDuplicateEmails($emails); if (empty($this->_errors)) { $step = $this->step; $last_tpl_id = 0; $template = NewsletterProTemplate::newFile($data['template'])->load(); $history = NewsletterProTplHistory::newFromTemplate($template); $history->add(); if (Db::getInstance()->insert('newsletter_pro_task', [ 'id_newsletter_pro_smtp' => (int) $data['id_newsletter_pro_smtp'], 'id_newsletter_pro_tpl_history' => (int) $history->id, 'send_method' => pSQL($data['send_method']), 'started' => 0, 'template' => addcslashes($data['template'], "'"), 'date_start' => pSQL($data['mysql_date']), 'date_modified' => pSQL(date('Y-m-d H:i:s')), 'active' => 1, 'status' => 0, 'sleep' => (int) $data['sleep'], 'emails_count' => count($emails), 'error_msg' => NewsletterProTools::dbSerialize([]), ])) { $id_task = (int) Db::getInstance()->Insert_ID(); $emails_chuck = array_chunk($emails, $step); foreach ($emails_chuck as $i => $emails_list) { $task_smtp = [ 'id_newsletter_pro_task' => $id_task, 'step' => ++$i, 'step_active' => 1, 'emails_to_send' => NewsletterProTools::dbSerialize($emails_list), 'emails_sent' => NewsletterProTools::dbSerialize([]), 'date' => date('Y-m-d H:i:s'), ]; Db::getInstance()->insert('newsletter_pro_task_step', $task_smtp); } $response['status'] = true; } else { $this->_errors[] = $this->l('The task cannot be added to the database!'); } } return Tools::jsonEncode($response); } /** * Select all in progress task * The returned data must be identical with the getTasks function. * * @return array/boolean */ public function getTasksInProgress($look_for = []) { if (!is_array($look_for)) { $look_for = []; } $sql = 'SELECT * FROM `'._DB_PREFIX_.'newsletter_pro_task` WHERE `status` = 1 AND `done` = 0 ORDER BY `date_start` ASC;'; $result_look = false; if (!empty($look_for)) { $sql_look = 'SELECT * FROM `'._DB_PREFIX_.'newsletter_pro_task` WHERE `id_newsletter_pro_task` IN ('.implode(', ', $look_for).');'; $result_look = Db::getInstance()->executeS($sql_look); } $result = Db::getInstance()->executeS($sql); if ($result || $result_look) { if (is_array($result)) { foreach ($result as &$row) { $row['error_msg'] = NewsletterProTools::unSerialize($row['error_msg']); } } return Tools::jsonEncode([ 'result' => is_array($result) ? $result : [], 'result_look' => is_array($result_look) ? array_values($result_look) : [], ]); } else { try { $sql = 'SELECT count(*) AS `count` FROM `'._DB_PREFIX_.'newsletter_pro_task` WHERE `status` = 0 AND `done` = 0;'; if ($count = Db::getInstance()->getValue($sql)) { return (int) $count; } } catch (Exception $e) { return (int) false; } } return (int) false; } /** * Continue tasks. * * @param int $id * * @return int */ public function continueTaskAjax($id) { if (Db::getInstance()->update('newsletter_pro_task', [ 'status' => 0, 'done' => 0, 'pause' => 0, ], 'id_newsletter_pro_task = '.(int) $id)) { $this->sendTaskAjax($id); return 1; } return 0; } /** * Send one task runned in background. * * @param int $id * @param bool $jump_next */ public function sendTaskAjax($id) { $task = NewsletterProTask::newInstance($id); if (Validate::isLoadedObject($task)) { $task->sendTaskAjax(); } } /** * Pause task. * * @param int $id * * @return int */ public function pauseTask($id) { return NewsletterProTask::newInstance($id)->pauseTask(); } /** * Get all smtp connections. * * @return array */ public function getAllSMTP() { $result = NewsletterProMail::getAllMails(); $selected = pqnp_config('SMTP'); if (!empty($result)) { if (!$selected) { $result[0]['selected'] = true; } else { $selected_exist = false; foreach ($result as &$value) { if ($value['id_newsletter_pro_smtp'] == $selected) { $selected_exist = true; $value['selected'] = true; break; } } if (!$selected_exist) { pqnp_config('SMTP', $result[0]['id_newsletter_pro_smtp']); $result[0]['selected'] = true; } } } return $result; } /** * Get all smtp connections as a json format. * * @return json */ public function getAllSMTPJson() { return Tools::jsonEncode($this->getAllSMTP()); } /** * Get category tree. * * @return array */ public function getCategoryTree() { $root = Category::getRootCategory(); $tab_root = ['id_category' => $root->id, 'name' => $root->name]; $category_tree = $this->renderCategoryTree([ 'root' => $tab_root, 'selected_cat' => [], 'input_name' => 'categoryBox', 'use_radio' => false, 'disabled_categories' => [], 'use_search' => true, 'use_in_popup' => false, 'use_shop_context' => true, 'option_no_decide' => true, 'ajax_request_url' => Context::getContext()->link->getModuleLink($this->name, 'ajax', []), ]); return $category_tree; } /** * Set controller. */ private function setController() { require_once $this->dir_location.'AdminNewsletterPro.php'; $this->context->controller = new AdminNewsletterPro(); } /** * Get the top catetory. * * @param int $id_lang * * @return object */ public static function getTopCategory($id_lang = null) { if (method_exists('Category', 'getTopCategory')) { return Category::getTopCategory($id_lang); } if (is_null($id_lang)) { $id_lang = Context::getContext()->language->id; } $id_category = Db::getInstance()->getValue(' SELECT `id_category` FROM `'._DB_PREFIX_.'category` WHERE `id_parent` = 0 '); return new Category($id_category, $id_lang); } /** * @Depracated ( Disabled ) * Add the wright javascript tree plugin files * * @param object $controller */ public function addTreeViewFiles($controller) { $jquery_plugins_foldername = _PS_ROOT_DIR_.'/js/jquery/plugins'; if (file_exists($jquery_plugins_foldername.'/treeview-categories')) { $controller->addCSS(_PS_JS_DIR_.'jquery/plugins/treeview-categories/jquery.treeview-categories.css'); $controller->addJs([ _PS_JS_DIR_.'jquery/plugins/treeview-categories/jquery.treeview-categories.js', _PS_JS_DIR_.'jquery/plugins/treeview-categories/jquery.treeview-categories.async.js', _PS_JS_DIR_.'jquery/plugins/treeview-categories/jquery.treeview-categories.edit.js', ]); } else { $controller->addCSS(_PS_JS_DIR_.'jquery/plugins/treeview/jquery.treeview.css'); $controller->addJs([ _PS_JS_DIR_.'jquery/plugins/treeview/jquery.treeview.js', _PS_JS_DIR_.'jquery/plugins/treeview/jquery.treeview.async.js', _PS_JS_DIR_.'jquery/plugins/treeview/jquery.treeview.edit.js', ]); } } /** * Render category tree. * * @param array $cfg * * @return string */ public function renderCategoryTree($cfg) { $root = isset($cfg['root']) ? $cfg['root'] : null; $selected_cat = isset($cfg['selected_cat']) ? $cfg['selected_cat'] : []; $input_name = isset($cfg['input_name']) ? $cfg['input_name'] : 'categoryBox'; $use_radio = isset($cfg['use_radio']) ? $cfg['use_radio'] : false; $use_search = isset($cfg['use_search']) ? $cfg['use_search'] : false; $disabled_categories = isset($cfg['disabled_categories']) ? $cfg['disabled_categories'] : []; $use_in_popup = isset($cfg['use_in_popup']) ? $cfg['use_in_popup'] : false; $use_shop_context = isset($cfg['use_shop_context']) ? $cfg['use_shop_context'] : false; $ajax_request_url = isset($cfg['ajax_request_url']) ? $cfg['ajax_request_url'] : 'ajax.php'; $option_no_decide = isset($cfg['option_no_decide']) ? $cfg['option_no_decide'] : false; if (!property_exists($this->context, 'controller') || !isset($this->context->controller)) { $this->setController(); } $translations = [ 'selected' => $this->l('Selected'), 'Collapse All' => $this->l('Collapse All'), 'Expand All' => $this->l('Expand All'), 'Check All' => $this->l('Check All'), 'Uncheck All' => $this->l('Uncheck All'), 'search' => $this->l('Find a category'), ]; $top_category = NewsletterPro::getTopCategory(); if (Tools::isSubmit('id_shop')) { $id_shop = Tools::getValue('id_shop'); } else { if (Context::getContext()->shop->id) { $id_shop = Context::getContext()->shop->id; } else { if (!Shop::isFeatureActive()) { $id_shop = Configuration::get('PS_SHOP_DEFAULT'); } else { $id_shop = 0; } } } $shop = new Shop($id_shop); $root_category = Category::getRootCategory(null, $shop); $disabled_categories[] = $top_category->id; if (!$root) { $root = ['name' => $root_category->name, 'id_category' => $root_category->id]; } if (!$use_radio) { $input_name = $input_name.'[]'; } $this->addTreeViewFiles($this->context->controller); $this->context->controller->addJs([ $this->uri_location.'views/js/categories-tree.js', ]); if ($use_search) { $this->context->controller->addJs(_PS_JS_DIR_.'jquery/plugins/autocomplete/jquery.autocomplete.js'); } $selected_cat_var = ''; if (count($selected_cat) > 0) { if (isset($selected_cat[0])) { $selected_cat_var = (int) implode(',', $selected_cat); } else { $selected_cat_var = (int) implode(',', array_keys($selected_cat)); } } $content = ''; $home_is_selected = false; foreach ($selected_cat as $cat) { if (is_array($cat)) { $disabled = in_array($cat['id_category'], $disabled_categories); if ($cat['id_category'] != $root['id_category']) { $content .= ''; } else { $home_is_selected = true; } } else { $disabled = in_array($cat, $disabled_categories); if ($cat != $root['id_category']) { $content .= ''; } else { $home_is_selected = true; } } } $this->context->smarty->assign([ 'input_name' => addcslashes($input_name, "'\""), 'selected_cat' => $selected_cat_var, 'selected_label' => addcslashes($translations['selected'], "'\""), 'home' => addcslashes($root['name'], "'\""), 'use_radio' => $use_radio, 'use_search' => $use_search, 'use_in_popup' => $use_in_popup, 'use_shop_context' => $use_shop_context, 'root' => $root, 'content' => $content, 'root_input' => ($root['id_category'] != $top_category->id || (Tools::isSubmit('ajax') && 'getCategoriesFromRootCategory' == Tools::getValue('action'))), 'home_is_selected' => $home_is_selected, 'ajax_request_url' => $ajax_request_url, 'option_no_decide' => $option_no_decide, ]); return $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/front/category_tree.tpl')); } /** * Check if the campaign is running properly. * * @return json */ public function checkIfCampaignIsRunning() { $errors = []; $response = ['status' => false, 'errors' => &$errors, 'msg' => '']; try { $curl = new NewsletterProCurl(); $params = [ 'newsletterpro_source' => 'newsletter', 'utm_source' => 'testCampaign', ]; $index_url = $this->context->link->getPageLink('index'); $result = $curl->request('GET', $curl->url($index_url, 'html'), $params); if (false !== strpos($result['response'], '[Debug]')) { preg_match('/("|\')(?P.*newsletterpro_source=newsletter\&utm_source=testCampaign.*?)\1/', $result['response'], $match); if (isset($match['url'])) { $result = $curl->request('GET', $curl->url($match['url'], 'html'), $params); } } if (205 == $result['code']) { $index = $result['response']; if ((bool) pqnp_config('GOOGLE_UNIVERSAL_ANALYTICS_ACTIVE')) { if (!preg_match('/(?:\s+)?ga(?:\s+)?\((?:\s+)?\'set\'(?:\s+)?,(?:\s+)?\'campaignSource\'/', $index)) { $errors[] = $this->l('The campaign is not set correctly!'); } } else { if (!preg_match('/_setCampaignTrack(?:\s+)?(\'|")(?:\s+)?,(?:\s+)?true/', $index)) { $errors[] = $this->l('The campaign is not set correctly!'); } } } elseif (200 == $result['code']) { $errors[] = $this->l('The campaign is not set correctly!'); } elseif (1 == $result['code']) { $errors[] = $result['response']; } else { $errors[] = $this->l('Error on running this verification!'); } } catch (Exception $e) { $errors[] = $e->getMessage(); } if (empty($errors)) { $response['msg'] = $this->l('The campaign is set correctly!'); $response['status'] = true; } return Tools::jsonEncode($response); } /** * Get statistics. * * @return json */ public function getStatistics() { $id_lang = (int) $this->context->language->id; if (Version::isLower('1.5.1')) { $sql = 'SELECT nps.`id_product`, nps.`clicks`, pl.`description`, pl.`description_short`, pl.`link_rewrite`, pl.`name`, pl.`id_lang`, p.*, asso_shop_image.`id_image` FROM '._DB_PREFIX_.'newsletter_pro_statistics nps LEFT JOIN '._DB_PREFIX_.'product p on (nps.id_product = p.id_product) LEFT JOIN '._DB_PREFIX_.'product_lang pl on (p.id_product = pl.id_product AND pl.id_lang = '.$id_lang.') LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`)'. @Shop::addSqlAssociation('image', 'i', true, 'image_shop.cover=1').' LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (asso_shop_image.`id_image` = il.`id_image` AND il.`id_lang` = '.(int) $id_lang.') GROUP BY nps.`id_product` ORDER BY nps.`clicks` DESC LIMIT 100;'; } else { $sql = 'SELECT nps.`id_product`, nps.`clicks`, pl.`description`, pl.`description_short`, pl.`link_rewrite`, pl.`name`, pl.`id_lang`, p.*, image_shop.`id_image` FROM '._DB_PREFIX_.'newsletter_pro_statistics nps LEFT JOIN '._DB_PREFIX_.'product p on (nps.id_product = p.id_product) LEFT JOIN '._DB_PREFIX_.'product_lang pl on (p.id_product = pl.id_product AND pl.id_lang = '.$id_lang.') LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`)'. Shop::addSqlAssociation('image', 'i', true, 'image_shop.cover=1').' LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (image_shop.`id_image` = il.`id_image` AND il.`id_lang` = '.(int) $id_lang.') GROUP BY nps.`id_product` ORDER BY nps.`clicks` DESC LIMIT 100;'; } $result = Db::getInstance()->executeS($sql); $products = []; if ($result) { $this->context->currency = new Currency((int) pqnp_config('PS_CURRENCY_DEFAULT')); $result = $this->getStatisticsProductsAttributes($id_lang, $result, (int) $this->context->currency->id); foreach ($result as $key => $value) { $products[$key]['id_product'] = $value['id_product']; $products[$key]['clicks'] = $value['clicks']; $products[$key]['name'] = $value['name']; $products[$key]['price_display'] = $value['price_display']; $products[$key]['link'] = $this->sanitizeLink($value['link']); $products[$key]['thumb_path'] = $value['thumb_path']; $products[$key]['top'] = $key + 1; } return Tools::jsonEncode($products); } return Tools::jsonEncode([]); } /** * Some of the queries are unuseful in the admin backoffice and a sanitize is required. * * @param string $link * * @return string */ public function sanitizeLink($link) { $link = preg_replace('/&id_newsletter=[^}]+\}(?=&|$)/', '', $link); $link = preg_replace('/&newsletterpro_source=newsletter/', '', $link); return $link; } /** * Execute the module update. * * @return json */ public function updateModule() { $errors = []; $response = ['status' => false, 'errors' => &$errors, 'message' => []]; if (!$this->upgrade->execute()) { $errors = array_merge($errors, $this->upgrade->getErrors()); } if (empty($errors)) { $response['status'] = true; $response['message'][] = $this->l('The module was update successfully!'); $response['message'][] = $this->l('The browser will refresh in %s seconds.'); } return Tools::jsonEncode($response); } public function clearUpdateWarnings() { NewsletterProUpgrade::clearWarningCookie(); return $this->response->json(); } /** * Get update details. * * @return array */ public function getUpdateDetails() { $db_version = $this->getDbVersion(); return [ 'needs_update' => ($db_version != $this->version), 'db_version' => $db_version, 'version' => $this->version, ]; } /** * Get module database version. * * @return string */ public function getDbVersion() { return Db::getInstance()->getValue('SELECT `version` FROM `'._DB_PREFIX_.'module` WHERE `name` = "'.pSQL($this->name).'"'); } /** * Get the products statistics attributes. * * @param int $id_lang * @param array $pr * @param int $id_currency * * @return array */ public function getStatisticsProductsAttributes($id_lang, $pr, $id_currency = null) { $prop = $this->getNewProperties(null, $id_currency); $products = Product::getProductsProperties($id_lang, $pr); foreach ($products as &$product) { $this->createProductTemplateVars($id_lang, $product, $prop); } return $products; } /** * Get the filter by purchase content. * * @return string */ public function getFilterByPurchaseContent() { $tpl = $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/filter_by_purchase.tpl')); return $tpl; } /** * Get filter by birthday content. * * @param string $fbb_class * * @return string */ public function getFilterByBirthdayContent($fbb_class = '') { $this->context->smarty->assign([ 'fbb_class' => $fbb_class, ]); $tpl = $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/filter_by_birthday.tpl')); return $tpl; } /** * Get range selection content. * * @return string */ public function getRangeSelectionContent() { $tpl = $this->context->smarty->fetch(pqnp_template_path($this->dir_location.'views/templates/admin/filter_by_range.tpl')); return $tpl; } /** * Search by purchased product. * * @param string $query * * @return json */ public function searchByPurchase($query) { return $this->searchProducts($query, (int) $this->context->language->id, (int) pqnp_config('PS_CURRENCY_DEFAULT')); } /** * Get customer language id. * * @param int $id_customer * * @return int */ public function getCustomerIdLang($id_customer) { return Db::getInstance()->getValue('SELECT `id_lang` FROM '._DB_PREFIX_.'customer WHERE `id_customer` = '.(int) $id_customer); } /** * Strip array. * * @param array $array * @param int $level * * @return array */ public static function strip($array, $level = 10) { if (_PS_MAGIC_QUOTES_GPC_) { if ($level < 0) { return $array; } if (is_array($array)) { foreach ($array as $key => $value) { if (is_array($value)) { $array[$key] = self::strip($value, --$level); } else { $array[$key] = Tools::stripslashes($value); } } } elseif (is_string($array)) { $array = Tools::stripslashes($array); } } return $array; } /** * Get hooks list. * * @return array */ public function getHooksList() { $reflection = new ReflectionObject($this); $methods = $reflection->getMethods(ReflectionMethod::IS_PUBLIC); $all_hooks = []; foreach ($methods as $method) { if (preg_match('/^hook[A-Z]/', $method->name) && __CLASS__ == $method->class) { $all_hooks[] = lcfirst(preg_replace('/^hook/', '', $method->name)); } } return $all_hooks; } /** * For the order version of prestashop. * * @param bool $share * * @return array */ public function getListOfID($share = false) { $shop_id = $this->getID(); $shop_group_id = $this->getGroupID(); if ($shop_id) { $list = ($share) ? Shop::getSharedShops($shop_id, $share) : [$shop_id]; } elseif ($shop_group_id) { $list = Shop::getShops(true, $shop_group_id, true); } else { $list = Shop::getShops(true, null, true); } return $list; } /** * For the order version of prestashop. * * @param bool $use_default * * @return array */ public function getID($use_default = false) { return (!$this->id && $use_default) ? (int) Configuration::get('PS_SHOP_DEFAULT') : (int) $this->id; } /** * For the order version of prestashop. * * @return int */ public function getGroupID() { if (defined('_PS_ADMIN_DIR_')) { return Shop::getContextGroupID(); } return (int) $this->id_group_shop; } /** * Get our modules. * * @return string */ public function getOurModules() { return NewsletterProOurModules::newInstance()->get(); } /** * Clear log files. * * @return json */ public function clearLogFiles() { $response = new NewsletterProAjaxResponse([ 'msg' => '', ]); foreach (NewsletterProLog::getFiles() as $filename) { if (!NewsletterProLog::clear($filename)) { $response->addError(sprintf($this->l('The log file "%s" cannot be cleared.'), $filename)); } } if ($response->success()) { $response->set('msg', $this->l('The log files has been cleared.')); } return $response->display(); } /** * Create backup. * * @param string $name * @param bool $check_duplicate * * @return bool */ public function ajaxCreateBackup($name, $check_duplicate = true) { /** @var NewsletterProInstall */ $install = null; include _NEWSLETTER_PRO_DIR_.'/sql/install.php'; @ini_set('max_execution_time', '600'); $response = new NewsletterProAjaxResponse([ 'msg' => '', ]); try { $backup_tables = $install->getTables(); $required_config_shop = NewsletterProConfigurationShop::getAllShopsConfiguration(); $name = trim($name); if (empty($name)) { $response->addError($this->l('The name cannot be empty.')); } elseif (!NewsletterProTools::isFileName($name)) { $response->addError($this->l('Some of the name characters are not allowed.')); } if (self::BACKUP_TYPE_XML == self::getBackupType()) { $backup = new NewsletterProBackupXml(); // if the second value is true, the backup will be in hex values $backup->create($backup_tables, false); $backup->addHeader('configuration_shop', serialize($required_config_shop)); $backup->addHeader('configuration', serialize(Config::get())); $backup->addHeader('configuration_campaign', Configuration::get('NEWSLETTER_PRO_CAMPAIGN')); $bn_info = $this->getNewsletterProInfo(); $backup->addHeader('hooks', serialize($bn_info['hooks'])); $path_name = 'global/xml/'.NewsletterProBackupXml::formatName($name); if (NewsletterProBackupXml::pathNameExists($path_name, true) && $check_duplicate) { $response->addError($this->l('The backup name already exists.')); } if ($response->success()) { if (!$backup->save($path_name, false)) { $response->addError($this->l('An error occurred at the backup creation. Please check the CHMOD permissions.')); } else { $response->set('msg', $this->l('The backup has made successfully.')); } } } else { // create a global backup $backup = new NewsletterProBackupSql(); $backup->create($backup_tables); $backup->setHeader('configuration_shop', serialize($required_config_shop)); $backup->setHeader('configuration', serialize(Config::get())); $path_name = 'global/sql/'.NewsletterProBackupSql::formatName($name); if (NewsletterProBackupSql::pathNameExists($path_name, true) && $check_duplicate) { $response->addError($this->l('The backup name already exists. Try with a different name.')); } if ($response->success()) { if (!$backup->save($path_name, false)) { $response->addError($this->l('An error occurred at the backup creation. Please check the CHMOD permissions.')); } else { $response->set('msg', $this->l('The backup has made successfully.')); } } } } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } /** * Show backups. * * @return string */ public function showLoadBackup() { $tpl = $this->context->smarty->createTemplate(pqnp_template_path($this->dir_location.'views/templates/admin/global_create_backup.tpl')); return $tpl->fetch(); } /** * Get backups. * * @return json */ public function ajaxGetBackup() { $list = []; $date = []; if (self::BACKUP_TYPE_XML == self::getBackupType()) { $index = 1; foreach (NewsletterProBackupXml::getList('global/xml') as $item) { $item['id'] = $index++; $list[$index] = $item; $date[$index] = $item['m_date']; } } else { $index = 1; foreach (NewsletterProBackupSql::getList('global/sql') as $item) { $item['id'] = $index++; $list[$index] = $item; $date[$index] = $item['m_date']; } } // srot array by last modification array_multisort($date, SORT_DESC, $list); return Tools::jsonEncode($list); } /** * Delete backup. * * @param string $basename * * @return json */ public function ajaxDeleteBackup($basename) { $response = new NewsletterProAjaxResponse([ 'msg' => '', ]); if (self::BACKUP_TYPE_XML == self::getBackupType()) { $path = NewsletterProBackupXml::path().'/global/xml/'.$basename; } else { $path = NewsletterProBackupSql::path().'/global/sql/'.$basename; } if (file_exists($path)) { if (false === @unlink($path)) { $this->addError($this->l('Cannot delete the record. Please check the CHMOD permissions.')); } } else { $this->addError($this->l('The file does not exists anymore.')); } return $response->display(); } /** * Restore backup. * * @param string $basename * * @return json */ public function ajaxLoadBackup($basename) { @ini_set('max_execution_time', '600'); $response = new NewsletterProAjaxResponse([ 'msg' => '', ]); try { if (self::BACKUP_TYPE_XML == self::getBackupType()) { $backup = new NewsletterProBackupXml(); $backup->load('/global/xml/'.$basename); if (!$backup->execute()) { $response->addError($this->l('The restore process has faild.')); } else { $response->set('msg', $this->l('The backup was restored successfully.')); } } else { $backup = new NewsletterProBackupSql(); $backup->load('/global/sql/'.$basename); if (!$backup->execute()) { $response->addError($this->l('The restore process has faild.')); } else { $response->set('msg', $this->l('The backup was restored successfully.')); } } } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } /** * Get backup type. * * @return int */ public static function getBackupType() { if ('xml' == Tools::strtolower(self::BACKUP_TYPE)) { return self::BACKUP_TYPE_XML; } return self::BACKUP_TYPE_SQL; } /** * Delete the bounced emails. * * @param array $file * @param array $post * * @return json */ public function deleteBouncedEmails($file) { @ini_set('max_execution_time', 600); $response = new NewsletterProAjaxResponse([ 'msg' => '', 'lists' => [], ]); if (!Tools::isSubmit('bounced_customers_list') && !Tools::isSubmit('bounced_visitors_list') && !Tools::isSubmit('bounced_visitors_np_list') && !Tools::isSubmit('bounced_added_list')) { $response->addError($this->l('You must select at least a list before to proceed.')); } if (!$response->success()) { return $response->display(); } $bounced_method = (int) Tools::getValue('bounced_method'); $success = 0; $errors = 0; $emails_count = 0; $tables_list = []; if (Tools::isSubmit('bounced_customers_list')) { $tables_list[] = 'customers'; } if (Tools::isSubmit('bounced_visitors_list')) { $tables_list[] = 'visitors'; } if (Tools::isSubmit('bounced_visitors_np_list')) { $tables_list[] = 'visitors_np'; } if (Tools::isSubmit('bounced_added_list')) { $tables_list[] = 'added'; } $response->set('lists', $tables_list); if (isset($file)) { if (preg_match('/\.csv$/i', $file['name'])) { $validate = $this->verifyFileErros($file); if (true === $validate) { $separator = trim(Tools::getValue('bounced_csv_separator')); if (';' != $separator || ',' != $separator) { $separator = ';'; } $rows = $this->csvToArray($file['tmp_name'], $separator, 2, 0, false); foreach ($rows['rows'] as $row_array) { ++$emails_count; $email = trim($row_array[key($row_array)]); if (NewsletterProBounce::execute($email, $tables_list, $bounced_method)) { ++$success; } else { ++$errors; } } } else { $response->addError($validate); } } else { $response->addError($this->l('The file extension is not allowed. Only the .csv file extensions are allowed.')); } } else { $response->addError($this->l('You need to select the .CSV file first.')); } if ($response->success()) { $action_msg = -1 == $bounced_method ? $this->l('removed') : $this->l('unsubscribed'); $response->set('msg', $this->l(sprintf('You have %s %s from %s emails.', $action_msg, $success, $emails_count))); } return $response->display(); } public function getHistoryExclusion() { $list = []; $send = Db::getInstance()->executeS(' SELECT h.`id_newsletter_pro_tpl_history`, s.`id_newsletter_pro_send`, s.`template`, s.`date`, s.`emails_count`, s.`emails_success`, s.`emails_error` FROM `'._DB_PREFIX_.'newsletter_pro_tpl_history` h LEFT JOIN `'._DB_PREFIX_.'newsletter_pro_send` s ON (s.`id_newsletter_pro_tpl_history` = h.`id_newsletter_pro_tpl_history`) WHERE s.`active` = 0 '); $i = 0; foreach ($send as $value) { $value['type'] = 'send'; $list[$i] = $value; ++$i; } $task = Db::getInstance()->executeS(' SELECT h.`id_newsletter_pro_tpl_history`, t.`id_newsletter_pro_task`, t.`template`, t.`date_start` as `date`, t.`emails_count`, t.`emails_success`, t.`emails_error` FROM `'._DB_PREFIX_.'newsletter_pro_tpl_history` h LEFT JOIN `'._DB_PREFIX_.'newsletter_pro_task` t ON (t.`id_newsletter_pro_tpl_history` = h.`id_newsletter_pro_tpl_history`) WHERE t.`done` = 1 '); foreach ($task as $value) { $value['type'] = 'task'; $list[$i] = $value; ++$i; } usort($list, [$this, 'sortByDate']); foreach ($list as &$value) { $value['template'] = Tools::ucfirst(str_replace('_', ' ', pathinfo($value['template'], PATHINFO_FILENAME))); $value['date'] = date('Y-m-d', strtotime($value['date'])); } return Tools::jsonEncode($list); } public function addHistoryEmailsToExclusion($data, $bool_remaining_email, $bool_sent_email) { $response = NewsletterProAjaxResponse::newInstance([ 'msg' => '', 'count' => 0, ]); try { if (!$bool_remaining_email && !$bool_sent_email) { $response->addError($this->l('One of the option "Remaining email" or "Sent email" should me checked.')); return $response->display(); } if (is_array($data) && !empty($data)) { $type_send = 'send'; $ids_send = []; $ids_task = []; foreach ($data as $value) { if ($value['type'] == $type_send) { $ids_send[] = $value['id']; } else { $ids_task[] = $value['id']; } } $email_exclusion = NewsletterProEmailExclusion::newInstance(); $send_emails = $email_exclusion->getEmailsFromSend($ids_send, $bool_remaining_email, $bool_sent_email); $task_emails = $email_exclusion->getEmailsFromSend($ids_task, $bool_remaining_email, $bool_sent_email); $emails = array_merge($send_emails, $task_emails); $result = $email_exclusion->add($emails); $response->set('msg', sprintf($this->l('(%s) emails was added to exclusion list and (%s) emails already exists into exclusion list.'), $result[0], $result[1])); $response->set('count', $email_exclusion->countList()); } else { $response->addError($this->l('There are not items selected.')); } } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } public function clearExclusionEmails() { $response = NewsletterProAjaxResponse::newInstance([ 'msg' => '', ]); if (!NewsletterProEmailExclusion::newInstance()->emptyList()) { $response->addError($this->l('An error occurred.')); } else { $response->set('msg', $this->l('The exclusion emails list has been cleared.')); } return $response->display(); } public function addCsvEmailsToExclusion($file) { $response = NewsletterProAjaxResponse::newInstance([ 'msg' => '', 'count' => 0, ]); try { if (isset($file)) { if (preg_match('/\.csv$/i', $file['name'])) { $validate = $this->verifyFileErros($file); if (true === $validate) { $separator = trim(Tools::getValue('exclusion_emails_csv_separator')); if (';' != $separator || ',' != $separator) { $separator = ';'; } $rows = $this->csvToArray($file['tmp_name'], $separator, 2, 0, false); $email_exclusion = NewsletterProEmailExclusion::newInstance(); $emails = []; foreach ($rows['rows'] as $row_array) { $emails[] = trim($row_array[key($row_array)]); } $result = $email_exclusion->add($emails); $response->set('msg', sprintf($this->l('(%s) emails was added to exclusion list and (%s) emails already exists into exclusion list.'), $result[0], $result[1])); $response->set('count', $email_exclusion->countList()); } else { $response->addError($validate); } } else { $response->addError($this->l('The file extension is not allowed. Only the .csv file extensions are allowed.')); } } else { $response->addError($this->l('You need to select the .CSV file first.')); } } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } public function isSendNewsletterInProgress() { return (int) Db::getInstance()->getValue(' SELECT `id_newsletter_pro_send` FROM `'._DB_PREFIX_.'newsletter_pro_send` WHERE `id_newsletter_pro_send` = (SELECT MAX(`id_newsletter_pro_send`) FROM '._DB_PREFIX_.'newsletter_pro_send) AND `active` = 1 '); } public function resendSendHistory($id_history, $left_list = 0, $right_list_undelivered = 0) { $emails = []; $response = NewsletterProAjaxResponse::newInstance([ 'emails' => &$emails, 'id_newsletter_pro_send' => 0, 'id_history' => 0, ]); try { if (!$left_list && !$right_list_undelivered) { $response->addError($this->l('You must select at least one list before to proceed.')); return $response->display(); } $id_history = $this->getHistoryId($id_history); $response->set('id_history', (int) $id_history); if (!$id_history) { $response->addError($this->l('Invalid hisotry id.')); return $response->display(); } $id_newsletter_pro_send = (int) Db::getInstance()->getValue(' SELECT `id_newsletter_pro_send` FROM `'._DB_PREFIX_.'newsletter_pro_send` WHERE `id_newsletter_pro_tpl_history` = '.(int) $id_history.' '); $response->set('id_newsletter_pro_send', (int) $id_newsletter_pro_send); if (!$id_newsletter_pro_send) { $response->addError(sprintf($this->l('Invalid database table "%s" id.'), 'newsletter_pro_send')); return $response->display(); } $emails_to_send = []; $emails_sent_faild = []; $emails_sent_success = []; $results = Db::getInstance()->executeS(' SELECT `emails_to_send`, `emails_sent` FROM `'._DB_PREFIX_.'newsletter_pro_send_step` WHERE `id_newsletter_pro_send` = '.(int) $id_newsletter_pro_send.' ORDER BY `step` ASC '); if (!$results) { $response->addError($this->l('There are no records.')); return $response->display(); } foreach ($results as $row) { foreach (NewsletterProTools::unSerialize($row['emails_to_send']) as $email) { $emails_to_send[] = $email; } foreach (NewsletterProTools::unSerialize($row['emails_sent']) as $email_result) { if (false == (bool) $email_result['status']) { $emails_sent_faild[] = $email_result['email']; } else { $emails_sent_success[] = $email_result['email']; } } } if ($left_list) { $emails = array_merge($emails, $emails_to_send); } if ($right_list_undelivered) { $emails = array_merge($emails, $emails_sent_faild); } if (empty($emails)) { $response->addError($this->l('Cannot find any emails addresses.')); return $response->display(); } } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } private function getHistoryId($id_history) { return (int) Db::getInstance()->getValue(' SELECT `id_newsletter_pro_tpl_history` FROM `'._DB_PREFIX_.'newsletter_pro_tpl_history` WHERE `id_newsletter_pro_tpl_history` = '.(int) $id_history.' '); } public function subscribe($email, $id_lang = null, $id_shop = null) { $errors = []; $error_message = $this->l('An error occurred at the subscription.'); $id_lang = isset($id_lang) ? (int) $id_lang : (int) $this->context->language->id; $id_shop = isset($id_shop) ? (int) $id_shop : (int) $this->context->shop->id; if ($info = $this->getUserTableByEmail($email)) { $write_consent = false; foreach ($info as $value) { if (!Db::getInstance()->update($value['table'], [ $value['newsletter'] => 1, ], '`'.$value['email'].'`= "'.pSQL($email).'"')) { $errors[] = $error_message; } else { $write_consent = true; } } if ($write_consent) { NewsletterProSubscriptionConsent::newInstance()->set($email, true)->add(); } } else { // this part will not check for duplicate emails, that check is made on the upper rows if ((bool) pqnp_config('SUBSCRIPTION_ACTIVE')) { $subscriber = new NewsletterProSubscribers(); $subscriber->id_shop = (int) $id_shop; $subscriber->email = pSQL($email); $subscriber->date_add = date('Y-m-d H:i:s'); $subscriber->ip_registration_newsletter = (string) Tools::getRemoteAddr(); $subscriber->active = 1; if (!$subscriber->add()) { $errors = array_merge($errors, $subscriber->getErrors()); } else { NewsletterProSubscriptionConsent::newInstance()->set($email, true)->add(); } } else { if (NewsletterProTools::blockNewsletterExists()) { if (!Db::getInstance()->insert('newsletter', [ 'id_shop' => (int) $id_shop, 'email' => pSQL($email), 'newsletter_date_add' => date('Y-m-d H:i:s'), 'ip_registration_newsletter' => (string) Tools::getRemoteAddr(), 'active' => 1, ])) { $errors[] = $error_message; } else { NewsletterProSubscriptionConsent::newInstance()->set($email, true)->add(); } } else { if (!Db::getInstance()->insert('newsletter_pro_email', [ 'id_shop' => (int) $id_shop, 'id_lang' => (int) $id_lang, 'email' => pSQL($email), 'date_add' => date('Y-m-d H:i:s'), 'ip_registration_newsletter' => (string) Tools::getRemoteAddr(), 'active' => 1, ])) { $errors[] = $error_message; } else { NewsletterProSubscriptionConsent::newInstance()->set($email, true)->add(); } } } } // if the emails is in the forward list will be deleted because the alreay subscribed Db::getInstance()->delete('newsletter_pro_forward', '`to` = "'.pSQL($email).'"'); return $errors; } private function getUserTableByEmail($email) { $definition = [ 'customer' => ['email' => 'email', 'newsletter' => 'newsletter'], 'newsletter' => ['email' => 'email', 'newsletter' => 'active'], 'newsletter_pro_email' => ['email' => 'email', 'newsletter' => 'active'], 'newsletter_pro_subscribers' => ['email' => 'email', 'newsletter' => 'active'], ]; $info = []; foreach ($definition as $table => $fields) { if (NewsletterProTools::tableExists($table)) { $sql = 'SELECT COUNT(*) FROM `'._DB_PREFIX_.$table.'` WHERE `'.$fields['email'].'` = "'.pSQL($email).'"'; if (Db::getInstance()->getValue($sql)) { $info[] = [ 'table' => $table, 'email' => $fields['email'], 'newsletter' => $fields['newsletter'], ]; } } } return !empty($info) ? $info : false; } public function syncNewsletters($id = null, $limit = null, $get_last_id = false) { return NewsletterProSendNewsletter::newInstance()->sync($id, $limit, $get_last_id); } public function startSendNewsletters($trigger) { if ($trigger) { NewsletterProSendConnection::clearAll(); } return NewsletterProSendNewsletter::newInstance()->send(); } public function continueSendNewsletters($trigger) { $continue = $trigger ? true : false; return NewsletterProSendNewsletter::newInstance()->send($continue); } public function stopSendNewsletters() { return NewsletterProSendNewsletter::newInstance()->stop(); } public function pauseSendNewsletters() { return NewsletterProSendNewsletter::newInstance()->pause(); } public function dateMonths($id_lang = null) { if (isset($id_lang)) { $language = new Language($id_lang); if (Validate::isLoadedObject($language)) { if ('fr' == $language->iso_code) { return [ '01' => 'Janvier', '02' => 'Février', '03' => 'Mars', '04' => 'Avril', '05' => 'Mai', '06' => 'Juin', '07' => 'Juillet', '08' => 'Août', '09' => 'Septembre', '10' => 'Octobre', '11' => 'Novembre', '12' => 'Décembre', ]; } } } return [ '01' => $this->l('January'), '02' => $this->l('February'), '03' => $this->l('March'), '04' => $this->l('April'), '05' => $this->l('May'), '06' => $this->l('June'), '07' => $this->l('July'), '08' => $this->l('August'), '09' => $this->l('September'), '10' => $this->l('October'), '11' => $this->l('November'), '12' => $this->l('December'), ]; } public function jsUpdateConfiguration($name, $value) { $response = NewsletterProAjaxResponse::newInstance([]); $error = sprintf($this->l('Cannot update the configuration "%s".'), $name); if (!$name) { $response->addError($error); return $response->display(); } if (!pqnp_config($name, $value)) { $response->addError($error); } return $response->display(); } public function updateTopShortcuts($name, $value) { $response = NewsletterProAjaxResponse::newInstance([]); $page_header_toolbar = pqnp_config('PAGE_HEADER_TOOLBAR'); $name = Tools::strtoupper($name); if (!isset($page_header_toolbar[$name])) { $response->addError(sprintf($this->l('The configuration key %s does not exists.'), $name)); } else { $page_header_toolbar[$name] = $value; if (!pqnp_config('PAGE_HEADER_TOOLBAR', $page_header_toolbar)) { $response->addError($this->l('An error occurred.')); } } $response->set('page_header_toolbar', $page_header_toolbar); return $response->display(); } public function clearSendHistoryDetails() { $response = NewsletterProAjaxResponse::newInstance([]); try { $ids = Db::getInstance()->executeS(' SELECT ss.`id_newsletter_pro_send_step` FROM `'._DB_PREFIX_.'newsletter_pro_send` s LEFT JOIN `'._DB_PREFIX_.'newsletter_pro_send_step` ss ON (s.`id_newsletter_pro_send` = ss.`id_newsletter_pro_send`) WHERE `active` = 0 '); if ($ids) { foreach ($ids as $row) { $id = (int) $row['id_newsletter_pro_send_step']; $send_step = NewsletterProSendStep::newInstance($id); if (Validate::isLoadedObject($send_step)) { $send_step->updateFields([ 'emails_to_send' => null, 'emails_sent' => null, 'error_msg' => null, ]); } } } } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } public function clearTaskHistoryDetails() { $response = NewsletterProAjaxResponse::newInstance([]); try { $ids = Db::getInstance()->executeS(' SELECT ts.`id_newsletter_pro_task_step` FROM `'._DB_PREFIX_.'newsletter_pro_task` t LEFT JOIN `'._DB_PREFIX_.'newsletter_pro_task_step` ts ON (t.`id_newsletter_pro_task` = ts.`id_newsletter_pro_task`) WHERE `active` = 0 '); if ($ids) { foreach ($ids as $row) { $id = (int) $row['id_newsletter_pro_task_step']; $send_step = NewsletterProTaskStep::newInstance($id); if (Validate::isLoadedObject($send_step)) { $send_step->updateFields([ 'emails_to_send' => null, 'emails_sent' => null, ]); } } } } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } public function replaceEmbedCallback($matches) { $path = $matches[3]; if (preg_match('/data-embed=("|\')0\1/', $matches[0])) { return $matches[0]; } $swift_image = NewsletterPro_Swift_Image::fromPath($path); $this->embed_images_attachments[] = $swift_image; return $matches[1].$this->embed_images_message->embed($swift_image).$matches[4]; } public function embedImages($embed_images_message, $template) { $this->embed_images_message = $embed_images_message; // detach the previous embedded images foreach ($this->embed_images_attachments as $attachment) { $this->embed_images_message->detach($attachment); } $this->embed_images_attachments = []; // embed images // You can embed files from a URL if allow_url_fopen is on in php.ini if (pqnp_config('SEND_EMBEDED_IMAGES')) { $template = preg_replace_callback('/(]+>)/', [$this, 'replaceEmbedCallback'], $template); } return $template; } public function addFilterSelection($name, $filters) { $response = NewsletterProAjaxResponse::newInstance([]); try { $filter = NewsletterProFiltersSelection::newInstance(); $filter->name = trim($name); if (empty($filters)) { $response->addError($this->l('There are no filters selected.')); return $response->display(); } $filter->value = Tools::jsonEncode($filters); if (empty($filter->name)) { $response->addError($this->l('The filename cannot be empty.')); } elseif ($filter->nameExists()) { $response->addError(sprintf($this->l('The filter name already exists, please use a different name.'), $name)); } else { if (!$filter->save()) { $response->addError($this->l('An error occurred.')); } } } catch (Exception $e) { $response->addError($e->getMessage()); } $response->set('filters', NewsletterProFiltersSelection::getFilters()); return $response->display(); } public function deleteFilterSelection($id) { $response = NewsletterProAjaxResponse::newInstance([]); try { if (0 == (int) $id) { $this->addError($this->l('You must to select a filter.')); return $response->display(); } $filter = NewsletterProFiltersSelection::newInstance((int) $id); if (!Validate::isLoadedObject($filter)) { $this->addError($this->l('The filter does not exists anymore.')); return $response->display(); } if (!$filter->delete()) { $this->addError($this->l('An error occurred.')); } } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } public function getFilterSelectionById($id) { $response = NewsletterProAjaxResponse::newInstance(); try { if (0 == (int) $id) { $this->addError($this->l('You must to select a filter.')); return $response->display(); } $filter = NewsletterProFiltersSelection::newInstance((int) $id); $response->set('value', Tools::jsonDecode($filter->value)); } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } public function getExportOptions($value) { $response = NewsletterProAjaxResponse::newInstance(); try { switch ($value) { case self::LIST_CUSTOMERS: $columns = NewsletterProTools::getTableColumns('customer'); $response->set('columns', $columns); break; case self::LIST_VISITORS: if (!($table_name = NewsletterProDefaultNewsletterTable::getTableName())) { throw new Exception($this->l('The table does not exists.')); } $columns = NewsletterProTools::getTableColumns($table_name); $response->set('columns', $columns); break; case self::LIST_VISITORS_NP: $columns = NewsletterProTools::getTableColumns('newsletter_pro_subscribers'); $response->set('columns', $columns); break; case self::LIST_ADDED: $columns = NewsletterProTools::getTableColumns('newsletter_pro_email'); $response->set('columns', $columns); break; default: throw new Exception($this->l('Invalid list id.')); break; } } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } public function openLogFIle($href) { $response = NewsletterProAjaxResponse::newInstance([ 'content' => '', ]); try { $basename = pathinfo($href, PATHINFO_BASENAME); $filename = $this->dir_location.'logs/'.$basename; if (!file_exists($filename)) { throw new Exception(sprintf($this->l('The filename %s does not exists.'), $basename)); } $content = Tools::file_get_contents($filename); $response->set('content', $content); } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } public static function getSearchConstions() { $module = NewsletterPro::getInstance(); return [ self::SEARCH_CONDITION_CONTAINS => $module->l('contains'), self::SEARCH_CONDITION_IS => $module->l('is equal'), self::SEARCH_CONDITION_IS_NOT => $module->l('is not equal'), self::SEARCH_CONDITION_GREATER => $module->l('is equal or grater than'), self::SEARCH_CONDITION_LESS => $module->l('is equal or less than'), ]; } public static function getSearchConstionsJs() { return [ 'SEARCH_CONDITION_CONTAINS' => self::SEARCH_CONDITION_CONTAINS, 'SEARCH_CONDITION_IS' => self::SEARCH_CONDITION_IS, 'SEARCH_CONDITION_IS_NOT' => self::SEARCH_CONDITION_IS_NOT, 'SEARCH_CONDITION_GREATER' => self::SEARCH_CONDITION_GREATER, 'SEARCH_CONDITION_LESS' => self::SEARCH_CONDITION_LESS, ]; } public function getMaxTotalSpent() { return ceil((float) Db::getInstance()->getValue(' SELECT MAX((SELECT SUM(`total_paid_real` / `conversion_rate`) FROM `'._DB_PREFIX_.'orders` WHERE `id_customer` = c.`id_customer`)) as `total_spent` FROM `'._DB_PREFIX_.'customer` c '.((bool) pqnp_config('VIEW_ACTIVE_ONLY') ? ' WHERE c.`newsletter` = 1 ' : '').' ')); /* return ceil((float)Db::getInstance()->getValue(' SELECT MAX(o.`total_paid_real` / o.`conversion_rate`) as total_spent FROM `'._DB_PREFIX_.'orders` o LEFT JOIN `'._DB_PREFIX_.'customer` c ON (c.id_customer = o.id_customer) WHERE 1 ')); */ } private function getCountriesSql($search = null) { return ' SELECT c.`id_country`, cl.`name`, c.`iso_code`, c.`active` FROM `'._DB_PREFIX_.'country` c INNER JOIN `'._DB_PREFIX_.'country_lang` cl ON (c.id_country = cl.id_country) AND cl.`id_lang` = '.(int) $this->context->language->id.' '.(isset($search) ? ' AND (cl.`name` LIKE "%'.pSQL($search).'%" OR c.`iso_code` LIKE "%'.pSQL($search).'%")' : '').' '.((int) pqnp_ini_config('filter_only_active_countries') ? ' AND c.`active` = 1 ' : '').' ORDER BY cl.`name` ASC '; } public function getCountries() { return Tools::jsonEncode(Db::getInstance()->executeS($this->getCountriesSql())); } public function searchCountries($value) { return Tools::jsonEncode(Db::getInstance()->executeS($this->getCountriesSql($value))); } public function deleteProductTemplate($path) { $response = NewsletterProAjaxResponse::newInstance(); if ((int) pqnp_ini_config('demo_mode')) { $demo_return = NewsletterProDemoMode::deleteProductTemplate($path); if ($demo_return) { return $demo_return; } } try { if (file_exists($path)) { if (!unlink($path)) { throw new Exception($this->l('The template cannot be delete. Please checked the CHMOD permissions.')); } } } catch (Exception $e) { $response->addError($e->getMessage()); } return $response->display(); } public function hookActionDeleteGDPRCustomer($customer) { if (!empty($customer['email']) && Validate::isEmail($customer['email'])) { $privacy_data = new NewsletterProPrivacyData(); $response = $privacy_data->hookActionDelete($customer['email']); if (true === $response) { return Tools::jsonEncode(true); } return Tools::jsonEncode($this->l('Newsletter Pro : Unable to delete the customer personal data.')); } } public function hookActionExportGDPRData($customer) { if (!Tools::isEmpty($customer['email']) && Validate::isEmail($customer['email'])) { $privacy_data = new NewsletterProPrivacyData(); $response = $privacy_data->export($customer['email']); if (count($response['errors']) > 0) { return Tools::jsonEncode($this->l('Newsletter Pro : Unable to export the customer personal data.')); } if (count($response['data']) > 0) { return Tools::jsonEncode($response['data']); } } } public function hookDisplayCustomerIdentityForm($params = []) { return $this->hookDisplayCustomerAccountForm($params); } public function hookDisplayCustomerAccountForm($params = []) { $list_of_interest = NewsletterProListOfInterest::getListActiveCustomer((int) $this->context->customer->id); $this->context->smarty->assign([ 'list_of_interest' => $list_of_interest, 'customer_account_subscribe_by_loi_active' => (bool) pqnp_config('CUSTOMER_ACCOUNT_SUBSCRIBE_BY_LOI'), ]); if (NewsletterProTools::hasTemplatePath($this->dir_location.'views/templates/hook/display_customer_account_form.tpl')) { return $this->context->smarty->fetch(NewsletterProTools::loadTemplatePath($this->dir_location.'views/templates/hook/display_customer_account_form.tpl')); } return $this->context->smarty->fetch($this->dir_location.'views/templates/hook/'.NewsletterProTools::getVersion().'/display_customer_account_form.tpl'); } public function hookActionCustomerAccountAdd($params = []) { $this->hookCreateAccount($params); $this->customerAccountSaveListOfInterest(); } public function hookAdditionalCustomerFormFields($params) { if (version_compare(_PS_VERSION_, '1.7.0.1', '>=')) { $label = $this->trans( 'Sign up for our newsletter[1][2]%conditions%[/2]', [ '[1]' => '
', '[2]' => '', '%conditions%' => 'You may unsubscribe at any moment. For that purpose, please find our contact info in the legal notice.', '[/2]' => '', ], 'Modules.Newsletterpro.Shop' ); return [ (new FormField()) ->setName('pqnp_newsletter') ->setType('checkbox') ->setLabel($label), ]; } } public function hookActionCustomerAccountUpdate($params = []) { $this->customerAccountSaveListOfInterest(); } private function customerAccountSaveListOfInterest() { if ((bool) pqnp_config('CUSTOMER_ACCOUNT_SUBSCRIBE_BY_LOI')) { $list_of_interest = $this->request->get('pqnp_list_of_interest', []); $customer_loi = NewsletterProCustomerListOfInterests::getInstanceByCustomerId((int) $this->context->customer->id); if (!empty($list_of_interest)) { $customer_loi->setCategories($list_of_interest); $customer_loi->id_customer = (int) $this->context->customer->id; if (!$customer_loi->save()) { $this->context->controller->errors[] = $this->l('Error on updating the list of interests.'); } else { $subscriber = NewsletterProSubscribers::getInstanceByEmail($this->context->customer->email, (int) $this->context->shop->id); if (Validate::isLoadedObject($subscriber)) { $subscriber->setListOfInterest($list_of_interest); $subscriber->update(); } } } else { if (Validate::isLoadedObject($customer_loi)) { $customer_loi->setCategories([]); $customer_loi->update(); } } } } }