* @copyright 2007-2014 PrestaShop SA * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) * International Registered Trademark & Property of PrestaShop SA */ if (!defined('_PS_VERSION_')) exit; class Followup extends Module { private static $cancelled_cart_min_amount_order = 30; public function __construct() { $this->name = 'followup'; $this->tab = 'advertising_marketing'; $this->version = '1.6.2'; $this->author = 'PrestaShop'; $this->need_instance = 0; $this->conf_keys = array( 'PS_FOLLOW_UP_ENABLE_1', 'PS_FOLLOW_UP_ENABLE_2', 'PS_FOLLOW_UP_ENABLE_3', 'PS_FOLLOW_UP_ENABLE_4', 'PS_FOLLOW_UP_ENABLE_5', 'PS_FOLLOW_UP_AMOUNT_1', 'PS_FOLLOW_UP_AMOUNT_2', 'PS_FOLLOW_UP_AMOUNT_3', 'PS_FOLLOW_UP_AMOUNT_4', 'PS_FOLLOW_UP_AMOUNT_5', 'PS_FOLLOW_UP_DAYS_1', 'PS_FOLLOW_UP_DAYS_2', 'PS_FOLLOW_UP_DAYS_3', 'PS_FOLLOW_UP_DAYS_4', 'PS_FOLLOW_UP_DAYS_5', 'PS_FOLLOW_UP_MIN_5', 'PS_FOLLOW_UP_THRESHOLD_3', 'PS_FOLLOW_UP_DAYS_THRESHOLD_4', 'PS_FOLLOW_UP_CLEAN_DB' ); $this->bootstrap = true; parent::__construct(); $secure_key = Configuration::get('PS_FOLLOWUP_SECURE_KEY'); if($secure_key === false) Configuration::updateValue('PS_FOLLOWUP_SECURE_KEY', Tools::strtoupper(Tools::passwdGen(16))); $this->displayName = $this->l('Customer follow-up'); $this->description = $this->l('Follow-up with your customers with daily customized e-mails.'); $this->confirmUninstall = $this->l('Are you sure you want to delete all settings and your logs?'); } public function install() { Db::getInstance()->execute(' CREATE TABLE '._DB_PREFIX_.'log_email ( `id_log_email` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , `id_email_type` INT UNSIGNED NOT NULL , `id_cart_rule` INT UNSIGNED NOT NULL , `id_customer` INT UNSIGNED NULL , `id_cart` INT UNSIGNED NULL , `date_add` DATETIME NOT NULL, INDEX `date_add`(`date_add`), INDEX `id_cart`(`id_cart`) ) ENGINE='._MYSQL_ENGINE_); foreach ($this->conf_keys as $key) Configuration::updateValue($key, 0); return parent::install(); } public function uninstall() { foreach ($this->conf_keys as $key) Configuration::deleteByName($key); Configuration::deleteByName('PS_FOLLOWUP_SECURE_KEY'); Db::getInstance()->execute('DROP TABLE '._DB_PREFIX_.'log_email'); return parent::uninstall(); } public function getContent() { $html = ''; /* @Override */ if (Tools::isSubmit('sendMailTest')){ $email = Tools::getValue('email_test'); $id_email = Tools::getValue('id_email_test'); $this->_sendMailTest($id_email, $email); } if (Tools::isSubmit('flw_export')){ $this->_processExport(Tools::getValue('id_export_type')); } /* @End Override */ /* Save settings */ if (Tools::isSubmit('submitFollowUp')) { $ok = true; foreach ($this->conf_keys as $c) if(Tools::getValue($c) !== false) // Prevent saving when URL is wrong $ok &= Configuration::updateValue($c, (float)Tools::getValue($c)); if ($ok) $html .= $this->displayConfirmation($this->l('Settings updated succesfully')); else $html .= $this->displayError($this->l('Error occurred during settings update')); } $html .= $this->renderForm(); $html .= $this->renderStats(); return $html; } /* Log each sent e-mail */ private function logEmail($id_email_type, $id_cart_rule, $id_customer = null, $id_cart = null) { $values = array( 'id_email_type' => (int)$id_email_type, 'id_cart_rule' => (int)$id_cart_rule, 'date_add' => date('Y-m-d H:i:s') ); if (!empty($id_cart)) $values['id_cart'] = (int)$id_cart; if (!empty($id_customer)) $values['id_customer'] = (int)$id_customer; Db::getInstance()->insert('log_email', $values); } public static function getIdProductOfAllActiveSale() { include_once(dirname(__FILE__).'../../privatesales/models/SaleCore.php'); $sales = SaleCore::getSales(SaleCore::STATE_CURRENT); $ids_products = array(); foreach($sales as $sale) { $ids_products = array_merge($ids_products, $sale->getProducts()); } return $ids_products; } /* Each cart which wasn't transformed into an order */ private function cancelledCart($count = false) { $ids_products = self::getIdProductOfAllActiveSale(); if(count($ids_products) == 0) return 0; /*$email_logs = $this->getLogsEmail(1); $sql = ' SELECT DISTINCT c.id_cart, c.id_lang, cu.id_default_group, cu.id_customer, c.id_shop, cu.firstname, cu.lastname, cu.email FROM '._DB_PREFIX_.'cart c LEFT JOIN '._DB_PREFIX_.'orders o ON (o.id_cart = c.id_cart) RIGHT JOIN '._DB_PREFIX_.'customer cu ON (cu.id_customer = c.id_customer) RIGHT JOIN '._DB_PREFIX_.'cart_product cp ON (cp.id_cart = c.id_cart AND cp.id_product IN ('.implode(',', $ids_products).')) WHERE 1 AND DATE_SUB(NOW(),INTERVAL 9 DAY) <= c.date_upd AND DATE_SUB(NOW(),INTERVAL 1 DAY) >= c.date_upd AND o.id_order IS NULL';*/ $sql = ' SELECT DISTINCT c.id_cart, c.id_lang, cu.id_default_group, cu.id_customer, c.id_shop, cu.firstname, cu.lastname, cu.email FROM '._DB_PREFIX_.'cart c LEFT JOIN '._DB_PREFIX_.'orders o ON (o.id_cart = c.id_cart) LEFT JOIN `'._DB_PREFIX_.'log_email` le ON (le.`id_cart` = c.`id_cart` AND le.`id_email_type` = 1) RIGHT JOIN '._DB_PREFIX_.'customer cu ON (cu.id_customer = c.id_customer) RIGHT JOIN '._DB_PREFIX_.'cart_product cp ON (cp.id_cart = c.id_cart AND cp.id_product IN ('.implode(',', $ids_products).')) WHERE 1 -- AND DATE_SUB(NOW(),INTERVAL 9 DAY) <= c.date_add -- AND DATE_SUB(NOW(),INTERVAL 1 DAY) >= c.date_add AND DATE_SUB(NOW(),INTERVAL 5 HOUR) <= c.date_upd AND DATE_SUB(NOW(),INTERVAL 3 HOUR) >= c.date_upd AND le.`id_log_email` IS NULL AND o.id_order IS NULL'; $sql .= Shop::addSqlRestriction(Shop::SHARE_CUSTOMER, 'c'); /*if (!empty($email_logs)){ $sql .= ' AND c.id_cart NOT IN ('.join(',', $email_logs).')'; }*/ $sql .= ' LIMIT 100'; $emails = Db::getInstance()->executeS($sql); if ($count || !count($emails)){ return count($emails); } $order_url = Context::getContext()->link->getPageLink('order.php', true, Context::getContext()->language->id, null, false); $shop_url = Context::getContext()->link->getPageLink('index', true, Context::getContext()->language->id, null, false); $img_url = $shop_url.'themes/'._THEME_NAME_.'/img/'; // ticket 12164 : remove conf 'PS_FOLLOW_UP_AMOUNT_1' loading, never used here $conf = Configuration::getMultiple(array('PS_FOLLOW_UP_DAYS_1')); //$conf = Configuration::getMultiple(array('PS_FOLLOW_UP_AMOUNT_1', 'PS_FOLLOW_UP_DAYS_1')); foreach ($emails as $email) { // $voucher = $this->createDiscount(1, (float)$conf['PS_FOLLOW_UP_AMOUNT_1'], (int)$email['id_customer'], strftime('%Y-%m-%d', strtotime('+'.(int)$conf['PS_FOLLOW_UP_DAYS_1'].' day')), $this->l('Discount for your cancelled cart')); // if ($voucher !== false) // { //AJOUT 20-01-2015 //Get cart $cart = new Cart(intval($email['id_cart'])); $products = $cart->getProducts(true); $price_display_method = Group::getPriceDisplayMethod($email['id_default_group']); $cartHtml = ''; // if (Product::getTaxCalculationMethod()) // $product['is_discounted'] = $product['price_without_specific_price'] != $product['price']; // else // $product['is_discounted'] = $product['price_without_specific_price'] != $product['price_wt']; //Création du panier $cart_product_context = Context::getContext()->cloneContext(); $cart_product_context->customer = new Customer($cart->id_customer); $cart_product_context->cart = $cart; if ($cart_product_context->shop->id != $cart->id_shop) { $cart_product_context->shop = new Shop((int)$cart->id_shop); } $cartText = ''; foreach($products as $product) { $cover = Product::getCover($product['id_product']); $product['id_image'] = $cover['id_image']; $imagePath = Context::getContext()->link->getImageLink($product['link_rewrite'], $product['id_image'], 'block_cart'); // change the last parameters to get the size you need $imagePath = str_replace('https:', 'http:', $imagePath); if (!preg_match("/^(http):/", $imagePath)) { $imagePath = 'http://'.$imagePath; } if(!empty($cartHtml)) { $cartHtml .= '
 
'; } $hack = ''; $product['price_without_specific_price'] = Product::getPriceStatic( (int)$product['id_product'], !$price_display_method, $product['id_product_attribute'], 6, null, false, false, 1, false, null, null, null, $hack, true, true, $cart_product_context ); $price = !$price_display_method ? $product['price_wt'] : $product['price']; $cartHtml .= ' '.$product['legend'].' '.$product['name'].' '.Tools::displayPrice($price, (int)$cart->id_currency).' '.(!$price_display_method ? $this->l('TTC') : $this->l('HT') ).' '; if(!empty($product['price_without_specific_price']) && $product['price_without_specific_price'] != $price) $cartHtml .= ''.$this->l('au lieu de').' '. Tools::displayPrice($product['price_without_specific_price'], (int)$cart->id_currency).' '; $cartHtml .= '

'.$this->l('Finaliser ma').'
'.$this->l('commande').'

'; // '.$product['cart_quantity'].' $cartText .= $product['name'].' - qté : '.$product['cart_quantity']."\n\r"; } //FIN AJOUT $template_vars = array( '{email}' => $email['email'], '{lastname}' => $email['lastname'], '{firstname}' => $email['firstname'], // ticket 12164 : remove conf loading, never used here //'{amount}' => $conf['PS_FOLLOW_UP_AMOUNT_1'], '{days}' => $conf['PS_FOLLOW_UP_DAYS_1'], // '{voucher_num}' => $voucher->code, '{cartHtml}' => $cartHtml, '{cartText}' => $cartText ); // coppee@antadis.com // Mail::Send((int)$email['id_lang'], 'followup_1', Mail::l('Ne manquez pas les ventes privilégiées que vous aviez sélectionnées, validez votre panier!', (int)$email['id_lang']), $template_vars, 'coppee@antadis.com', $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); // marion@antadis.com // Mail::Send((int)$email['id_lang'], 'followup_H3', Mail::l('Ne manquez pas les ventes privilégiées que vous aviez sélectionnées, validez votre panier!', (int)$email['id_lang']), $template_vars, 'marion@antadis.com', $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); // clefebvre@privilegedemarque.com // Mail::Send((int)$email['id_lang'], 'followup_1', Mail::l('Ne manquez pas les ventes privilégiées que vous aviez sélectionnées, validez votre panier!', (int)$email['id_lang']), $template_vars, 'clefebvre@privilegedemarque.com', $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); Mail::Send((int)$email['id_lang'], 'followup_H3', Mail::l('Ne manquez pas les ventes privilégiées que vous aviez sélectionnées, validez votre panier!', (int)$email['id_lang']), $template_vars, $email['email'], $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); // $this->logEmail(1, (int)$voucher->id, (int)$email['id_customer'], (int)$email['id_cart']); $this->logEmail(1, 0, (int)$email['id_customer'], (int)$email['id_cart']); // } } } private function cancelledCartRecall($count = false){ $ids_products = self::getIdProductOfAllActiveSale(); if(count($ids_products) == 0) return 0; /*$sql = ' SELECT DISTINCT c.id_cart, c.id_lang, cu.id_customer, cu.id_default_group, c.id_shop, cu.firstname, cu.lastname, cu.email FROM '._DB_PREFIX_.'cart c LEFT JOIN '._DB_PREFIX_.'orders o ON (o.id_cart = c.id_cart) LEFT JOIN `'._DB_PREFIX_.'log_email` le1 ON (le1.`id_cart` = c.`id_cart` AND le1.`id_email_type` = 1 AND le1.`id_cart_rule` = 0) LEFT JOIN `'._DB_PREFIX_.'log_email` le5 ON (le5.`id_cart` = c.`id_cart` AND le5.`id_email_type` = 5) RIGHT JOIN '._DB_PREFIX_.'customer cu ON (cu.id_customer = c.id_customer) RIGHT JOIN '._DB_PREFIX_.'cart_product cp ON (cp.id_cart = c.id_cart AND cp.id_product IN ('.implode(',', $ids_products).')) WHERE 1 AND DATE_SUB(NOW(),INTERVAL 9 DAY) <= c.date_upd AND le1.`id_log_email` IS NOT NULL AND DATE_SUB(NOW(),INTERVAL 2 DAY) >= le1.`date_add` AND le5.`id_log_email` IS NULL AND o.id_order IS NULL';*/ // a verifier pour Si le client n'a pas déjà reçu cette relance pour ce panier // a verifier Si le client n'a pas déjà reçu cette relance (quelque soit le panier) dans les 2 mois d'avant $sql = ' SELECT DISTINCT c.id_cart, c.id_lang, cu.id_customer, cu.id_default_group, c.id_shop, cu.firstname, cu.lastname, cu.email FROM '._DB_PREFIX_.'cart c LEFT JOIN '._DB_PREFIX_.'orders o ON (o.id_cart = c.id_cart) LEFT JOIN '._DB_PREFIX_.'log_email le1 ON (le1.id_cart = c.id_cart AND le1.id_email_type = 1 AND le1.id_cart_rule = 0) LEFT JOIN '._DB_PREFIX_.'log_email le5 ON (le5.id_cart = c.id_cart AND le5.id_customer = c.id_customer AND le5.id_email_type = 5 ) RIGHT JOIN '._DB_PREFIX_.'customer cu ON (cu.id_customer = c.id_customer) RIGHT JOIN '._DB_PREFIX_.'cart_product cp ON (cp.id_cart = c.id_cart AND cp.id_product IN ('.implode(',', $ids_products).')) WHERE 1 AND le1.`id_log_email` IS NOT NULL AND o.id_order IS NULL AND DATE_SUB(NOW(),INTERVAL 25 HOUR) <= c.date_upd AND DATE_SUB(NOW(),INTERVAL 23 HOUR) >= c.date_upd AND le5.`id_log_email` IS NULL AND ( DATE_SUB(NOW(),INTERVAL 2 MONTH) > ( SELECT IF (MAX(le.`date_add`), MAX(le.`date_add`), "0000-00-00 00:00:00") FROM '._DB_PREFIX_.'log_email le WHERE le.id_email_type = 5 AND le.id_customer = cu.id_customer ) )'; $emails = Db::getInstance()->executeS($sql); if ($count || !count($emails)) return count($emails); $order_url = Context::getContext()->link->getPageLink('order.php', true, Context::getContext()->language->id, null, false); $shop_url = Context::getContext()->link->getPageLink('index', true, Context::getContext()->language->id, null, false); $img_url = $shop_url.'themes/'._THEME_NAME_.'/img/'; $conf = Configuration::getMultiple(array('PS_FOLLOW_UP_AMOUNT_5', 'PS_FOLLOW_UP_DAYS_5', 'PS_FOLLOW_UP_MIN_5')); foreach ($emails as $email) { // Ajout 22-10-2015 // Get cart $cart = new Cart(intval($email['id_cart'])); $totalWithoutShipping = floatval($cart->getOrderTotal(true, Cart::BOTH_WITHOUT_SHIPPING)); if ($totalWithoutShipping < self::$cancelled_cart_min_amount_order) { continue; } // $voucher = $this->createDiscount(1, (float)$conf['PS_FOLLOW_UP_AMOUNT_5'], (int)$email['id_customer'], strftime('%Y-%m-%d', strtotime('+'.(int)$conf['PS_FOLLOW_UP_DAYS_5'].' day')), $this->l('Discount for your cancelled cart')); $voucher = $this->createAdvancedDiscount(1, (float)$conf['PS_FOLLOW_UP_AMOUNT_5'], 0, (int)$email['id_customer'], strftime('%Y-%m-%d', strtotime('+'.(int)$conf['PS_FOLLOW_UP_DAYS_5'].' day')), $this->l('Discount for your cancelled cart'), 0, (int)$conf['PS_FOLLOW_UP_MIN_5']); if ($voucher !== false) { //AJOUT 20-01-2015 //Get cart // $cart = new Cart(intval($email['id_cart'])); $products = $cart->getProducts(true); $price_display_method = Group::getPriceDisplayMethod($email['id_default_group']); $cartHtml = ''; //Création du panier $cart_product_context = Context::getContext()->cloneContext(); $cart_product_context->customer = new Customer($cart->id_customer); $cart_product_context->cart = $cart; if ($cart_product_context->shop->id != $cart->id_shop) { $cart_product_context->shop = new Shop((int)$cart->id_shop); } $cartText = ''; foreach($products as $product) { $cover = Product::getCover($product['id_product']); $product['id_image'] = $cover['id_image']; $imagePath = Context::getContext()->link->getImageLink($product['link_rewrite'], $product['id_image'], 'block_cart'); // change the last parameters to get the size you need $imagePath = str_replace('https:', 'http:', $imagePath); if (!preg_match("/^(http):/", $imagePath)) { $imagePath = 'http://'.$imagePath; } if(!empty($cartHtml)) { $cartHtml .= '
 
'; } $hack = ''; $product['price_without_specific_price'] = Product::getPriceStatic( (int)$product['id_product'], !$price_display_method, $product['id_product_attribute'], 6, null, false, false, 1, false, null, null, null, $hack, true, true, $cart_product_context ); $price = !$price_display_method ? $product['price_wt'] : $product['price']; $cartHtml .= ' '.$product['legend'].' '.$product['name'].' '.Tools::displayPrice($price, (int)$cart->id_currency).' '.(!$price_display_method ? $this->l('TTC') : $this->l('HT') ).' '; if(!empty($product['price_without_specific_price']) && $product['price_without_specific_price'] != $price) $cartHtml .= ''.$this->l('au lieu de').' '. Tools::displayPrice($product['price_without_specific_price'], (int)$cart->id_currency).' '; $cartHtml .= '

'.$this->l('Finaliser ma').'
'.$this->l('commande').'

'; // '.$product['cart_quantity'].' $cartText .= $product['name'].' - qté : '.$product['cart_quantity']."\n\r"; } //FIN AJOUT $template_vars = array( '{email}' => $email['email'], '{lastname}' => $email['lastname'], '{firstname}' => $email['firstname'], '{amount}' => $conf['PS_FOLLOW_UP_AMOUNT_5'], '{days}' => $conf['PS_FOLLOW_UP_DAYS_5'], '{voucher_num}' => $voucher->code, '{cartHtml}' => $cartHtml, '{cartText}' => $cartText ); // coppee@antadis.com // Mail::Send((int)$email['id_lang'], 'followup_1', Mail::l('Ne manquez pas les ventes privilégiées que vous aviez sélectionnées, validez votre panier!', (int)$email['id_lang']), $template_vars, 'coppee@antadis.com', $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); // marion@antadis.com // Mail::Send((int)$email['id_lang'], 'followup_H24', Mail::l('Ne manquez pas les ventes privilégiées que vous aviez sélectionnées, validez votre panier!', (int)$email['id_lang']), $template_vars, 'marion@antadis.com', $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); // clefebvre@privilegedemarque.com // Mail::Send((int)$email['id_lang'], 'followup_1', Mail::l('Ne manquez pas les ventes privilégiées que vous aviez sélectionnées, validez votre panier!', (int)$email['id_lang']), $template_vars, 'clefebvre@privilegedemarque.com', $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); Mail::Send((int)$email['id_lang'], 'followup_H24', Mail::l('Ne manquez pas les ventes privilégiées que vous aviez sélectionnées, validez votre panier!', (int)$email['id_lang']), $template_vars, $email['email'], $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); $this->logEmail(5, (int)$voucher->id, (int)$email['id_customer'], (int)$email['id_cart']); } } } private function getLogsEmail($email_type) { static $id_list = array( '1' => array(), '2' => array(), '3' => array(), '4' => array(), '5' => array(), ); static $executed = false; if (!$executed) { $query = ' SELECT id_cart, id_customer, id_email_type FROM '._DB_PREFIX_.'log_email WHERE id_email_type <> 4 OR date_add >= DATE_SUB(date_add,INTERVAL '.(int)Configuration::get('PS_FOLLOW_UP_DAYS_THRESHOLD_4').' DAY)'; $results = Db::getInstance()->executeS($query); foreach ($results as $line) { switch ($line['id_email_type']) { case 1: $id_list['1'][] = $line['id_cart']; break; case 2: $id_list['2'][] = $line['id_cart']; break; case 3: $id_list['3'][] = $line['id_customer']; break; case 4: $id_list['4'][] = $line['id_customer']; break; case 5: $id_list['5'][] = $line['id_cart']; break; } } $executed = true; } return $id_list[$email_type]; } /* For all validated orders, a discount if re-ordering before x days */ private function reOrder($count = false) { $email_logs = $this->getLogsEmail(2); $sql = ' SELECT o.id_order, c.id_cart, o.id_lang, o.id_shop, cu.id_customer, cu.firstname, cu.lastname, cu.email FROM '._DB_PREFIX_.'orders o LEFT JOIN '._DB_PREFIX_.'customer cu ON (cu.id_customer = o.id_customer) LEFT JOIN '._DB_PREFIX_.'cart c ON (c.id_cart = o.id_cart) WHERE o.valid = 1 AND c.date_add >= DATE_SUB(CURDATE(),INTERVAL 7 DAY) AND cu.is_guest = 0'; $sql .= Shop::addSqlRestriction(Shop::SHARE_CUSTOMER, 'o'); if (!empty($email_logs)) $sql .= ' AND o.id_cart NOT IN ('.join(',', $email_logs).')'; $emails = Db::getInstance()->executeS($sql); if ($count || !count($emails)) return count($emails); $conf = Configuration::getMultiple(array('PS_FOLLOW_UP_AMOUNT_2', 'PS_FOLLOW_UP_DAYS_2')); foreach ($emails as $email) { $voucher = $this->createDiscount(2, (float)$conf['PS_FOLLOW_UP_AMOUNT_2'], (int)$email['id_customer'], strftime('%Y-%m-%d', strtotime('+'.(int)$conf['PS_FOLLOW_UP_DAYS_2'].' day')), $this->l('Thank you for your order.')); if ($voucher !== false) { $template_vars = array( '{email}' => $email['email'], '{lastname}' => $email['lastname'], '{firstname}' => $email['firstname'], '{amount}' => $conf['PS_FOLLOW_UP_AMOUNT_2'], '{days}' => $conf['PS_FOLLOW_UP_DAYS_2'], '{voucher_num}' => $voucher->code ); $object = "Bénéficiez de ".$conf['PS_FOLLOW_UP_AMOUNT_2'].".% sur votre prochaine commande, profitez-en dès à présent!"; Mail::Send((int)$email['id_lang'], 'followup_2', $object, $template_vars, $email['email'], $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); $this->logEmail(2, (int)$voucher->id, (int)$email['id_customer'], (int)$email['id_cart']); } } } /* For all customers with more than x euros in 90 days */ private function bestCustomer($count = false) { $email_logs = $this->getLogsEmail(3); $sql = ' SELECT SUM(o.total_paid) total, c.id_cart, o.id_lang, cu.id_customer, cu.id_shop, cu.firstname, cu.lastname, cu.email FROM '._DB_PREFIX_.'orders o LEFT JOIN '._DB_PREFIX_.'customer cu ON (cu.id_customer = o.id_customer) LEFT JOIN '._DB_PREFIX_.'cart c ON (c.id_cart = o.id_cart) WHERE o.valid = 1 AND DATE_SUB(CURDATE(),INTERVAL 90 DAY) <= o.date_add AND cu.is_guest = 0 '; $sql .= Shop::addSqlRestriction(Shop::SHARE_CUSTOMER, 'o'); if (!empty($email_logs)) $sql .= ' AND cu.id_customer NOT IN ('.join(',', $email_logs).') '; $sql .= ' GROUP BY o.id_customer HAVING total >= '.(float)Configuration::get('PS_FOLLOW_UP_THRESHOLD_3'); $emails = Db::getInstance()->executeS($sql); if ($count || !count($emails)) return count($emails); $conf = Configuration::getMultiple(array('PS_FOLLOW_UP_AMOUNT_3', 'PS_FOLLOW_UP_DAYS_3')); foreach ($emails as $email) { $voucher = $this->createDiscount(3, (float)$conf['PS_FOLLOW_UP_AMOUNT_3'], (int)$email['id_customer'], strftime('%Y-%m-%d', strtotime('+'.(int)$conf['PS_FOLLOW_UP_DAYS_3'].' day')), $this->l('You are one of our best customers!')); if ($voucher !== false) { $template_vars = array( '{email}' => $email['email'], '{lastname}' => $email['lastname'], '{firstname}' => $email['firstname'], '{amount}' => $conf['PS_FOLLOW_UP_AMOUNT_3'], '{days}' => $conf['PS_FOLLOW_UP_DAYS_3'], '{voucher_num}' => $voucher->code ); $object = "Nous vous offrons ".$conf['PS_FOLLOW_UP_AMOUNT_3']."% pour votre fidélité privilégiée."; Mail::Send((int)$email['id_lang'], 'followup_3',$object, $template_vars, $email['email'], $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); $this->logEmail(3, (int)$voucher->id, (int)$email['id_customer'], (int)$email['id_cart']); } } } /* For all customers with no orders since more than x days */ /** * badCustomer send mails to all customers with no orders since more than x days, * with at least one valid order in history * * @param boolean $count if set to true, will return number of customer (default : false, will send mails, no return value) * * @return void */ private function badCustomer($count = false) { $email_logs = $this->getLogsEmail(4); $sql = ' SELECT o.id_lang, c.id_cart, cu.id_customer, cu.id_shop, cu.firstname, cu.lastname, cu.email, (SELECT COUNT(o.id_order) FROM '._DB_PREFIX_.'orders o WHERE o.id_customer = cu.id_customer and o.valid = 1) nb_orders FROM '._DB_PREFIX_.'customer cu LEFT JOIN '._DB_PREFIX_.'orders o ON (o.id_customer = cu.id_customer) LEFT JOIN '._DB_PREFIX_.'cart c ON (c.id_cart = o.id_cart) WHERE cu.id_customer NOT IN (SELECT o.id_customer FROM '._DB_PREFIX_.'orders o WHERE DATE_SUB(CURDATE(),INTERVAL '.(int)Configuration::get('PS_FOLLOW_UP_DAYS_THRESHOLD_4').' DAY) <= o.date_add) AND cu.is_guest = 0 '; $sql .= Shop::addSqlRestriction(Shop::SHARE_CUSTOMER, 'cu'); if (!empty($email_logs)) $sql .= ' AND cu.id_customer NOT IN ('.join(',', $email_logs).') '; $sql .= ' GROUP BY cu.id_customer HAVING nb_orders >= 1'; $emails = Db::getInstance()->executeS($sql); if ($count || !count($emails)) return count($emails); $conf = Configuration::getMultiple(array('PS_FOLLOW_UP_AMOUNT_4', 'PS_FOLLOW_UP_DAYS_4')); foreach ($emails as $email) { $voucher = $this->createDiscount(4, (float)$conf['PS_FOLLOW_UP_AMOUNT_4'], (int)$email['id_customer'], strftime('%Y-%m-%d', strtotime('+'.(int)$conf['PS_FOLLOW_UP_DAYS_4'].' day')), $this->l('We miss you!')); if ($voucher !== false) { $template_vars = array( '{email}' => $email['email'], '{lastname}' => $email['lastname'], '{firstname}' => $email['firstname'], '{amount}' => $conf['PS_FOLLOW_UP_AMOUNT_4'], '{days}' => $conf['PS_FOLLOW_UP_DAYS_4'], '{days_threshold}' => (int)Configuration::get('PS_FOLLOW_UP_DAYS_THRESHOLD_4'), '{voucher_num}' => $voucher->code ); Mail::Send((int)$email['id_lang'], 'followup_4', Mail::l('Vous nous manquez, revenez!', (int)$email['id_lang']), $template_vars, $email['email'], $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); $this->logEmail(4, (int)$voucher->id, (int)$email['id_customer'], (int)$email['id_cart']); } } } private function createDiscount($id_email_type, $amount, $id_customer, $date_validity, $description, $free_shipping = false) { $cart_rule = new CartRule(); $cart_rule->reduction_percent = (float)$amount; $cart_rule->id_customer = (int)$id_customer; $cart_rule->date_to = $date_validity; $cart_rule->date_from = date('Y-m-d H:i:s'); $cart_rule->quantity = 1; $cart_rule->quantity_per_user = 1; $cart_rule->cart_rule_restriction = 1; $cart_rule->minimum_amount = 0; if($free_shipping) $cart_rule->free_shipping = 1; $languages = Language::getLanguages(true); foreach ($languages as $language) $cart_rule->name[(int)$language['id_lang']] = $description; $code = 'FLW-'.(int)$id_email_type.'-'.Tools::strtoupper(Tools::passwdGen(10)); // $code = 'PRIVILEGE'.Tools::strtoupper(Tools::passwdGen(4)); $cart_rule->code = $code; $cart_rule->active = 1; if (!$cart_rule->add()) return false; return $cart_rule; } /** * @Override Create advanced discount with more options */ private function createAdvancedDiscount($id_email_type, $reduction_percent=0, $reduction_amount=0, $id_customer, $date_validity, $description, $cart_rule_restriction=0, $minimum_amount=0, $highlight = 1) { $cart_rule = new CartRule(); $cart_rule->id_customer = (int)$id_customer; $cart_rule->date_from = date('Y-m-d H:i:s'); $cart_rule->date_to = $date_validity; $cart_rule->minimum_amount = $minimum_amount; $cart_rule->minimum_amount_tax = 1; $cart_rule->cart_rule_restriction = 0; $cart_rule->reduction_percent = (float)$reduction_percent; $cart_rule->reduction_amount = (float)$reduction_amount; $cart_rule->reduction_tax = 1; $cart_rule->quantity = 1; $cart_rule->quantity_per_user = 1; $cart_rule->highlight = $highlight; /* Modification */ if(($minimum_amount - (float)$reduction_amount) > 0){ $cart_rule->partial_use = 0; } else { $cart_rule->partial_use = 1; } /* end of Modification */ $languages = Language::getLanguages(true); foreach ($languages as $language) $cart_rule->name[(int)$language['id_lang']] = $description; $code = 'PRIVILEGE'.Tools::strtoupper(Tools::passwdGen(4)); $cart_rule->code = $code; $cart_rule->active = 1; if (!$cart_rule->add()) return false; return $cart_rule; } public function cronTask() { Context::getContext()->link = new Link(); //when this is call by cron context is not init $conf = Configuration::getMultiple(array( 'PS_FOLLOW_UP_ENABLE_1', 'PS_FOLLOW_UP_ENABLE_2', 'PS_FOLLOW_UP_ENABLE_3', 'PS_FOLLOW_UP_ENABLE_4', 'PS_FOLLOW_UP_ENABLE_5', 'PS_FOLLOW_UP_CLEAN_DB' )); if ($conf['PS_FOLLOW_UP_ENABLE_1']) $this->cancelledCart(); if ($conf['PS_FOLLOW_UP_ENABLE_2']) $this->reOrder(); if ($conf['PS_FOLLOW_UP_ENABLE_3']) $this->bestCustomer(); if ($conf['PS_FOLLOW_UP_ENABLE_4']) $this->badCustomer(); if ($conf['PS_FOLLOW_UP_ENABLE_5']) $this->cancelledCartRecall(); /* Clean-up database by deleting all outdated discounts */ if ($conf['PS_FOLLOW_UP_CLEAN_DB'] == 1) { $outdated_discounts = Db::getInstance()->executeS('SELECT id_cart_rule FROM '._DB_PREFIX_.'cart_rule WHERE date_to < NOW() AND code LIKE "FLW-%"'); foreach ($outdated_discounts as $outdated_discount) { $cart_rule = new CartRule((int)$outdated_discount['id_cart_rule']); if (Validate::isLoadedObject($cart_rule)) $cart_rule->delete(); } } } public function renderStats() { $sql = ' SELECT DATE_FORMAT(l.date_add, \'%Y-%m-%d\') date_stat, l.id_email_type, COUNT(l.id_log_email) nb, (SELECT COUNT(l2.id_cart_rule) FROM '._DB_PREFIX_.'log_email l2 LEFT JOIN '._DB_PREFIX_.'order_cart_rule ocr ON (ocr.id_cart_rule = l2.id_cart_rule) LEFT JOIN '._DB_PREFIX_.'orders o ON (o.id_order = ocr.id_order) WHERE l2.id_email_type = l.id_email_type AND l2.date_add = l.date_add AND ocr.id_order IS NOT NULL AND o.valid = 1) nb_used FROM '._DB_PREFIX_.'log_email l WHERE l.date_add >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) GROUP BY DATE_FORMAT(l.date_add, \'%Y-%m-%d\'), l.id_email_type'; $stats = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); $stats_array = array(); foreach ($stats as $stat) { $stats_array[$stat['date_stat']][$stat['id_email_type']]['nb'] = (int)$stat['nb']; $stats_array[$stat['date_stat']][$stat['id_email_type']]['nb_used'] = (int)$stat['nb_used']; } foreach ($stats_array as $date_stat => $array) { $rates = array(); for ($i = 1; $i != 6; $i++) if (isset($stats_array[$date_stat][$i]['nb']) && isset($stats_array[$date_stat][$i]['nb_used']) && $stats_array[$date_stat][$i]['nb_used'] > 0) $rates[$i] = number_format(($stats_array[$date_stat][$i]['nb_used'] / $stats_array[$date_stat][$i]['nb']) * 100, 2, '.', ''); for ($i = 1; $i != 6; $i++) { $stats_array[$date_stat][$i]['nb'] = isset($stats_array[$date_stat][$i]['nb']) ? (int)$stats_array[$date_stat][$i]['nb'] : 0; $stats_array[$date_stat][$i]['nb_used'] = isset($stats_array[$date_stat][$i]['nb_used']) ? (int)$stats_array[$date_stat][$i]['nb_used'] : 0; $stats_array[$date_stat][$i]['rate'] = isset($rates[$i]) ? $rates[$i] : '0.00'; } ksort($stats_array[$date_stat]); } $this->context->smarty->assign(array('stats_array' => $stats_array)); return $this->display(__FILE__, 'stats.tpl'); } public function renderForm() { $currency = new Currency((int)Configuration::get('PS_CURRENCY_DEFAULT')); $n1 = $this->cancelledCart(true); $n2 = $this->reOrder(true); $n3 = $this->bestCustomer(true); $n4 = $this->badCustomer(true); $n5 = $this->cancelledCartRecall(true); $cron_info = ''; if (Shop::getContext() === Shop::CONTEXT_SHOP) $cron_info = $this->l('Define the settings and place the following URL in the crontab, or call it manually on a daily basis:').'
'.$this->context->shop->getBaseURL().'modules/followup/cron.php?secure_key='.Configuration::get('PS_FOLLOWUP_SECURE_KEY').'

'; $fields_form_info = array( 'form' => array( 'legend' => array( 'title' => $this->l('Informations'), 'icon' => 'icon-cogs', ), 'description' => $this->l('Four kinds of e-mail alerts are available in order to stay in touch with your customers!').'
'.$cron_info, ) ); $fields_form_1 = array( 'form' => array( 'legend' => array( // ticket 12164 - change title to explicit it 'title' => $this->l('Paniers annulés (1ère relance)'), 'icon' => 'icon-cogs' ), // ticket 12164 - change sentence to explicit it 'description' => $this->l('Pour chaque panier abandonné (sans commande), envoit un premier email de relance au client (pas de bon de réduction).'), //'description' => $this->l('For each cancelled cart (with no order), generate a discount and send it to the customer.'), 'input' => array( array( 'type' => 'switch', 'is_bool' => true, //retro-compat 'label' => $this->l('Enable'), 'name' => 'PS_FOLLOW_UP_ENABLE_1', 'values' => array( array( 'id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled') ), array( 'id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled') ) ), ), // ticket 12164 - never used /* array( 'type' => 'text', 'label' => $this->l('Discount amount'), 'name' => 'PS_FOLLOW_UP_AMOUNT_1', 'suffix' => '%', ), */ array( 'type' => 'text', 'label' => $this->l('Discount validity'), 'name' => 'PS_FOLLOW_UP_DAYS_1', 'suffix' => $this->l('day(s)'), ), array( 'type' => 'desc', 'name' => '', 'text' => sprintf($this->l('The next process will send %d e-mail(s).'), $n1) ), ), 'submit' => array( 'title' => $this->l('Save'), 'class' => 'btn btn-default pull-right' ) ), ); $fields_form_2 = array( 'form' => array( 'legend' => array( 'title' => $this->l('Re-order'), 'icon' => 'icon-cogs' ), 'description' => $this->l('For each validated order, generate a discount and send it to the customer.'), 'input' => array( array( 'type' => 'switch', 'is_bool' => true, //retro-compat 'label' => $this->l('Enable'), 'name' => 'PS_FOLLOW_UP_ENABLE_2', 'values' => array( array( 'id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled') ), array( 'id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled') ) ), ), array( 'type' => 'text', 'label' => $this->l('Discount amount'), 'name' => 'PS_FOLLOW_UP_AMOUNT_2', 'suffix' => '%', ), array( 'type' => 'text', 'label' => $this->l('Discount validity'), 'name' => 'PS_FOLLOW_UP_DAYS_2', 'suffix' => $this->l('day(s)'), ), array( 'type' => 'desc', 'name' => '', 'text' => sprintf($this->l('Next process will send: %d e-mail(s)'), $n2) ), ), 'submit' => array( 'title' => $this->l('Save'), 'class' => 'btn btn-default pull-right' ) ), ); $fields_form_3 = array( 'form' => array( 'legend' => array( 'title' => $this->l('Best customers'), 'icon' => 'icon-cogs' ), 'description' => $this->l('For each customer raising a threshold, generate a discount and send it to the customer.'), 'input' => array( array( 'type' => 'switch', 'is_bool' => true, //retro-compat 'label' => $this->l('Enable'), 'name' => 'PS_FOLLOW_UP_ENABLE_3', 'values' => array( array( 'id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled') ), array( 'id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled') ) ), ), array( 'type' => 'text', 'label' => $this->l('Discount amount'), 'name' => 'PS_FOLLOW_UP_AMOUNT_3', 'suffix' => '%', ), array( 'type' => 'text', 'label' => $this->l('Threshold'), 'name' => 'PS_FOLLOW_UP_THRESHOLD_3', 'suffix' => $currency->sign, ), array( 'type' => 'text', 'label' => $this->l('Discount validity'), 'name' => 'PS_FOLLOW_UP_DAYS_3', 'suffix' => $this->l('day(s)'), ), array( 'type' => 'desc', 'name' => '', 'text' => sprintf($this->l('Next process will send: %d e-mail(s)'), $n3) ), ), 'submit' => array( 'title' => $this->l('Save'), 'class' => 'btn btn-default pull-right' ) ), ); $fields_form_4 = array( 'form' => array( 'legend' => array( 'title' => $this->l('Bad customers'), 'icon' => 'icon-cogs' ), 'description' => $this->l('For each customer who has already passed at least one order and with no orders since a given duration, generate a discount and send it to the customer.'), 'input' => array( array( 'type' => 'switch', 'is_bool' => true, //retro-compat 'label' => $this->l('Enable'), 'name' => 'PS_FOLLOW_UP_ENABLE_4', 'values' => array( array( 'id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled') ), array( 'id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled') ) ), ), array( 'type' => 'text', 'label' => $this->l('Discount amount'), 'name' => 'PS_FOLLOW_UP_AMOUNT_4', 'suffix' => '%', ), array( 'type' => 'text', 'label' => $this->l('Since x days'), 'name' => 'PS_FOLLOW_UP_DAYS_THRESHOLD_4', 'suffix' => $this->l('day(s)'), ), array( 'type' => 'text', 'label' => $this->l('Discount validity'), 'name' => 'PS_FOLLOW_UP_DAYS_4', 'suffix' => $this->l('day(s)'), ), array( 'type' => 'desc', 'name' => '', 'text' => sprintf($this->l('Next process will send: %d e-mail(s)'), $n4) ), ), 'submit' => array( 'title' => $this->l('Save'), 'class' => 'btn btn-default pull-right' ) ), ); $fields_form_5 = array( 'form' => array( 'legend' => array( // ticket 12164 - change title to explicit it 'title' => $this->l('Relance avec remise (si précédente sans réponse)'), 'icon' => 'icon-cogs' ), 'description' => sprintf($this->l('Pour chaque panier abandonné (ayant un montant minimum de %d €) et si le client n\'a pas répondu au précédent email, génère un bon d\'achat et l\'envoit au client.'), self::$cancelled_cart_min_amount_order), 'input' => array( array( 'type' => 'switch', 'is_bool' => true, //retro-compat 'label' => $this->l('Enable'), 'name' => 'PS_FOLLOW_UP_ENABLE_5', 'values' => array( array( 'id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled') ), array( 'id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled') ) ), ), array( 'type' => 'text', 'label' => $this->l('Discount amount'), 'name' => 'PS_FOLLOW_UP_AMOUNT_5', 'suffix' => '%', ), array( 'type' => 'text', 'label' => $this->l('Discount min'), 'name' => 'PS_FOLLOW_UP_MIN_5', 'suffix' => '€', ), array( 'type' => 'text', 'label' => $this->l('Discount validity'), 'name' => 'PS_FOLLOW_UP_DAYS_5', 'suffix' => $this->l('day(s)'), ), array( 'type' => 'desc', 'name' => '', 'text' => sprintf($this->l('The next process will send %d e-mail(s).'), $n5) ), ), 'submit' => array( 'title' => $this->l('Save'), 'class' => 'btn btn-default pull-right' ) ), ); $fields_form_settings = array( 'form' => array( 'legend' => array( 'title' => $this->l('General'), 'icon' => 'icon-cogs' ), 'input' => array( array( 'type' => 'switch', 'is_bool' => true, //retro-compat 'label' => $this->l('Delete outdated discounts during each launch to clean database'), 'name' => 'PS_FOLLOW_UP_CLEAN_DB', 'values' => array( array( 'id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled') ), array( 'id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled') ) ), ), ), 'submit' => array( 'title' => $this->l('Save'), 'class' => 'btn btn-default pull-right' ) ), ); /* @Override */ $mailTemplates = array( array('id' => 1, 'name' => 'Paniers annulés (cancelledCart)'), array('id' => 5, 'name' => 'Relance paniers annulés (cancelledCartRecall)'), // array('id' => 2, 'name' => 'reOrder'), // array('id' => 3, 'name' => 'bestCustomer'), // array('id' => 4, 'name' => 'badCustomer'), ); $fields_form_test = array( 'form' => array( 'legend' => array( 'title' => $this->l('Send test mail'), 'icon' => 'icon-cogs' ), 'input' => array( array( 'type' => 'select', 'options' => array( 'query' => $mailTemplates, 'id' => 'id', 'name' => 'name' ), 'label' => $this->l('Mail tempalte'), 'name' => 'id_email_test' ), array( 'type' => 'text', 'label' => $this->l('Email address'), 'name' => 'email_test' ), ), 'submit' => array( 'title' => $this->l('Send Mail'), 'class' => 'btn btn-default pull-right', 'name' => 'sendMailTest' ) ), ); $exportOptions = array( array('id' => 1, 'name' => 'Paniers abandonnés'), // array('id' => 5, 'name' => 'cancelledCartRecall'), // array('id' => 2, 'name' => 'reOrder'), // array('id' => 3, 'name' => 'bestCustomer'), array('id' => 4, 'name' => 'Mauvais Clients'), ); $fields_form_export = array( 'form' => array( 'legend' => array( 'title' => $this->l('Export'), 'icon' => 'icon-cogs' ), 'input' => array( array( 'type' => 'select', 'options' => array( 'query' => $exportOptions, 'id' => 'id', 'name' => 'name' ), 'label' => $this->l('Mail tempalte'), 'name' => 'id_export_type' ), ), 'submit' => array( 'title' => $this->l('Export'), 'class' => 'btn btn-default pull-right', 'name' => 'flw_export' ) ), ); $helper = new HelperForm(); $helper->show_toolbar = false; $helper->table = $this->table; $lang = new Language((int)Configuration::get('PS_LANG_DEFAULT')); $helper->default_form_language = $lang->id; $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0; $helper->identifier = $this->identifier; $helper->override_folder = '/'; $helper->module = $this; $helper->submit_action = 'submitFollowUp'; $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false).'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name; $helper->token = Tools::getAdminTokenLite('AdminModules'); $helper->tpl_vars = array( 'fields_value' => $this->getConfigFieldsValues(), 'languages' => $this->context->controller->getLanguages(), 'id_language' => $this->context->language->id ); $forms = array( $fields_form_info, $fields_form_1, $fields_form_5, $fields_form_2, $fields_form_3, $fields_form_4, $fields_form_settings, $fields_form_export, $fields_form_test ); return $helper->generateForm($forms); } public function getConfigFieldsValues() { return array( 'PS_FOLLOW_UP_ENABLE_1' => Tools::getValue('PS_FOLLOW_UP_ENABLE_1', Configuration::get('PS_FOLLOW_UP_ENABLE_1')), 'PS_FOLLOW_UP_DAYS_1' => Tools::getValue('PS_FOLLOW_UP_DAYS_1', Configuration::get('PS_FOLLOW_UP_DAYS_1')), 'PS_FOLLOW_UP_AMOUNT_1' => Tools::getValue('PS_FOLLOW_UP_AMOUNT_1', Configuration::get('PS_FOLLOW_UP_AMOUNT_1')), 'PS_FOLLOW_UP_ENABLE_2' => Tools::getValue('PS_FOLLOW_UP_ENABLE_2', Configuration::get('PS_FOLLOW_UP_ENABLE_2')), 'PS_FOLLOW_UP_DAYS_2' => Tools::getValue('PS_FOLLOW_UP_DAYS_2', Configuration::get('PS_FOLLOW_UP_DAYS_2')), 'PS_FOLLOW_UP_AMOUNT_2' => Tools::getValue('PS_FOLLOW_UP_AMOUNT_2', Configuration::get('PS_FOLLOW_UP_AMOUNT_2')), 'PS_FOLLOW_UP_THRESHOLD_3' => Tools::getValue('PS_FOLLOW_UP_THRESHOLD_3', Configuration::get('PS_FOLLOW_UP_THRESHOLD_3')), 'PS_FOLLOW_UP_DAYS_3' => Tools::getValue('PS_FOLLOW_UP_DAYS_3', Configuration::get('PS_FOLLOW_UP_DAYS_3')), 'PS_FOLLOW_UP_ENABLE_3' => Tools::getValue('PS_FOLLOW_UP_ENABLE_3', Configuration::get('PS_FOLLOW_UP_ENABLE_3')), 'PS_FOLLOW_UP_AMOUNT_3' => Tools::getValue('PS_FOLLOW_UP_AMOUNT_3', Configuration::get('PS_FOLLOW_UP_AMOUNT_3')), 'PS_FOLLOW_UP_AMOUNT_4' => Tools::getValue('PS_FOLLOW_UP_AMOUNT_4', Configuration::get('PS_FOLLOW_UP_AMOUNT_4')), 'PS_FOLLOW_UP_ENABLE_4' => Tools::getValue('PS_FOLLOW_UP_ENABLE_4', Configuration::get('PS_FOLLOW_UP_ENABLE_4')), 'PS_FOLLOW_UP_DAYS_THRESHOLD_4' => Tools::getValue('PS_FOLLOW_UP_DAYS_THRESHOLD_4', Configuration::get('PS_FOLLOW_UP_DAYS_THRESHOLD_4')), 'PS_FOLLOW_UP_DAYS_4' => Tools::getValue('PS_FOLLOW_UP_DAYS_4', Configuration::get('PS_FOLLOW_UP_DAYS_4')), /*@Override*/ 'PS_FOLLOW_UP_ENABLE_5' => Tools::getValue('PS_FOLLOW_UP_ENABLE_5', Configuration::get('PS_FOLLOW_UP_ENABLE_5')), 'PS_FOLLOW_UP_DAYS_5' => Tools::getValue('PS_FOLLOW_UP_DAYS_5', Configuration::get('PS_FOLLOW_UP_DAYS_5')), 'PS_FOLLOW_UP_AMOUNT_5' => Tools::getValue('PS_FOLLOW_UP_AMOUNT_5', Configuration::get('PS_FOLLOW_UP_AMOUNT_5')), 'PS_FOLLOW_UP_MIN_5' => Tools::getValue('PS_FOLLOW_UP_MIN_5', Configuration::get('PS_FOLLOW_UP_MIN_5')), 'PS_FOLLOW_UP_CLEAN_DB' => Tools::getValue('PS_FOLLOW_UP_CLEAN_DB', Configuration::get('PS_FOLLOW_UP_CLEAN_DB')), 'id_email_test' => '', 'email_test' => 'marion@antadis.com', 'id_export_type' => '1', ); } private function _sendMailTest($id_email, $email){ switch ($id_email) { case 1: $this->_cancelledCartTest($email); break; case 2: # code... break; case 3: # code... break; case 4: # code... break; case 5: $this->_cancelledCartRecallTest($email); break; default: break; } return; } private function _cancelledCartTest($email, $is_pro = false){ $order_url = Context::getContext()->link->getPageLink('order.php', true, Context::getContext()->language->id, null, false); $shop_url = Context::getContext()->link->getPageLink('index', true, Context::getContext()->language->id, null, false); $img_url = $shop_url.'themes/'._THEME_NAME_.'/img/'; $conf = Configuration::getMultiple(array('PS_FOLLOW_UP_AMOUNT_1', 'PS_FOLLOW_UP_DAYS_1')); //AJOUT 20-01-2015 //Get cart $products = Product::getProducts(Context::getContext()->language->id, 0, 3, 'id_product', 'ASC'); $cartHtml = ''; $cartText = ''; foreach($products as $product) { $cover = Product::getCover($product['id_product']); $product['id_image'] = $cover['id_image']; $imagePath = Context::getContext()->link->getImageLink($product['link_rewrite'], $product['id_image'], 'block_cart'); // change the last parameters to get the size you need $imagePath = str_replace('https:', 'http:', $imagePath); if (!preg_match("/^(http):/", $imagePath)) { $imagePath = 'http://'.$imagePath; } if(!empty($cartHtml)) $cartHtml .= '
 
'; $hack = ''; $product['price_without_specific_price'] = Product::getPriceStatic( (int)$product['id_product'], !$is_pro, null, 6, null, false, false ); $product['price_wt'] = Product::getPriceStatic( (int)$product['id_product'], !$is_pro ); $price = !$is_pro ? $product['price_wt'] : $product['price']; $cartHtml .= ' '.$product['name'].' '.Tools::displayPrice($price).' '.(!$is_pro ? $this->l('TTC') : $this->l('HT') ).' '; if(!empty($product['price_without_specific_price']) && $product['price_without_specific_price'] != $price) $cartHtml .= ''.$this->l('au lieu de').' '. Tools::displayPrice($product['price_without_specific_price']).' '; $cartHtml .= '

'.$this->l('Finaliser ma').'
'.$this->l('commande').'

'; $cartText .= $product['name'].' - qté : 1'."\n\r"; } // FIN AJOUT $template_vars = array( '{email}' => $email, '{lastname}' => 'lastname', '{firstname}' => 'firstname', '{amount}' => $conf['PS_FOLLOW_UP_AMOUNT_1'], '{days}' => $conf['PS_FOLLOW_UP_DAYS_1'], '{voucher_num}' => Tools::passwdGen(10), '{cartHtml}' => $cartHtml, '{cartText}' => $cartText ); return Mail::Send($this->context->language->id, 'followup_H3', Mail::l('Ne manquez pas les ventes privilégiées que vous aviez sélectionnées, validez votre panier!', (int)$this->context->language->id), $template_vars, $email, 'firstname lastname', null, null, null, null, dirname(__FILE__).'/mails/'); } private function _cancelledCartRecallTest($email, $is_pro=false){ $order_url = Context::getContext()->link->getPageLink('order.php', true, Context::getContext()->language->id, null, false); $shop_url = Context::getContext()->link->getPageLink('index', true, Context::getContext()->language->id, null, false); $img_url = $shop_url.'themes/'._THEME_NAME_.'/img/'; $conf = Configuration::getMultiple(array('PS_FOLLOW_UP_AMOUNT_5', 'PS_FOLLOW_UP_DAYS_5', 'PS_FOLLOW_UP_MIN_5')); //AJOUT 20-01-2015 //Get cart $products = Product::getProducts(Context::getContext()->language->id, 0, 3, 'id_product', 'ASC'); $cartHtml = ''; $cartText = ''; foreach($products as $product) { $cover = Product::getCover($product['id_product']); $product['id_image'] = $cover['id_image']; $imagePath = Context::getContext()->link->getImageLink($product['link_rewrite'], $product['id_image'], 'block_cart'); // change the last parameters to get the size you need $imagePath = str_replace('https:', 'http:', $imagePath); if (!preg_match("/^(http):/", $imagePath)) { $imagePath = 'http://'.$imagePath; } if(!empty($cartHtml)) $cartHtml .= '
 
'; $hack = ''; $product['price_without_specific_price'] = Product::getPriceStatic( (int)$product['id_product'], !$is_pro, null, 6, null, false, false ); $product['price_wt'] = Product::getPriceStatic( (int)$product['id_product'], !$is_pro ); $price = !$is_pro ? $product['price_wt'] : $product['price']; $cartHtml .= ' '.$product['name'].' '.Tools::displayPrice($price).' '.(!$is_pro ? $this->l('TTC') : $this->l('HT') ).' '; if(!empty($product['price_without_specific_price']) && $product['price_without_specific_price'] != $price) $cartHtml .= ''.$this->l('au lieu de').' '. Tools::displayPrice($product['price_without_specific_price']).' '; $cartHtml .= '

'.$this->l('Finaliser ma').'
'.$this->l('commande').'

'; $cartText .= $product['name'].' - qté : 1'."\n\r"; } // FIN AJOUT $template_vars = array( '{email}' => $email, '{lastname}' => 'lastname', '{firstname}' => 'firstname', '{amount}' => $conf['PS_FOLLOW_UP_AMOUNT_5'], '{days}' => $conf['PS_FOLLOW_UP_DAYS_5'], '{voucher_num}' => Tools::passwdGen(10), '{cartHtml}' => $cartHtml, '{cartText}' => $cartText ); return Mail::Send($this->context->language->id, 'followup_H24', Mail::l('Ne manquez pas les ventes privilégiées que vous aviez sélectionnées, validez votre panier!', (int)$this->context->language->id), $template_vars, $email, 'firstname lastname', null, null, null, null, dirname(__FILE__).'/mails/'); } private function _processExport($id_export_type = 1){ header('Pragma: public'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Content-Description: File Transfer'); header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename=export_followup.csv;'); header('Content-Transfer-Encoding: binary'); $fp = fopen('php://output', 'w'); $delim = ';'; $row_definition = $this->_getRowDefinition((int)$id_export_type); // First row $data = array(); foreach ($row_definition as $colName => $value) $data[]=Tools::htmlentitiesDecodeUTF8($colName); fputcsv ($fp,$data,$delim); $logs = $this->_getLogmails((int)$id_export_type); foreach($logs as $log){ $data = array(); foreach ($row_definition as $index) $data[] = $log[$index]; fputcsv ($fp,$data,$delim); } fclose($fp); exit; } private function _getRowDefinition($id_export_type){ $row_definition = array( 'ID Client' => 'id_customer', 'ID Panier' => 'id_cart', /*'date Panier' => 'date_upd',*/ 'relance 1' => 'date_flw1', 'relance 2' => 'date_flw2', 'ID commande' => 'id_order', 'Date commande' => 'order_date_add', 'Total TTC' => 'total_paid_tax_incl', 'Total HT' => 'total_paid_tax_excl', 'Bon utilise' => 'have_discount', // 'Cmd avec bon' => 'voucher_cmd', ); switch ($id_export_type) { case 1: break; case 2: break; case 3: break; case 4: $row_definition = array_merge($row_definition, array( 'Derniere commande' => 'last_order', 'Total TTC DC' => 'total_paid_tax_incl_last_order', 'Total HT DC' => 'total_paid_tax_excl_last_order', )); break; case 5: break; default: break; } return $row_definition; } private function _getLogmails($id_export_type){ switch ($id_export_type) { case 1: return $this->_getLogsCancelledCart(); break; case 2: return array(); break; case 3: return array(); break; case 4: return $this->_getLogsBadCustomer(); break; case 5: return array(); break; default: return array(); break; } } private function _getLogsCancelledCart(){ $sql = ' SELECT DISTINCT le.`id_customer`, le.`id_cart`, DATE_FORMAT(le.`date_add`, \'%Y-%m-%d\') as `date_flw1`, DATE_FORMAT(le2.`date_add`, \'%Y-%m-%d\') as `date_flw2`, o.`id_order`, DATE_FORMAT(o.`date_add`, \'%Y-%m-%d\') as `order_date_add`, o.`total_paid_tax_incl`, o.`total_paid_tax_excl`, ( SELECT COUNT(*) FROM `'._DB_PREFIX_.'order_cart_rule` ocr WHERE `id_cart_rule` = le2.`id_cart_rule` ) as `have_discount` FROM `'._DB_PREFIX_.'log_email` le LEFT JOIN `'._DB_PREFIX_.'orders` o ON (o.`id_cart` = le.`id_cart`) LEFT JOIN `'._DB_PREFIX_.'log_email` le2 ON (le2.`id_cart` = le.`id_cart` AND le2.`id_email_type` = 5) WHERE 1 AND le.`id_email_type` = 1 ORDER BY le.`date_add` DESC, le2.`date_add` DESC, o.`date_add` DESC'; /*$sql = ' SELECT DISTINCT le.`id_customer`, le.`id_cart`, c.`date_upd`, ( SELECT DATE_FORMAT(le2.`date_add`, \'%Y-%m-%d\') FROM `'._DB_PREFIX_.'log_email` le2 WHERE le2.`id_cart` = le.`id_cart` AND le2.`id_email_type` = 1 ORDER BY le2.`date_add` DESC LIMIT 1 ) as `date_flw1`, DATE_FORMAT(le.`date_add`, \'%Y-%m-%d\') as `date_flw2`, -- le.`id_cart_rule`, o.`id_order`, DATE_FORMAT(o.`date_add`, \'%Y-%m-%d\') as `order_date_add`, o.`total_paid_tax_incl`, o.`total_paid_tax_excl`, ( SELECT COUNT(*) FROM `'._DB_PREFIX_.'order_cart_rule` ocr WHERE `id_cart_rule` = le.`id_cart_rule` ) as `have_discount` FROM `'._DB_PREFIX_.'log_email` le LEFT JOIN `'._DB_PREFIX_.'orders` o ON (o.`id_cart` = le.`id_cart`) LEFT JOIN `'._DB_PREFIX_.'cart` c ON (c.`id_cart` = le.`id_cart`) WHERE 1 AND le.`id_email_type` = 5 ORDER BY le.`date_add` DESC, `date_flw2` DESC, o.`date_add` DESC';*/ return Db::getInstance()->executeS($sql); } private function _getLogsBadCustomer(){ $sql = ' SELECT DISTINCT le.`id_customer`, le.`id_cart`, DATE_FORMAT(le.`date_add`, \'%Y-%m-%d\') as `date_flw1`, o.`id_order`, DATE_FORMAT(o.`date_add`, \'%Y-%m-%d\') as `order_date_add`, o.`total_paid_tax_incl`, o.`total_paid_tax_excl`, ( SELECT COUNT(*) FROM `'._DB_PREFIX_.'order_cart_rule` ocr WHERE `id_cart_rule` = le.`id_cart_rule` )as `have_discount`, lo.`id_order` as last_order, lo.`total_paid_tax_incl` as total_paid_tax_incl_last_order, lo.`total_paid_tax_excl` as total_paid_tax_excl_last_order FROM `'._DB_PREFIX_.'log_email` le LEFT JOIN `'._DB_PREFIX_.'orders` o ON (o.`id_cart` = le.`id_cart`) LEFT JOIN `'._DB_PREFIX_.'orders` lo ON (lo.`id_order` = ( SELECT `id_order` FROM `'._DB_PREFIX_.'orders` WHERE `id_customer` = le.`id_customer` ORDER BY `date_add` DESC LIMIT 1 ) AND lo.`id_order` <> o.`id_order` ) WHERE 1 AND le.`id_email_type` = 4 ORDER BY le.`date_add` DESC, le.`date_add` DESC, o.`date_add` DESC'; return Db::getInstance()->executeS($sql); } public function cancelledCartBis($count = false) { $ids_products = self::getIdProductOfAllActiveSale(); if(count($ids_products) == 0) return 0; $email_logs = $this->getLogsEmail(1); $sql = ' SELECT DISTINCT c.id_cart, c.id_lang, cu.id_default_group, cu.id_customer, c.id_shop, cu.firstname, cu.lastname, cu.email FROM '._DB_PREFIX_.'cart c LEFT JOIN '._DB_PREFIX_.'orders o ON (o.id_cart = c.id_cart) RIGHT JOIN '._DB_PREFIX_.'customer cu ON (cu.id_customer = c.id_customer) RIGHT JOIN '._DB_PREFIX_.'cart_product cp ON (cp.id_cart = c.id_cart AND cp.id_product IN ('.implode(',', $ids_products).')) WHERE c.id_cart = 49469'; $sql .= Shop::addSqlRestriction(Shop::SHARE_CUSTOMER, 'c'); $emails = Db::getInstance()->executeS($sql); if ($count || !count($emails)){ return count($emails); } $order_url = Context::getContext()->link->getPageLink('order.php', true, Context::getContext()->language->id, null, false); $shop_url = Context::getContext()->link->getPageLink('index', true, Context::getContext()->language->id, null, false); $img_url = $shop_url.'themes/'._THEME_NAME_.'/img/'; $conf = Configuration::getMultiple(array('PS_FOLLOW_UP_AMOUNT_1', 'PS_FOLLOW_UP_DAYS_1')); foreach ($emails as $email) { //AJOUT 20-01-2015 //Get cart $cart = new Cart(intval($email['id_cart'])); $products = $cart->getProducts(true); $price_display_method = Group::getPriceDisplayMethod($email['id_default_group']); $cartHtml = ''; //Création du panier $cart_product_context = Context::getContext()->cloneContext(); $cart_product_context->customer = new Customer($cart->id_customer); $cart_product_context->cart = $cart; if ($cart_product_context->shop->id != $cart->id_shop) { $cart_product_context->shop = new Shop((int)$cart->id_shop); } $cartText = ''; foreach($products as $product) { $imagePath = Context::getContext()->link->getImageLink($product['link_rewrite'], $product['id_image'], 'block_cart'); // change the last parameters to get the size you need if(!empty($cartHtml)) { $cartHtml .= '
 
'; } $hack = ''; $product['price_without_specific_price'] = Product::getPriceStatic( (int)$product['id_product'], !$price_display_method, $product['id_product_attribute'], 6, null, false, false, 1, false, null, null, null, $hack, true, true, $cart_product_context ); $price = !$price_display_method ? $product['price_wt'] : $product['price']; $cartHtml .= ' '.$product['legend'].' '.$product['name'].' '.Tools::displayPrice($price, (int)$cart->id_currency).' '.(!$price_display_method ? $this->l('TTC') : $this->l('HT') ).' '; if(!empty($product['price_without_specific_price']) && $product['price_without_specific_price'] != $price) $cartHtml .= ''.$this->l('au lieu de').' '. Tools::displayPrice($product['price_without_specific_price'], (int)$cart->id_currency).' '; $cartHtml .= '

'.$this->l('Finaliser ma').'
'.$this->l('commande').'

'; $cartText .= $product['name'].' - qté : '.$product['cart_quantity']."\n\r"; } //FIN AJOUT $template_vars = array( '{email}' => $email['email'], '{lastname}' => $email['lastname'], '{firstname}' => $email['firstname'], '{amount}' => $conf['PS_FOLLOW_UP_AMOUNT_1'], '{days}' => $conf['PS_FOLLOW_UP_DAYS_1'], // '{voucher_num}' => $voucher->code, '{cartHtml}' => $cartHtml, '{cartText}' => $cartText ); Mail::Send((int)$email['id_lang'], 'followup_J1', Mail::l('Ne manquez pas les ventes privilégiées que vous aviez sélectionnées, validez votre panier!', (int)$email['id_lang']), $template_vars, 'coppee@antadis.com', $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); return Mail::Send((int)$email['id_lang'], 'followup_J1', Mail::l('Ne manquez pas les ventes privilégiées que vous aviez sélectionnées, validez votre panier!', (int)$email['id_lang']), $template_vars, 'clefebvre@privilegedemarque.com', $email['firstname'].' '.$email['lastname'], null, null, null, null, dirname(__FILE__).'/mails/'); } } }