PageRenderTime 73ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/controllers/admin/AdminCustomersController.php

https://github.com/netplayer/PrestaShop
PHP | 1054 lines | 886 code | 95 blank | 73 comment | 108 complexity | 0dbb8b92ea770641d4d10151ae2e0991 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /*
  3. * 2007-2014 PrestaShop
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@prestashop.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
  18. * versions in the future. If you wish to customize PrestaShop for your
  19. * needs please refer to http://www.prestashop.com for more information.
  20. *
  21. * @author PrestaShop SA <contact@prestashop.com>
  22. * @copyright 2007-2014 PrestaShop SA
  23. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  24. * International Registered Trademark & Property of PrestaShop SA
  25. */
  26. class AdminCustomersControllerCore extends AdminController
  27. {
  28. protected $delete_mode;
  29. protected $_defaultOrderBy = 'date_add';
  30. protected $_defaultOrderWay = 'DESC';
  31. protected $can_add_customer = true;
  32. public function __construct()
  33. {
  34. $this->bootstrap = true;
  35. $this->required_database = true;
  36. $this->required_fields = array('newsletter','optin');
  37. $this->table = 'customer';
  38. $this->className = 'Customer';
  39. $this->lang = false;
  40. $this->deleted = true;
  41. $this->explicitSelect = true;
  42. $this->allow_export = true;
  43. $this->addRowAction('edit');
  44. $this->addRowAction('view');
  45. $this->addRowAction('delete');
  46. $this->bulk_actions = array(
  47. 'delete' => array(
  48. 'text' => $this->l('Delete selected'),
  49. 'confirm' => $this->l('Delete selected items?'),
  50. 'icon' => 'icon-trash'
  51. )
  52. );
  53. $this->context = Context::getContext();
  54. $this->default_form_language = $this->context->language->id;
  55. $titles_array = array();
  56. $genders = Gender::getGenders($this->context->language->id);
  57. foreach ($genders as $gender)
  58. $titles_array[$gender->id_gender] = $gender->name;
  59. $this->_select = '
  60. a.date_add, gl.name as title, (
  61. SELECT SUM(total_paid_real / conversion_rate) FROM '._DB_PREFIX_.'orders o
  62. WHERE o.id_customer = a.id_customer
  63. '.Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o').'
  64. AND a.active = 1
  65. ) as total_spent, (
  66. SELECT c.date_add FROM '._DB_PREFIX_.'guest g
  67. LEFT JOIN '._DB_PREFIX_.'connections c ON c.id_guest = g.id_guest
  68. WHERE g.id_customer = a.id_customer
  69. ORDER BY c.date_add DESC
  70. LIMIT 1
  71. ) as connect';
  72. $this->_join = 'LEFT JOIN '._DB_PREFIX_.'gender_lang gl ON (a.id_gender = gl.id_gender AND gl.id_lang = '.(int)$this->context->language->id.')';
  73. $this->fields_list = array(
  74. 'id_customer' => array(
  75. 'title' => $this->l('ID'),
  76. 'align' => 'text-center',
  77. 'class' => 'fixed-width-xs'
  78. ),
  79. 'title' => array(
  80. 'title' => $this->l('Social title'),
  81. 'filter_key' => 'a!id_gender',
  82. 'type' => 'select',
  83. 'list' => $titles_array,
  84. 'filter_type' => 'int',
  85. 'order_key' => 'gl!name'
  86. ),
  87. 'lastname' => array(
  88. 'title' => $this->l('Last name')
  89. ),
  90. 'firstname' => array(
  91. 'title' => $this->l('First Name')
  92. ),
  93. 'email' => array(
  94. 'title' => $this->l('Email address')
  95. ),
  96. );
  97. if (Configuration::get('PS_B2B_ENABLE'))
  98. {
  99. $this->fields_list = array_merge($this->fields_list, array(
  100. 'company' => array(
  101. 'title' => $this->l('Company')
  102. ),
  103. ));
  104. }
  105. $this->fields_list = array_merge($this->fields_list, array(
  106. 'total_spent' => array(
  107. 'title' => $this->l('Sales'),
  108. 'type' => 'price',
  109. 'search' => false,
  110. 'havingFilter' => true,
  111. 'align' => 'text-right',
  112. 'badge_success' => true
  113. ),
  114. 'active' => array(
  115. 'title' => $this->l('Enabled'),
  116. 'align' => 'text-center',
  117. 'active' => 'status',
  118. 'type' => 'bool',
  119. 'orderby' => false,
  120. 'filter_key' => 'a!active'
  121. ),
  122. 'newsletter' => array(
  123. 'title' => $this->l('Newsletter'),
  124. 'align' => 'text-center',
  125. 'type' => 'bool',
  126. 'callback' => 'printNewsIcon',
  127. 'orderby' => false
  128. ),
  129. 'optin' => array(
  130. 'title' => $this->l('Opt-in'),
  131. 'align' => 'text-center',
  132. 'type' => 'bool',
  133. 'callback' => 'printOptinIcon',
  134. 'orderby' => false
  135. ),
  136. 'date_add' => array(
  137. 'title' => $this->l('Registration'),
  138. 'type' => 'date',
  139. 'align' => 'text-right'
  140. ),
  141. 'connect' => array(
  142. 'title' => $this->l('Last visit'),
  143. 'type' => 'datetime',
  144. 'search' => false,
  145. 'havingFilter' => true
  146. )
  147. ));
  148. $this->shopLinkType = 'shop';
  149. $this->shopShareDatas = Shop::SHARE_CUSTOMER;
  150. parent::__construct();
  151. // Check if we can add a customer
  152. if (Shop::isFeatureActive() && (Shop::getContext() == Shop::CONTEXT_ALL || Shop::getContext() == Shop::CONTEXT_GROUP))
  153. $this->can_add_customer = false;
  154. }
  155. public function postProcess()
  156. {
  157. if (!$this->can_add_customer && $this->display == 'add')
  158. $this->redirect_after = $this->context->link->getAdminLink('AdminCustomers');
  159. parent::postProcess();
  160. }
  161. public function initContent()
  162. {
  163. if ($this->action == 'select_delete')
  164. $this->context->smarty->assign(array(
  165. 'delete_form' => true,
  166. 'url_delete' => htmlentities($_SERVER['REQUEST_URI']),
  167. 'boxes' => $this->boxes,
  168. ));
  169. if (!$this->can_add_customer && !$this->display)
  170. $this->informations[] = $this->l('You have to select a shop if you want to create a customer.');
  171. parent::initContent();
  172. }
  173. public function initToolbar()
  174. {
  175. parent::initToolbar();
  176. if (!$this->can_add_customer)
  177. unset($this->toolbar_btn['new']);
  178. else if (!$this->display) //display import button only on listing
  179. {
  180. $this->toolbar_btn['import'] = array(
  181. 'href' => $this->context->link->getAdminLink('AdminImport', true).'&import_type=customers',
  182. 'desc' => $this->l('Import')
  183. );
  184. }
  185. }
  186. public function getList($id_lang, $orderBy = null, $orderWay = null, $start = 0, $limit = null, $id_lang_shop = null)
  187. {
  188. parent::getList($id_lang, $orderBy, $orderWay, $start, $limit, $id_lang_shop);
  189. if ($this->_list)
  190. foreach ($this->_list as &$row)
  191. $row['badge_success'] = $row['total_spent'] > 0;
  192. }
  193. public function initToolbarTitle()
  194. {
  195. parent::initToolbarTitle();
  196. switch ($this->display)
  197. {
  198. case '':
  199. case 'list':
  200. $this->toolbar_title[] = $this->l('Manage your Customers');
  201. break;
  202. case 'view':
  203. if (($customer = $this->loadObject(true)) && Validate::isLoadedObject($customer))
  204. $this->toolbar_title[] = sprintf('Information about Customer: %s', Tools::substr($customer->firstname, 0, 1).'. '.$customer->lastname);
  205. break;
  206. case 'add':
  207. case 'edit':
  208. if (($customer = $this->loadObject(true)) && Validate::isLoadedObject($customer))
  209. $this->toolbar_title[] = sprintf($this->l('Editing Customer: %s'), Tools::substr($customer->firstname, 0, 1).'. '.$customer->lastname);
  210. else
  211. $this->toolbar_title[] = $this->l('Creating a new Customer');
  212. break;
  213. }
  214. }
  215. public function initPageHeaderToolbar()
  216. {
  217. if (empty($this->display))
  218. $this->page_header_toolbar_btn['new_customer'] = array(
  219. 'href' => self::$currentIndex.'&addcustomer&token='.$this->token,
  220. 'desc' => $this->l('Add new customer', null, null, false),
  221. 'icon' => 'process-icon-new'
  222. );
  223. parent::initPageHeaderToolbar();
  224. }
  225. public function initProcess()
  226. {
  227. parent::initProcess();
  228. if (Tools::isSubmit('submitGuestToCustomer') && $this->id_object)
  229. {
  230. if ($this->tabAccess['edit'] === '1')
  231. $this->action = 'guest_to_customer';
  232. else
  233. $this->errors[] = Tools::displayError('You do not have permission to edit this.');
  234. }
  235. elseif (Tools::isSubmit('changeNewsletterVal') && $this->id_object)
  236. {
  237. if ($this->tabAccess['edit'] === '1')
  238. $this->action = 'change_newsletter_val';
  239. else
  240. $this->errors[] = Tools::displayError('You do not have permission to edit this.');
  241. }
  242. elseif (Tools::isSubmit('changeOptinVal') && $this->id_object)
  243. {
  244. if ($this->tabAccess['edit'] === '1')
  245. $this->action = 'change_optin_val';
  246. else
  247. $this->errors[] = Tools::displayError('You do not have permission to edit this.');
  248. }
  249. // When deleting, first display a form to select the type of deletion
  250. if ($this->action == 'delete' || $this->action == 'bulkdelete')
  251. if (Tools::getValue('deleteMode') == 'real' || Tools::getValue('deleteMode') == 'deleted')
  252. $this->delete_mode = Tools::getValue('deleteMode');
  253. else
  254. $this->action = 'select_delete';
  255. }
  256. public function renderList()
  257. {
  258. if (Tools::isSubmit('submitBulkdelete'.$this->table) || Tools::isSubmit('delete'.$this->table))
  259. $this->tpl_list_vars = array(
  260. 'delete_customer' => true,
  261. 'REQUEST_URI' => $_SERVER['REQUEST_URI'],
  262. 'POST' => $_POST
  263. );
  264. return parent::renderList();
  265. }
  266. public function renderForm()
  267. {
  268. if (!($obj = $this->loadObject(true)))
  269. return;
  270. $genders = Gender::getGenders();
  271. $list_genders = array();
  272. foreach ($genders as $key => $gender)
  273. {
  274. $list_genders[$key]['id'] = 'gender_'.$gender->id;
  275. $list_genders[$key]['value'] = $gender->id;
  276. $list_genders[$key]['label'] = $gender->name;
  277. }
  278. $years = Tools::dateYears();
  279. $months = Tools::dateMonths();
  280. $days = Tools::dateDays();
  281. $groups = Group::getGroups($this->default_form_language, true);
  282. $this->fields_form = array(
  283. 'legend' => array(
  284. 'title' => $this->l('Customer'),
  285. 'icon' => 'icon-user'
  286. ),
  287. 'input' => array(
  288. array(
  289. 'type' => 'radio',
  290. 'label' => $this->l('Social title'),
  291. 'name' => 'id_gender',
  292. 'required' => false,
  293. 'class' => 't',
  294. 'values' => $list_genders
  295. ),
  296. array(
  297. 'type' => 'text',
  298. 'label' => $this->l('First name'),
  299. 'name' => 'firstname',
  300. 'required' => true,
  301. 'col' => '4',
  302. 'hint' => $this->l('Forbidden characters:').' 0-9!&lt;&gt;,;?=+()@#"째{}_$%:'
  303. ),
  304. array(
  305. 'type' => 'text',
  306. 'label' => $this->l('Last name'),
  307. 'name' => 'lastname',
  308. 'required' => true,
  309. 'col' => '4',
  310. 'hint' => $this->l('Invalid characters:').' 0-9!&lt;&gt;,;?=+()@#"째{}_$%:'
  311. ),
  312. array(
  313. 'type' => 'text',
  314. 'prefix' => '<i class="icon-envelope-o"></i>',
  315. 'label' => $this->l('Email address'),
  316. 'name' => 'email',
  317. 'col' => '4',
  318. 'required' => true,
  319. 'autocomplete' => false
  320. ),
  321. array(
  322. 'type' => 'password',
  323. 'label' => $this->l('Password'),
  324. 'name' => 'passwd',
  325. 'required' => ($obj->id ? false : true),
  326. 'col' => '4',
  327. 'hint' => ($obj->id ? $this->l('Leave this field blank if there\'s no change.') :
  328. sprintf($this->l('Minimum of %s characters.'), Validate::PASSWORD_LENGTH))
  329. ),
  330. array(
  331. 'type' => 'birthday',
  332. 'label' => $this->l('Birthday'),
  333. 'name' => 'birthday',
  334. 'options' => array(
  335. 'days' => $days,
  336. 'months' => $months,
  337. 'years' => $years
  338. )
  339. ),
  340. array(
  341. 'type' => 'switch',
  342. 'label' => $this->l('Status'),
  343. 'name' => 'active',
  344. 'required' => false,
  345. 'class' => 't',
  346. 'is_bool' => true,
  347. 'values' => array(
  348. array(
  349. 'id' => 'active_on',
  350. 'value' => 1,
  351. 'label' => $this->l('Enabled')
  352. ),
  353. array(
  354. 'id' => 'active_off',
  355. 'value' => 0,
  356. 'label' => $this->l('Disabled')
  357. )
  358. ),
  359. 'hint' => $this->l('Enable or disable customer login.')
  360. ),
  361. array(
  362. 'type' => 'switch',
  363. 'label' => $this->l('Newsletter'),
  364. 'name' => 'newsletter',
  365. 'required' => false,
  366. 'class' => 't',
  367. 'is_bool' => true,
  368. 'values' => array(
  369. array(
  370. 'id' => 'newsletter_on',
  371. 'value' => 1,
  372. 'label' => $this->l('Enabled')
  373. ),
  374. array(
  375. 'id' => 'newsletter_off',
  376. 'value' => 0,
  377. 'label' => $this->l('Disabled')
  378. )
  379. ),
  380. 'hint' => $this->l('This customer will receive your newsletter via email.')
  381. ),
  382. array(
  383. 'type' => 'switch',
  384. 'label' => $this->l('Opt-in'),
  385. 'name' => 'optin',
  386. 'required' => false,
  387. 'class' => 't',
  388. 'is_bool' => true,
  389. 'values' => array(
  390. array(
  391. 'id' => 'optin_on',
  392. 'value' => 1,
  393. 'label' => $this->l('Enabled')
  394. ),
  395. array(
  396. 'id' => 'optin_off',
  397. 'value' => 0,
  398. 'label' => $this->l('Disabled')
  399. )
  400. ),
  401. 'hint' => $this->l('This customer will receive your ads via email.')
  402. ),
  403. )
  404. );
  405. // if we add a customer via fancybox (ajax), it's a customer and he doesn't need to be added to the visitor and guest groups
  406. if (Tools::isSubmit('addcustomer') && Tools::isSubmit('submitFormAjax'))
  407. {
  408. $visitor_group = Configuration::get('PS_UNIDENTIFIED_GROUP');
  409. $guest_group = Configuration::get('PS_GUEST_GROUP');
  410. foreach ($groups as $key => $g)
  411. if (in_array($g['id_group'], array($visitor_group, $guest_group)))
  412. unset($groups[$key]);
  413. }
  414. $this->fields_form['input'] = array_merge(
  415. $this->fields_form['input'],
  416. array(
  417. array(
  418. 'type' => 'group',
  419. 'label' => $this->l('Group access'),
  420. 'name' => 'groupBox',
  421. 'values' => $groups,
  422. 'required' => true,
  423. 'col' => '6',
  424. 'hint' => $this->l('Select all the groups that you would like to apply to this customer.')
  425. ),
  426. array(
  427. 'type' => 'select',
  428. 'label' => $this->l('Default customer group'),
  429. 'name' => 'id_default_group',
  430. 'options' => array(
  431. 'query' => $groups,
  432. 'id' => 'id_group',
  433. 'name' => 'name'
  434. ),
  435. 'col' => '4',
  436. 'hint' => array(
  437. $this->l('This group will be the user\'s default group.'),
  438. $this->l('Only the discount for the selected group will be applied to this customer.')
  439. )
  440. )
  441. )
  442. );
  443. // if customer is a guest customer, password hasn't to be there
  444. if ($obj->id && ($obj->is_guest && $obj->id_default_group == Configuration::get('PS_GUEST_GROUP')))
  445. {
  446. foreach ($this->fields_form['input'] as $k => $field)
  447. if ($field['type'] == 'password')
  448. array_splice($this->fields_form['input'], $k, 1);
  449. }
  450. if (Configuration::get('PS_B2B_ENABLE'))
  451. {
  452. $risks = Risk::getRisks();
  453. $list_risks = array();
  454. foreach ($risks as $key => $risk)
  455. {
  456. $list_risks[$key]['id_risk'] = (int)$risk->id;
  457. $list_risks[$key]['name'] = $risk->name;
  458. }
  459. $this->fields_form['input'][] = array(
  460. 'type' => 'text',
  461. 'label' => $this->l('Company'),
  462. 'name' => 'company'
  463. );
  464. $this->fields_form['input'][] = array(
  465. 'type' => 'text',
  466. 'label' => $this->l('SIRET'),
  467. 'name' => 'siret'
  468. );
  469. $this->fields_form['input'][] = array(
  470. 'type' => 'text',
  471. 'label' => $this->l('APE'),
  472. 'name' => 'ape'
  473. );
  474. $this->fields_form['input'][] = array(
  475. 'type' => 'text',
  476. 'label' => $this->l('Website'),
  477. 'name' => 'website'
  478. );
  479. $this->fields_form['input'][] = array(
  480. 'type' => 'text',
  481. 'label' => $this->l('Allowed outstanding amount'),
  482. 'name' => 'outstanding_allow_amount',
  483. 'hint' => $this->l('Valid characters:').' 0-9',
  484. 'suffix' => $this->context->currency->sign
  485. );
  486. $this->fields_form['input'][] = array(
  487. 'type' => 'text',
  488. 'label' => $this->l('Maximum number of payment days'),
  489. 'name' => 'max_payment_days',
  490. 'hint' => $this->l('Valid characters:').' 0-9'
  491. );
  492. $this->fields_form['input'][] = array(
  493. 'type' => 'select',
  494. 'label' => $this->l('Risk rating'),
  495. 'name' => 'id_risk',
  496. 'required' => false,
  497. 'class' => 't',
  498. 'options' => array(
  499. 'query' => $list_risks,
  500. 'id' => 'id_risk',
  501. 'name' => 'name'
  502. ),
  503. );
  504. }
  505. $this->fields_form['submit'] = array(
  506. 'title' => $this->l('Save'),
  507. );
  508. $birthday = explode('-', $this->getFieldValue($obj, 'birthday'));
  509. $this->fields_value = array(
  510. 'years' => $this->getFieldValue($obj, 'birthday') ? $birthday[0] : 0,
  511. 'months' => $this->getFieldValue($obj, 'birthday') ? $birthday[1] : 0,
  512. 'days' => $this->getFieldValue($obj, 'birthday') ? $birthday[2] : 0,
  513. );
  514. // Added values of object Group
  515. if (!Validate::isUnsignedId($obj->id))
  516. $customer_groups = array();
  517. else
  518. $customer_groups = $obj->getGroups();
  519. $customer_groups_ids = array();
  520. if (is_array($customer_groups))
  521. foreach ($customer_groups as $customer_group)
  522. $customer_groups_ids[] = $customer_group;
  523. // if empty $carrier_groups_ids : object creation : we set the default groups
  524. if (empty($customer_groups_ids))
  525. {
  526. $preselected = array(Configuration::get('PS_UNIDENTIFIED_GROUP'), Configuration::get('PS_GUEST_GROUP'), Configuration::get('PS_CUSTOMER_GROUP'));
  527. $customer_groups_ids = array_merge($customer_groups_ids, $preselected);
  528. }
  529. foreach ($groups as $group)
  530. $this->fields_value['groupBox_'.$group['id_group']] =
  531. Tools::getValue('groupBox_'.$group['id_group'], in_array($group['id_group'], $customer_groups_ids));
  532. return parent::renderForm();
  533. }
  534. public function beforeAdd($customer)
  535. {
  536. $customer->id_shop = $this->context->shop->id;
  537. }
  538. public function renderKpis()
  539. {
  540. $time = time();
  541. $kpis = array();
  542. /* The data generation is located in AdminStatsControllerCore */
  543. $helper = new HelperKpi();
  544. $helper->id = 'box-gender';
  545. $helper->icon = 'icon-male';
  546. $helper->color = 'color1';
  547. $helper->title = $this->l('Customers', null, null, false);
  548. $helper->subtitle = $this->l('All Time', null, null, false);
  549. if (ConfigurationKPI::get('CUSTOMER_MAIN_GENDER', $this->context->language->id) !== false)
  550. $helper->value = ConfigurationKPI::get('CUSTOMER_MAIN_GENDER', $this->context->language->id);
  551. if (ConfigurationKPI::get('CUSTOMER_MAIN_GENDER_EXPIRE', $this->context->language->id) < $time)
  552. $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=customer_main_gender';
  553. $kpis[] = $helper->generate();
  554. $helper = new HelperKpi();
  555. $helper->id = 'box-age';
  556. $helper->icon = 'icon-calendar';
  557. $helper->color = 'color2';
  558. $helper->title = $this->l('Average Age', 'AdminTab', null, false);
  559. $helper->subtitle = $this->l('All Time', null, null, false);
  560. if (ConfigurationKPI::get('AVG_CUSTOMER_AGE', $this->context->language->id) !== false)
  561. $helper->value = ConfigurationKPI::get('AVG_CUSTOMER_AGE', $this->context->language->id);
  562. if (ConfigurationKPI::get('AVG_CUSTOMER_AGE_EXPIRE', $this->context->language->id) < $time)
  563. $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=avg_customer_age';
  564. $kpis[] = $helper->generate();
  565. $helper = new HelperKpi();
  566. $helper->id = 'box-orders';
  567. $helper->icon = 'icon-retweet';
  568. $helper->color = 'color3';
  569. $helper->title = $this->l('Orders per Customer', null, null, false);
  570. $helper->subtitle = $this->l('All Time', null, null, false);
  571. if (ConfigurationKPI::get('ORDERS_PER_CUSTOMER') !== false)
  572. $helper->value = ConfigurationKPI::get('ORDERS_PER_CUSTOMER');
  573. if (ConfigurationKPI::get('ORDERS_PER_CUSTOMER_EXPIRE') < $time)
  574. $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=orders_per_customer';
  575. $kpis[] = $helper->generate();
  576. $helper = new HelperKpi();
  577. $helper->id = 'box-newsletter';
  578. $helper->icon = 'icon-envelope';
  579. $helper->color = 'color4';
  580. $helper->title = $this->l('Newsletter Registrations', null, null, false);
  581. $helper->subtitle = $this->l('All Time', null, null, false);
  582. if (ConfigurationKPI::get('NEWSLETTER_REGISTRATIONS') !== false)
  583. $helper->value = ConfigurationKPI::get('NEWSLETTER_REGISTRATIONS');
  584. if (ConfigurationKPI::get('NEWSLETTER_REGISTRATIONS_EXPIRE') < $time)
  585. $helper->source = $this->context->link->getAdminLink('AdminStats').'&ajax=1&action=getKpi&kpi=newsletter_registrations';
  586. $kpis[] = $helper->generate();
  587. $helper = new HelperKpiRow();
  588. $helper->kpis = $kpis;
  589. return $helper->generate();
  590. }
  591. public function renderView()
  592. {
  593. if (!($customer = $this->loadObject()))
  594. return;
  595. $this->context->customer = $customer;
  596. $gender = new Gender($customer->id_gender, $this->context->language->id);
  597. $gender_image = $gender->getImage();
  598. $customer_stats = $customer->getStats();
  599. $sql = 'SELECT SUM(total_paid_real) FROM '._DB_PREFIX_.'orders WHERE id_customer = %d AND valid = 1';
  600. if ($total_customer = Db::getInstance()->getValue(sprintf($sql, $customer->id)))
  601. {
  602. $sql = 'SELECT SQL_CALC_FOUND_ROWS COUNT(*) FROM '._DB_PREFIX_.'orders WHERE valid = 1 AND id_customer != '.(int)$customer->id.' GROUP BY id_customer HAVING SUM(total_paid_real) > %d';
  603. Db::getInstance()->getValue(sprintf($sql, (int)$total_customer));
  604. $count_better_customers = (int)Db::getInstance()->getValue('SELECT FOUND_ROWS()') + 1;
  605. }
  606. else
  607. $count_better_customers = '-';
  608. $orders = Order::getCustomerOrders($customer->id, true);
  609. $total_orders = count($orders);
  610. for ($i = 0; $i < $total_orders; $i++)
  611. {
  612. $orders[$i]['total_paid_real_not_formated'] = $orders[$i]['total_paid_real'];
  613. $orders[$i]['total_paid_real'] = Tools::displayPrice($orders[$i]['total_paid_real'], new Currency((int)$orders[$i]['id_currency']));
  614. }
  615. $messages = CustomerThread::getCustomerMessages((int)$customer->id);
  616. $total_messages = count($messages);
  617. for ($i = 0; $i < $total_messages; $i++)
  618. {
  619. $messages[$i]['message'] = substr(strip_tags(html_entity_decode($messages[$i]['message'], ENT_NOQUOTES, 'UTF-8')), 0, 75);
  620. $messages[$i]['date_add'] = Tools::displayDate($messages[$i]['date_add'], null, true);
  621. }
  622. $groups = $customer->getGroups();
  623. $total_groups = count($groups);
  624. for ($i = 0; $i < $total_groups; $i++)
  625. {
  626. $group = new Group($groups[$i]);
  627. $groups[$i] = array();
  628. $groups[$i]['id_group'] = $group->id;
  629. $groups[$i]['name'] = $group->name[$this->default_form_language];
  630. }
  631. $total_ok = 0;
  632. $orders_ok = array();
  633. $orders_ko = array();
  634. foreach ($orders as $order)
  635. {
  636. if (!isset($order['order_state']))
  637. $order['order_state'] = $this->l('There is no status defined for this order.');
  638. if ($order['valid'])
  639. {
  640. $orders_ok[] = $order;
  641. $total_ok += $order['total_paid_real_not_formated'];
  642. }
  643. else
  644. $orders_ko[] = $order;
  645. }
  646. $products = $customer->getBoughtProducts();
  647. $carts = Cart::getCustomerCarts($customer->id);
  648. $total_carts = count($carts);
  649. for ($i = 0; $i < $total_carts; $i++)
  650. {
  651. $cart = new Cart((int)$carts[$i]['id_cart']);
  652. $this->context->cart = $cart;
  653. $summary = $cart->getSummaryDetails();
  654. $currency = new Currency((int)$carts[$i]['id_currency']);
  655. $carrier = new Carrier((int)$carts[$i]['id_carrier']);
  656. $carts[$i]['id_cart'] = sprintf('%06d', $carts[$i]['id_cart']);
  657. $carts[$i]['date_add'] = Tools::displayDate($carts[$i]['date_add'], null, true);
  658. $carts[$i]['total_price'] = Tools::displayPrice($summary['total_price'], $currency);
  659. $carts[$i]['name'] = $carrier->name;
  660. }
  661. $sql = 'SELECT DISTINCT cp.id_product, c.id_cart, c.id_shop, cp.id_shop AS cp_id_shop
  662. FROM '._DB_PREFIX_.'cart_product cp
  663. JOIN '._DB_PREFIX_.'cart c ON (c.id_cart = cp.id_cart)
  664. JOIN '._DB_PREFIX_.'product p ON (cp.id_product = p.id_product)
  665. WHERE c.id_customer = '.(int)$customer->id.'
  666. AND cp.id_product NOT IN (
  667. SELECT product_id
  668. FROM '._DB_PREFIX_.'orders o
  669. JOIN '._DB_PREFIX_.'order_detail od ON (o.id_order = od.id_order)
  670. WHERE o.valid = 1 AND o.id_customer = '.(int)$customer->id.'
  671. )';
  672. $interested = Db::getInstance()->executeS($sql);
  673. $total_interested = count($interested);
  674. for ($i = 0; $i < $total_interested; $i++)
  675. {
  676. $product = new Product($interested[$i]['id_product'], false, $this->default_form_language, $interested[$i]['id_shop']);
  677. if (!Validate::isLoadedObject($product))
  678. continue;
  679. $interested[$i]['url'] = $this->context->link->getProductLink(
  680. $product->id,
  681. $product->link_rewrite,
  682. Category::getLinkRewrite($product->id_category_default, $this->default_form_language),
  683. null,
  684. null,
  685. $interested[$i]['cp_id_shop']
  686. );
  687. $interested[$i]['id'] = (int)$product->id;
  688. $interested[$i]['name'] = Tools::htmlentitiesUTF8($product->name);
  689. }
  690. $connections = $customer->getLastConnections();
  691. if (!is_array($connections))
  692. $connections = array();
  693. $total_connections = count($connections);
  694. for ($i = 0; $i < $total_connections; $i++)
  695. $connections[$i]['http_referer'] = $connections[$i]['http_referer'] ? preg_replace('/^www./', '', parse_url($connections[$i]['http_referer'], PHP_URL_HOST)) : $this->l('Direct link');
  696. $referrers = Referrer::getReferrers($customer->id);
  697. $total_referrers = count($referrers);
  698. for ($i = 0; $i < $total_referrers; $i++)
  699. $referrers[$i]['date_add'] = Tools::displayDate($referrers[$i]['date_add'],null , true);
  700. $customerLanguage = new Language($customer->id_lang);
  701. $shop = new Shop($customer->id_shop);
  702. $this->tpl_view_vars = array(
  703. 'customer' => $customer,
  704. 'gender' => $gender,
  705. 'gender_image' => $gender_image,
  706. // General information of the customer
  707. 'registration_date' => Tools::displayDate($customer->date_add,null , true),
  708. 'customer_stats' => $customer_stats,
  709. 'last_visit' => Tools::displayDate($customer_stats['last_visit'],null , true),
  710. 'count_better_customers' => $count_better_customers,
  711. 'shop_is_feature_active' => Shop::isFeatureActive(),
  712. 'name_shop' => $shop->name,
  713. 'customer_birthday' => Tools::displayDate($customer->birthday),
  714. 'last_update' => Tools::displayDate($customer->date_upd,null , true),
  715. 'customer_exists' => Customer::customerExists($customer->email),
  716. 'id_lang' => $customer->id_lang,
  717. 'customerLanguage' => $customerLanguage,
  718. // Add a Private note
  719. 'customer_note' => Tools::htmlentitiesUTF8($customer->note),
  720. // Messages
  721. 'messages' => $messages,
  722. // Groups
  723. 'groups' => $groups,
  724. // Orders
  725. 'orders' => $orders,
  726. 'orders_ok' => $orders_ok,
  727. 'orders_ko' => $orders_ko,
  728. 'total_ok' => Tools::displayPrice($total_ok, $this->context->currency->id),
  729. // Products
  730. 'products' => $products,
  731. // Addresses
  732. 'addresses' => $customer->getAddresses($this->default_form_language),
  733. // Discounts
  734. 'discounts' => CartRule::getCustomerCartRules($this->default_form_language, $customer->id, false, false),
  735. // Carts
  736. 'carts' => $carts,
  737. // Interested
  738. 'interested' => $interested,
  739. // Connections
  740. 'connections' => $connections,
  741. // Referrers
  742. 'referrers' => $referrers,
  743. 'show_toolbar' => true
  744. );
  745. return parent::renderView();
  746. }
  747. public function processDelete()
  748. {
  749. $this->_setDeletedMode();
  750. parent::processDelete();
  751. }
  752. protected function _setDeletedMode()
  753. {
  754. if ($this->delete_mode == 'real')
  755. $this->deleted = false;
  756. elseif ($this->delete_mode == 'deleted')
  757. $this->deleted = true;
  758. else
  759. {
  760. $this->errors[] = Tools::displayError('Unknown delete mode:').' '.$this->deleted;
  761. return;
  762. }
  763. }
  764. protected function processBulkDelete()
  765. {
  766. $this->_setDeletedMode();
  767. parent::processBulkDelete();
  768. }
  769. public function processAdd()
  770. {
  771. if (Tools::getValue('submitFormAjax'))
  772. $this->redirect_after = false;
  773. // Check that the new email is not already in use
  774. $customer_email = strval(Tools::getValue('email'));
  775. $customer = new Customer();
  776. if (Validate::isEmail($customer_email))
  777. $customer->getByEmail($customer_email);
  778. if ($customer->id)
  779. {
  780. $this->errors[] = Tools::displayError('An account already exists for this email address:').' '.$customer_email;
  781. $this->display = 'edit';
  782. return $customer;
  783. }
  784. elseif (trim(Tools::getValue('passwd')) == '')
  785. {
  786. $this->validateRules();
  787. $this->errors[] = Tools::displayError('Password can not be empty.');
  788. $this->display = 'edit';
  789. }
  790. elseif ($customer = parent::processAdd())
  791. {
  792. $this->context->smarty->assign('new_customer', $customer);
  793. return $customer;
  794. }
  795. return false;
  796. }
  797. public function processUpdate()
  798. {
  799. if (Validate::isLoadedObject($this->object))
  800. {
  801. $customer_email = strval(Tools::getValue('email'));
  802. // check if e-mail already used
  803. if ($customer_email != $this->object->email)
  804. {
  805. $customer = new Customer();
  806. if (Validate::isEmail($customer_email))
  807. $customer->getByEmail($customer_email);
  808. if (($customer->id) && ($customer->id != (int)$this->object->id))
  809. $this->errors[] = Tools::displayError('An account already exists for this email address:').' '.$customer_email;
  810. }
  811. return parent::processUpdate();
  812. }
  813. else
  814. $this->errors[] = Tools::displayError('An error occurred while loading the object.').'
  815. <b>'.$this->table.'</b> '.Tools::displayError('(cannot load object)');
  816. }
  817. public function processSave()
  818. {
  819. // Check that default group is selected
  820. if (!is_array(Tools::getValue('groupBox')) || !in_array(Tools::getValue('id_default_group'), Tools::getValue('groupBox')))
  821. $this->errors[] = Tools::displayError('A default customer group must be selected in group box.');
  822. // Check the requires fields which are settings in the BO
  823. $customer = new Customer();
  824. $this->errors = array_merge($this->errors, $customer->validateFieldsRequiredDatabase());
  825. return parent::processSave();
  826. }
  827. protected function afterDelete($object, $old_id)
  828. {
  829. $customer = new Customer($old_id);
  830. $addresses = $customer->getAddresses($this->default_form_language);
  831. foreach ($addresses as $k => $v)
  832. {
  833. $address = new Address($v['id_address']);
  834. $address->id_customer = $object->id;
  835. $address->save();
  836. }
  837. return true;
  838. }
  839. /**
  840. * Transform a guest account into a registered customer account
  841. */
  842. public function processGuestToCustomer()
  843. {
  844. $customer = new Customer((int)Tools::getValue('id_customer'));
  845. if (!Validate::isLoadedObject($customer))
  846. $this->errors[] = Tools::displayError('This customer does not exist.');
  847. if (Customer::customerExists($customer->email))
  848. $this->errors[] = Tools::displayError('This customer already exists as a non-guest.');
  849. else if ($customer->transformToCustomer(Tools::getValue('id_lang', $this->context->language->id)))
  850. Tools::redirectAdmin(self::$currentIndex.'&'.$this->identifier.'='.$customer->id.'&conf=3&token='.$this->token);
  851. else
  852. $this->errors[] = Tools::displayError('An error occurred while updating customer information.');
  853. }
  854. /**
  855. * Toggle the newsletter flag
  856. */
  857. public function processChangeNewsletterVal()
  858. {
  859. $customer = new Customer($this->id_object);
  860. if (!Validate::isLoadedObject($customer))
  861. $this->errors[] = Tools::displayError('An error occurred while updating customer information.');
  862. $customer->newsletter = $customer->newsletter ? 0 : 1;
  863. if (!$customer->update())
  864. $this->errors[] = Tools::displayError('An error occurred while updating customer information.');
  865. Tools::redirectAdmin(self::$currentIndex.'&token='.$this->token);
  866. }
  867. /**
  868. * Toggle newsletter optin flag
  869. */
  870. public function processChangeOptinVal()
  871. {
  872. $customer = new Customer($this->id_object);
  873. if (!Validate::isLoadedObject($customer))
  874. $this->errors[] = Tools::displayError('An error occurred while updating customer information.');
  875. $customer->optin = $customer->optin ? 0 : 1;
  876. if (!$customer->update())
  877. $this->errors[] = Tools::displayError('An error occurred while updating customer information.');
  878. Tools::redirectAdmin(self::$currentIndex.'&token='.$this->token);
  879. }
  880. public function printNewsIcon($value, $customer)
  881. {
  882. return '<a class="list-action-enable '.($value ? 'action-enabled' : 'action-disabled').'" href="index.php?tab=AdminCustomers&id_customer='
  883. .(int)$customer['id_customer'].'&changeNewsletterVal&token='.Tools::getAdminTokenLite('AdminCustomers').'">
  884. '.($value ? '<i class="icon-check"></i>' : '<i class="icon-remove"></i>').
  885. '</a>';
  886. }
  887. public function printOptinIcon($value, $customer)
  888. {
  889. return '<a class="list-action-enable '.($value ? 'action-enabled' : 'action-disabled').'" href="index.php?tab=AdminCustomers&id_customer='
  890. .(int)$customer['id_customer'].'&changeOptinVal&token='.Tools::getAdminTokenLite('AdminCustomers').'">
  891. '.($value ? '<i class="icon-check"></i>' : '<i class="icon-remove"></i>').
  892. '</a>';
  893. }
  894. /**
  895. * @param string $token
  896. * @param integer $id
  897. * @param string $name
  898. * @return mixed
  899. */
  900. public function displayDeleteLink($token = null, $id, $name = null)
  901. {
  902. $tpl = $this->createTemplate('helpers/list/list_action_delete.tpl');
  903. $customer = new Customer($id);
  904. $name = $customer->lastname.' '.$customer->firstname;
  905. $name = '\n\n'.$this->l('Name:', 'helper').' '.$name;
  906. $tpl->assign(array(
  907. 'href' => self::$currentIndex.'&'.$this->identifier.'='.$id.'&delete'.$this->table.'&token='.($token != null ? $token : $this->token),
  908. 'confirm' => $this->l('Delete the selected item?').$name,
  909. 'action' => $this->l('Delete'),
  910. 'id' => $id,
  911. ));
  912. return $tpl->fetch();
  913. }
  914. /**
  915. * add to $this->content the result of Customer::SearchByName
  916. * (encoded in json)
  917. *
  918. * @return void
  919. */
  920. public function ajaxProcessSearchCustomers()
  921. {
  922. $searches = explode(' ', Tools::getValue('customer_search'));
  923. $customers = array();
  924. $searches = array_unique($searches);
  925. foreach ($searches as $search)
  926. if (!empty($search) && $results = Customer::searchByName($search))
  927. foreach ($results as $result)
  928. $customers[$result['id_customer']] = $result;
  929. if (count($customers))
  930. $to_return = array(
  931. 'customers' => $customers,
  932. 'found' => true
  933. );
  934. else
  935. $to_return = array('found' => false);
  936. $this->content = Tools::jsonEncode($to_return);
  937. }
  938. /**
  939. * Uodate the customer note
  940. *
  941. * @return void
  942. */
  943. public function ajaxProcessUpdateCustomerNote()
  944. {
  945. if ($this->tabAccess['edit'] === '1')
  946. {
  947. $note = Tools::htmlentitiesDecodeUTF8(Tools::getValue('note'));
  948. $customer = new Customer((int)Tools::getValue('id_customer'));
  949. if (!Validate::isLoadedObject($customer))
  950. die ('error:update');
  951. if (!empty($note) && !Validate::isCleanHtml($note))
  952. die ('error:validation');
  953. $customer->note = $note;
  954. if (!$customer->update())
  955. die ('error:update');
  956. die('ok');
  957. }
  958. }
  959. }