diff --git a/admin-dev/ajax.php b/admin-dev/ajax.php index 1f9c8815e..1b779c78f 100644 --- a/admin-dev/ajax.php +++ b/admin-dev/ajax.php @@ -722,3 +722,75 @@ if (Tools::isSubmit('updateElementEmployee') && Tools::getValue('updateElementEm $notification = new Notification; die($notification->updateEmployeeLastElement(Tools::getValue('updateElementEmployeeType'))); } + +if (Tools::isSubmit('syncImapMail')) +{ + if (!$url = Configuration::get('PS_SAV_IMAP_URL') + OR !$port = Configuration::get('PS_SAV_IMAP_PORT') + OR !$user = Configuration::get('PS_SAV_IMAP_USER') + OR !$password = Configuration::get('PS_SAV_IMAP_PWD')) + die('{"hasError" : true, "errors" : "Configuration is not correct"}'); + + $mbox = @imap_open('{'.$url.':'.$port.'}', $user, $password); + + $errors = imap_errors(); + if (sizeof($errors)) + { + $str_errors = '["'; + foreach($errors as $error) + $str_errors .= $error.','; + $str_errors = rtrim($str_errors, ',').'"]'; + } + if (!$mbox) + die('{"hasError" : true, "errors" : ["Can not connect to the mailbox"]}'); + + $check = imap_check($mbox); + + if ($check->Nmsgs == 0) + die('{"hasError" : true, "errors" : ["NO message to sync"]}'); + + $result = imap_fetch_overview($mbox,"1:{$check->Nmsgs}",0); + foreach ($result as $overview) + { + //check if message exist in database + if (isset($overview->subject)) + $subject = $overview->subject; + else + $subject = ''; + + $md5 = md5($overview->date.$overview->from.$subject); + $exist = Db::getInstance()->getValue( + 'SELECT md5_header + FROM `'._DB_PREFIX_.'customer_message_sync_imap` + WHERE md5_header = \''.pSQL($md5).'\''); + if ($exist) + { + if (Configuration::get('PS_SAV_IMAP_DELETE_MSG')) + imap_delete($mbox, $overview->msgno); + } + else + { + //check if subject has id_order + preg_match('/\#ct([0-9]*)/', $subject, $matches1); + preg_match('/\#tc([0-9-a-z-A-Z]*)/', $subject, $matches2); + + if (isset($matches1[1]) AND isset($matches2[1])) + { + //check if order exist in database + $ct = new CustomerThread((int)$matches1[1]); + + if (Validate::isLoadedObject($ct) && $ct->token == $matches2[1]) + { + $cm = new CustomerMessage(); + $cm->id_customer_thread = $ct->id; + $cm->message = imap_fetchbody($mbox, $overview->msgno, 1); + $cm->add(); + } + } + Db::getInstance()->execute('INSERT INTO `'._DB_PREFIX_.'customer_message_sync_imap` VALUES (\''.pSQL($md5).'\')'); + } + } + imap_expunge($mbox); + imap_close($mbox); + die('{"hasError" : false, "errors" : '.$str_errors.'}'); +} diff --git a/admin-dev/tabs/AdminCustomerThreads.php b/admin-dev/tabs/AdminCustomerThreads.php index 61d597d17..8ef4282d1 100644 --- a/admin-dev/tabs/AdminCustomerThreads.php +++ b/admin-dev/tabs/AdminCustomerThreads.php @@ -86,6 +86,22 @@ class AdminCustomerThreads extends AdminTab ); $this->shopLinkType = 'shop'; + $this->optionsList = array( + 'general' => array( + 'title' => $this->l('Customer service options'), + 'fields' => array( + 'PS_SAV_IMAP_URL' => array('title' => $this->l('Imap url'), 'desc' => $this->l('Url for imap server (mail.server.com)'), 'type' => 'text', 'size' => 40, 'visibility' => Shop::CONTEXT_ALL), + 'PS_SAV_IMAP_PORT' => array('title' => $this->l('Imap port'), 'desc' => $this->l('Port to use to connect imap server'), 'type' => 'text', 'defaultValue' => 143, 'visibility' => Shop::CONTEXT_ALL), + 'PS_SAV_IMAP_USER' => array('title' => $this->l('Imap user'), 'desc' => $this->l('User to use to connect imap server'), 'type' => 'text', 'size' => 40, 'visibility' => Shop::CONTEXT_ALL), + 'PS_SAV_IMAP_PWD' => array('title' => $this->l('Imap password'), 'desc' => $this->l('Password to use to connect imap server'), 'type' => 'text', 'size' => 40, 'visibility' => Shop::CONTEXT_ALL), + 'PS_SAV_IMAP_DELETE_MSG' => array('title' => $this->l('Delete messages'), 'desc' => $this->l('Deletes message after sync. If you do not active this option, the sync will be longer'), 'cast' => 'intval', 'type' => 'select', 'identifier' => 'value', 'list' => array( + '0' => array('value' => 0, 'name' => $this->l('No')), + '1' => array('value' => 1, 'name' => $this->l('Yes')) + ), 'visibility' => Shop::CONTEXT_ALL) + ), + ), + ); + parent::__construct(); } @@ -180,7 +196,7 @@ class AdminCustomerThreads extends AdminTab '{reply}' => Tools::nl2br(Tools::getValue('reply_message')), '{link}' => Tools::url($this->context->link->getPageLink('contact', true), 'id_customer_thread='.(int)($ct->id).'&token='.$ct->token), ); - if (Mail::Send($ct->id_lang, 'reply_msg', Mail::l('An answer to your message is available'), + if (Mail::Send($ct->id_lang, 'reply_msg', Mail::l('An answer to your message is available').' #ct'.$ct->id.'#tc'.$ct->token, $params, Tools::getValue('msg_email'), NULL, NULL, NULL, $fileAttachment, NULL, _PS_MAIL_DIR_, true)) { @@ -207,7 +223,10 @@ class AdminCustomerThreads extends AdminTab else { $this->getList($this->context->language->id, !Tools::getValue($this->table.'Orderby') ? 'date_upd' : NULL, !Tools::getValue($this->table.'Orderway') ? 'DESC' : NULL); + $this->displayList(); + $this->displayOptionsList(); + $this->displaySyncOption(); } } @@ -605,5 +624,67 @@ class AdminCustomerThreads extends AdminTab

'; } + + + private function displaySyncOption() + { + if (Configuration::get('PS_SAV_IMAP_URL') + AND Configuration::get('PS_SAV_IMAP_PORT') + AND Configuration::get('PS_SAV_IMAP_USER') + AND Configuration::get('PS_SAV_IMAP_PWD')) + echo ' +
'.$this->l('Sync').' + +
+ +

'.$this->l('Click to synchronize mail automatically').'

+
+ + +
+

+ '; + } + + } diff --git a/admin-dev/tabs/AdminOrders.php b/admin-dev/tabs/AdminOrders.php index 96268ef87..7ccc158b9 100644 --- a/admin-dev/tabs/AdminOrders.php +++ b/admin-dev/tabs/AdminOrders.php @@ -167,21 +167,44 @@ class AdminOrders extends AdminTab $this->_errors[] = Tools::displayError('field').' '.$field.' '.Tools::displayError('is invalid.'); if (!sizeof($this->_errors)) { - $message = new Message(); - $message->id_employee = (int)$this->context->employee->id; - $message->message = htmlentities(Tools::getValue('message'), ENT_COMPAT, 'UTF-8'); - $message->id_order = $id_order; - $message->private = Tools::getValue('visibility'); - if (!$message->add()) + $order = new Order((int)(Tools::getValue('id_order'))); + $customer = new Customer((int)$order->id_customer); + //check if a thread already exist + $id_customer_thread = CustomerThread::getIdCustomerThreadByEmailAndIdOrder($customer->email, $order->id); + $cm = new CustomerMessage(); + if (!$id_customer_thread) + { + $ct = new CustomerThread(); + $ct->id_contact = 0; + $ct->id_customer = (int)$order->id_customer; + $ct->id_shop = (int)$this->context->shop->getId(true); + $ct->id_order = (int)$order->id; + $ct->id_lang = (int)$this->context->language->id; + $ct->email = $customer->email; + $ct->status = 'open'; + $ct->token = Tools::passwdGen(12); + $ct->add(); + } + else + $ct = new CustomerThread((int)$id_customer_thread); + $cm->id_customer_thread = $ct->id; + $cm->id_employee = (int)$this->context->employee->id; + $cm->message = htmlentities(Tools::getValue('message'), ENT_COMPAT, 'UTF-8'); + $cm->private = Tools::getValue('visibility'); + if (!$cm->add()) $this->_errors[] = Tools::displayError('An error occurred while sending message.'); elseif ($message->private) - Tools::redirectAdmin(self::$currentIndex.'&id_order='.$id_order.'&vieworder&conf=11'.'&token='.$this->token); + Tools::redirectAdmin($currentIndex.'&id_order='.$id_order.'&vieworder&conf=11'.'&token='.$this->token); elseif (Validate::isLoadedObject($customer = new Customer($id_customer))) { - $order = new Order((int)($message->id_order)); if (Validate::isLoadedObject($order)) { - $varsTpl = array('{lastname}' => $customer->lastname, '{firstname}' => $customer->firstname, '{id_order}' => $message->id_order, '{message}' => (Configuration::get('PS_MAIL_TYPE') == 2 ? $message->message : Tools::nl2br($message->message))); + $varsTpl = array( + '{lastname}' => $customer->lastname, + '{firstname}' => $customer->firstname, + '{id_order}' => $order->id, + '{message}' => (Configuration::get('PS_MAIL_TYPE') == 2 ? $cm->message : Tools::nl2br($cm->message)) + ); if (@Mail::Send((int)($order->id_lang), 'order_merchant_comment', Mail::l('New message regarding your order'), $varsTpl, $customer->email, $customer->firstname.' '.$customer->lastname, NULL, NULL, NULL, NULL, _PS_MAIL_DIR_, true)) diff --git a/classes/CustomerMessage.php b/classes/CustomerMessage.php index 79fb9d228..755224932 100644 --- a/classes/CustomerMessage.php +++ b/classes/CustomerMessage.php @@ -34,6 +34,7 @@ class CustomerMessageCore extends ObjectModel public $file_name; public $ip_address; public $user_agent; + public $private; public $date_add; protected $table = 'customer_message'; @@ -52,11 +53,12 @@ class CustomerMessageCore extends ObjectModel $fields['file_name'] = pSQL($this->file_name); $fields['ip_address'] = (int)($this->ip_address); $fields['user_agent'] = pSQL($this->user_agent); + $fields['private'] = pSQL($this->private); $fields['date_add'] = pSQL($this->date_add); return $fields; } - public static function getMessagesByOrderId($id_order) + public static function getMessagesByOrderId($id_order, $private = true) { return Db::getInstance()->ExecuteS(' SELECT cm.*, c.`firstname` AS cfirstname, c.`lastname` AS clastname, e.`firstname` AS efirstname, e.`lastname` AS elastname, (COUNT(cm.id_customer_message) = 0 AND ct.id_customer != 0) AS is_new_for_me @@ -64,7 +66,7 @@ class CustomerMessageCore extends ObjectModel LEFT JOIN `'._DB_PREFIX_.'customer_thread` ct ON ct.`id_customer_thread` = cm.`id_customer_thread` LEFT JOIN `'._DB_PREFIX_.'customer` c ON ct.`id_customer` = c.`id_customer` LEFT OUTER JOIN `'._DB_PREFIX_.'employee` e ON e.`id_employee` = cm.`id_employee` - WHERE ct.id_order = '.(int)$id_order.' + WHERE ct.id_order = '.(int)$id_order.' AND '.(!$private ? 'cm.`private` = 0' : '').' GROUP BY cm.id_customer_message ORDER BY cm.date_add DESC'); } diff --git a/controllers/OrderDetailController.php b/controllers/OrderDetailController.php index 1e116c744..1bbc3e13c 100644 --- a/controllers/OrderDetailController.php +++ b/controllers/OrderDetailController.php @@ -62,8 +62,6 @@ class OrderDetailControllerCore extends FrontController //check if a thread already exist $id_customer_thread = CustomerThread::getIdCustomerThreadByEmailAndIdOrder($this->context->customer->email, $order->id); - p(var_dump($id_customer_thread)); - $cm = new CustomerMessage(); if (!$id_customer_thread) { @@ -164,7 +162,7 @@ class OrderDetailControllerCore extends FrontController 'deliveryAddressFormatedValues' => $deliveryAddressFormatedValues, 'deliveryState' => (Validate::isLoadedObject($addressDelivery) AND $addressDelivery->id_state) ? new State($addressDelivery->id_state) : false, 'is_guest' => false, - 'messages' => CustomerMessage::getMessagesByOrderId((int)($order->id)), + 'messages' => CustomerMessage::getMessagesByOrderId((int)($order->id), false), 'CUSTOMIZE_FILE' => Product::CUSTOMIZE_FILE, 'CUSTOMIZE_TEXTFIELD' => _CUSTOMIZE_TEXTFIELD_, 'isRecyclable' => Configuration::get('PS_RECYCLABLE_PACK'), diff --git a/install-dev/sql/db.sql b/install-dev/sql/db.sql index 66fb70793..97438b149 100644 --- a/install-dev/sql/db.sql +++ b/install-dev/sql/db.sql @@ -468,6 +468,14 @@ CREATE TABLE `PREFIX_customer_message` ( KEY `id_employee` (`id_employee`) ) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8; + +CREATE TABLE `PREFIX_customer_message_sync_imap` ( + `md5_header` varbinary(32) NOT NULL, + KEY `md5_header_index` (`md5_header`(4)) +) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8; + +CREATE INDEX `md5_header_index` ON `PREFIX_customer_message_sync_imap` (md5_header(4)); + CREATE TABLE `PREFIX_customer_thread` ( `id_customer_thread` int(11) unsigned NOT NULL auto_increment, `id_shop` INT(11) UNSIGNED NOT NULL DEFAULT '1', diff --git a/install-dev/sql/upgrade/1.5.0.1.sql b/install-dev/sql/upgrade/1.5.0.1.sql index 3c343bc8a..d258f510d 100644 --- a/install-dev/sql/upgrade/1.5.0.1.sql +++ b/install-dev/sql/upgrade/1.5.0.1.sql @@ -92,3 +92,11 @@ ALTER TABLE `PREFIX_order_detail` DROP `tax_name`, DROP `tax_rate`; +CREATE TABLE `PREFIX_customer_message_sync_imap` ( + `md5_header` varbinary(32) NOT NULL, + KEY `md5_header_index` (`md5_header`(4)) +) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8; + +CREATE INDEX `md5_header_index` ON `PREFIX_customer_message_sync_imap` (md5_header(4)); + +ALTER TABLE `PREFIX_customer_message` ADD `private` TINYINT NOT NULL DEFAULT '0' AFTER `user_agent`;