Guest User

Untitled

a guest
Jan 30th, 2026
6
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.66 KB | None | 0 0
  1. <?php
  2. /**
  3. * Shop product reviews
  4. *
  5. * @author businesstech.fr <[email protected]> - https://www.businesstech.fr/
  6. * @copyright Business Tech - https://www.businesstech.fr/
  7. * @license see file: LICENSE.txt
  8. *
  9. * ____ _______
  10. * | _ \ |__ __|
  11. * | |_) | | |
  12. * | _ < | |
  13. * | |_) | | |
  14. * |____/ |_|
  15. */
  16. if (!defined('_PS_VERSION_')) {
  17. exit;
  18. }
  19.  
  20. use SPR\Models\Callback;
  21. use SPR\Models\CriteriaProduct;
  22. use SPR\Models\Dispute;
  23. use SPR\Models\Reviews;
  24. use SPR\Models\VoucherAssoc;
  25. use SPR\Src\IncentiveUtils;
  26. use SPR\Src\ModuleUtils;
  27. use SPR\Src\ReviewsUtils;
  28.  
  29. class gsnippetsreviewsReviewFormModuleFrontController extends ModuleFrontController
  30. {
  31. /**
  32. * @var object :
  33. */
  34. protected $customer;
  35.  
  36. /**
  37. * @var int :
  38. */
  39. protected $customer_lang_id;
  40.  
  41. /**
  42. * @var int :
  43. */
  44. protected $shop_lang_id;
  45.  
  46. /**
  47. * @var int :
  48. */
  49. protected $shop_id;
  50.  
  51. /**
  52. * @var Product :
  53. */
  54. protected $product;
  55.  
  56. /**
  57. * @var bool :
  58. */
  59. protected $already_rate;
  60.  
  61. /**
  62. * @var int :
  63. */
  64. protected $rating_value;
  65.  
  66. /**
  67. * @var int :
  68. */
  69. protected $review_title = '';
  70.  
  71. /**
  72. * @var int :
  73. */
  74. protected $review_text = '';
  75.  
  76. /**
  77. * @var int :
  78. */
  79. protected $voucher_behavior = '';
  80.  
  81. /**
  82. * @var bool :
  83. */
  84. protected $has_voucher = '';
  85.  
  86. /**
  87. * @var bool :
  88. */
  89. protected $product_category = '';
  90.  
  91. /**
  92. * @var object :
  93. */
  94. protected $order;
  95.  
  96. /**
  97. * @var array :
  98. */
  99. protected $criteria = '';
  100.  
  101. /**
  102. * init module front controller
  103. */
  104. public function init()
  105. {
  106. // Execute parent initialization
  107. parent::init();
  108.  
  109. try {
  110. // Get product and customer IDs with validation
  111. $idProduct = (int) (!empty(\Tools::getValue('id_product')) ? \Tools::getValue('id_product') : \Tools::getValue('bt_gsr_product_id'));
  112. $context = \Context::getContext();
  113. $idCustomer = (int) (!empty($context->customer->id) ? $context->customer->id : \Tools::getValue('id_customer'));
  114. $orderId = (int) \Tools::getValue('order_id');
  115.  
  116. if ($idProduct <= 0) {
  117. // Invalid/missing product ID: skip noisy logging and stop processing.
  118. \Tools::redirect('index.php');
  119. }
  120.  
  121. // Initialize required objects with validation
  122. $this->product = new \Product($idProduct);
  123. if ($idProduct > 0 && !Validate::isLoadedObject($this->product)) {
  124. \PrestaShopLogger::addLog('Invalid product ID: ' . $idProduct, 3);
  125. }
  126.  
  127. $this->customer = new \Customer($idCustomer);
  128. if ($idCustomer > 0 && !Validate::isLoadedObject($this->customer)) {
  129. \PrestaShopLogger::addLog('Invalid customer ID: ' . $idCustomer, 3);
  130. }
  131.  
  132. // Set shop and language context
  133. $this->shop_id = (int) $context->shop->id;
  134. $this->shop_lang_id = (int) $context->language->id;
  135.  
  136. // Initialize order
  137. $this->order = new \Order($orderId);
  138. if ($orderId > 0 && !Validate::isLoadedObject($this->order)) {
  139. \PrestaShopLogger::addLog('Invalid order ID: ' . $orderId, 3);
  140. }
  141.  
  142. // Set customer language
  143. $this->customer_lang_id = (int) $this->customer->id_lang;
  144.  
  145. // Check if customer already rated
  146. $this->already_rate = ReviewsUtils::isAlreadyRated(
  147. (int) $this->customer->id,
  148. (int) $this->product->id,
  149. (int) $this->order->id
  150. );
  151.  
  152. // Get voucher configuration and status
  153. $this->voucher_behavior = \Configuration::get('BT_GSR_VOUCHER_MODE', true);
  154. $voucherMode = \Configuration::get('BT_GSR_VOUCHER_MODE', 'customer');
  155. $orderId = ($voucherMode === 'order') ? $this->order->id : null;
  156. $this->has_voucher = VoucherAssoc::isVoucherAssocatied(
  157. (int) $this->customer->id,
  158. $orderId,
  159. null
  160. );
  161.  
  162. // Set product category
  163. $categoryId = (int) $this->product->getDefaultCategory();
  164. $this->product_category = new \Category($categoryId, (int) $this->shop_lang_id);
  165. if ($categoryId > 0 && !Validate::isLoadedObject($this->product_category)) {
  166. \PrestaShopLogger::addLog('Invalid category ID: ' . $categoryId, 3);
  167. }
  168.  
  169. // Get product review criteria
  170. $this->criteria = ReviewsUtils::getProductCriteria((int) $this->product->id);
  171.  
  172. // Set template with dynamic PS version handling
  173. $templateBase = 'module:gsnippetsreviews/views/templates/front/email_add_review';
  174. $templatePath = GSnippetsReviews::$bcomparePS9 ? $templateBase . '_ps9.tpl' : $templateBase . '.tpl';
  175. $this->setTemplate($templatePath);
  176. } catch (\Exception $e) {
  177. \PrestaShopLogger::addLog('Error in review form initialization: ' . $e->getMessage(), 3);
  178. throw $e;
  179. }
  180. }
  181.  
  182. /**
  183. * Initialize module front controller content
  184. *
  185. * @return void
  186. */
  187. public function initContent()
  188. {
  189. try {
  190. parent::initContent();
  191.  
  192. // Add required assets
  193. Context::getContext()->controller->addCSS(_MODULE_DIR_ . 'gsnippetsreviews/views/css/front/review_form.css');
  194. Context::getContext()->controller->addJS(_MODULE_DIR_ . 'gsnippetsreviews/views/js/front/review_form.js');
  195.  
  196. // Initialize JS definitions
  197. $jsDefs = $this->getJsDefinitions();
  198.  
  199. // Handle customer login if needed
  200. $this->handleCustomerLogin();
  201.  
  202. // Build criteria IDs for JS form handling
  203. if (!empty($this->criteria)) {
  204. $jsDefs['criteria_ids'] = array_column($this->criteria, 'id_criteria');
  205. }
  206.  
  207. // Add JS definitions
  208. \Media::addJsDef(['btSpr' => $jsDefs]);
  209.  
  210. // Check if customer is excluded
  211. $isExcluded = $this->isCustomerExcluded();
  212.  
  213. // Assign template variables
  214. $this->assignTemplateVariables($isExcluded);
  215. } catch (\Exception $e) {
  216. \PrestaShopLogger::addLog('Error in review form content initialization: ' . $e->getMessage(), 3);
  217. throw $e;
  218. }
  219. }
  220.  
  221. /**
  222. * Get JS definitions for form
  223. *
  224. * @return array
  225. */
  226. private function getJsDefinitions()
  227. {
  228. return [
  229. 'reviewLength' => \Configuration::get('BT_GSR_MIN_RVW_LENGHT', true),
  230. 'reviewLengthMessage' => $this->module->l('characters minimum required', 'reviewForm'),
  231. 'reviewRequire' => \Configuration::get('BT_GSR_ENABLE_COMMENTS', true),
  232. 'has_multi' => !empty($this->criteria)
  233. ];
  234. }
  235.  
  236. /**
  237. * Handle customer login if needed
  238. *
  239. * @return void
  240. */
  241. private function handleCustomerLogin()
  242. {
  243. if (!Context::getContext()->customer->isLogged()) {
  244. $token = ModuleUtils::makeToken($this->customer->id, $this->product->id, $this->order->id);
  245. if ($this->customer->id && (Tools::getValue('bt_token') === $token)) {
  246. if (Validate::isLoadedObject($this->customer)) {
  247. // Note: We do NOT call updateCustomer here to avoid overprivileged access
  248. // The token is only meant to allow posting a review, not to log in as the customer
  249. $this->customer_lang_id = $this->customer->id_lang;
  250. }
  251. }
  252. }
  253. }
  254.  
  255. /**
  256. * Check if customer is excluded from reviews
  257. *
  258. * @return bool
  259. */
  260. private function isCustomerExcluded()
  261. {
  262. if (ModuleUtils::isProductExcluded((int) $this->product->id)) {
  263. return true;
  264. }
  265.  
  266. if (empty(Context::getContext()->customer->id)) {
  267. return false;
  268. }
  269.  
  270. $excludedCustomers = explode(',', \Configuration::get('BT_GSR_BLACKLIST'));
  271. $email = Context::getContext()->customer->email;
  272.  
  273. return in_array($email, $excludedCustomers, true);
  274. }
  275.  
  276. /**
  277. * Assign variables to template
  278. *
  279. * @param bool $isExcluded Whether customer is excluded
  280. * @return void
  281. */
  282. private function assignTemplateVariables($isExcluded)
  283. {
  284. $this->context->smarty->assign([
  285. 'customer_id' => $this->customer->id,
  286. 'product_id' => $this->product->id,
  287. 'order_id' => $this->order->id,
  288. 'rating_email_value' => (int) Tools::getValue('rating'),
  289. 'review_required' => \Configuration::get('BT_GSR_ENABLE_COMMENTS', true),
  290. 'product_image_link' => ModuleUtils::getProductImageUrl(
  291. $this->product,
  292. ImageType::getFormattedName('home'),
  293. $this->shop_lang_id
  294. ),
  295. 'product_name' => isset($this->product->name[$this->shop_lang_id]) && isset($this->product->name[1]) ? $this->product->name[$this->shop_lang_id] : (isset($this->product->name[1]) ? $this->product->name[1] : ''),
  296. 'product_description' => isset($this->product->description_short) && isset($this->product->description_short[$this->shop_lang_id]) ? strip_tags($this->product->description_short[$this->shop_lang_id]) : (isset($this->product->description_short[1]) ? strip_tags($this->product->description_short[1]) : ''),
  297. 'is_aready_rated' => $this->already_rate,
  298. 'incentive_data' => IncentiveUtils::getIncentiveData(),
  299. 'has_voucher' => $this->has_voucher,
  300. 'review_length' => \Configuration::get('BT_GSR_MIN_RVW_LENGHT', true),
  301. 'bt_is_excluded' => $isExcluded,
  302. 'criteria' => $this->criteria,
  303. 'show_description' => \Configuration::get('BT_GSR_ENABLE_PROD_DESC_REVIEW', true),
  304. 'allow_photo' => \Configuration::get('BT_GSR_ENABLE_PHOTO', true),
  305. 'bt_token' => Tools::getValue('bt_token')
  306. ]);
  307. }
  308.  
  309. /**
  310. * Process review submission
  311. *
  312. * @return bool
  313. *
  314. * @throws Exception
  315. */
  316. public function postProcess()
  317. {
  318. try {
  319. if (!Tools::isSubmit('reviewPost')) {
  320. return false;
  321. }
  322.  
  323. // Get and validate input parameters
  324. $customerId = (int) Tools::getValue('customer_id');
  325. $orderId = !empty(Tools::getValue('order_id')) ? (int) Tools::getValue('order_id') : 0;
  326. $productId = (int) Tools::getValue('product_id');
  327. $submittedToken = Tools::getValue('bt_token');
  328. $reviewSource = Tools::getValue('source_url');
  329.  
  330. // Determine authentication method based on review source
  331. $isProductPageReview = ($reviewSource === 'product_page');
  332.  
  333. if ($isProductPageReview) {
  334. // PRODUCT PAGE REVIEW FLOW
  335. // SECURITY CHECK 1: Verify user is logged in
  336. if (!Context::getContext()->customer->isLogged()) {
  337. \PrestaShopLogger::addLog(
  338. 'Security: Unauthenticated review attempt from product page - Product: ' . $productId .
  339. ', IP: ' . Tools::getRemoteAddr(),
  340. 3,
  341. null,
  342. 'Customer',
  343. $customerId
  344. );
  345. $this->errors[] = $this->module->l('You must be logged in to submit a review.', 'reviewForm');
  346. return false;
  347. }
  348.  
  349. // SECURITY CHECK 2: Verify the logged-in customer matches the submitted customer ID
  350. $loggedCustomerId = (int) Context::getContext()->customer->id;
  351. if ($loggedCustomerId !== $customerId) {
  352. \PrestaShopLogger::addLog(
  353. 'Security: Customer ID mismatch - Logged: ' . $loggedCustomerId .
  354. ', Submitted: ' . $customerId . ', IP: ' . Tools::getRemoteAddr(),
  355. 3,
  356. null,
  357. 'Customer',
  358. $loggedCustomerId
  359. );
  360. $this->errors[] = $this->module->l('Invalid customer information.', 'reviewForm');
  361. return false;
  362. }
  363.  
  364. // SECURITY CHECK 3: Verify purchase (if required by configuration)
  365. $whoCanReview = (int) Configuration::get('BT_GSR_COMMENTS_USER', 1);
  366. if ($whoCanReview === 1) { // 1 = Only registered customers who purchased
  367. if (!ReviewsUtils::hasPurchased($customerId, $productId)) {
  368. \PrestaShopLogger::addLog(
  369. 'Security: Review attempt without purchase - Customer: ' . $customerId .
  370. ', Product: ' . $productId . ', IP: ' . Tools::getRemoteAddr(),
  371. 2,
  372. null,
  373. 'Customer',
  374. $customerId
  375. );
  376. $this->errors[] = $this->module->l('You can only review products you have purchased.', 'reviewForm');
  377. return false;
  378. }
  379. }
  380. } else {
  381. // EMAIL LINK REVIEW FLOW
  382. // SECURITY CHECK 1: Validate token
  383. // This prevents attackers from submitting reviews without a valid email link
  384. $expectedToken = ModuleUtils::makeToken($customerId, $productId, $orderId);
  385. if (empty($submittedToken) || $submittedToken !== $expectedToken) {
  386. \PrestaShopLogger::addLog(
  387. 'Security: Invalid review token attempt - Customer: ' . $customerId .
  388. ', Product: ' . $productId . ', Order: ' . $orderId .
  389. ', IP: ' . Tools::getRemoteAddr(),
  390. 3,
  391. null,
  392. 'Customer',
  393. $customerId
  394. );
  395. $this->errors[] = $this->module->l('Invalid authentication token. Please use the link from your email.', 'reviewForm');
  396. return false;
  397. }
  398.  
  399. // SECURITY CHECK 2: Verify order ownership
  400. // This prevents attackers from using someone else's customer_id with a different order_id
  401. if (!empty($orderId)) {
  402. $order = new \Order($orderId);
  403. if (!Validate::isLoadedObject($order) || (int) $order->id_customer !== $customerId) {
  404. \PrestaShopLogger::addLog(
  405. 'Security: Order ownership mismatch - Customer: ' . $customerId .
  406. ', Order: ' . $orderId . ', Order Customer: ' . (Validate::isLoadedObject($order) ? $order->id_customer : 'invalid') .
  407. ', IP: ' . Tools::getRemoteAddr(),
  408. 3,
  409. null,
  410. 'Customer',
  411. $customerId
  412. );
  413. $this->errors[] = $this->module->l('Invalid order information.', 'reviewForm');
  414. return false;
  415. }
  416. }
  417.  
  418. // SECURITY CHECK 3: Verify purchase (if required by configuration)
  419. // This enforces the "only registered clients that have purchased" setting
  420. $whoCanReview = (int) Configuration::get('BT_GSR_COMMENTS_USER', 1);
  421. if ($whoCanReview === 1) { // 1 = Only registered customers who purchased
  422. if (!ReviewsUtils::hasPurchased($customerId, $productId)) {
  423. \PrestaShopLogger::addLog(
  424. 'Security: Review attempt without purchase - Customer: ' . $customerId .
  425. ', Product: ' . $productId . ', IP: ' . Tools::getRemoteAddr(),
  426. 2,
  427. null,
  428. 'Customer',
  429. $customerId
  430. );
  431. $this->errors[] = $this->module->l('You can only review products you have purchased.', 'reviewForm');
  432. return false;
  433. }
  434. }
  435. }
  436.  
  437. // Product exclusion check (common to both flows)
  438. if (ModuleUtils::isProductExcluded($productId)) {
  439. $this->errors[] = $this->module->l('This product cannot be reviewed.', 'reviewForm');
  440. return false;
  441. }
  442.  
  443. $criteria = ReviewsUtils::getProductCriteria($productId);
  444.  
  445. $product = new \Product($productId, false, (int) Context::getContext()->language->id);
  446. $productCategory = new \Category((int) $product->getDefaultCategory(), (int) Context::getContext()->language->id);
  447.  
  448. $productUrl = Context::getContext()->link->getProductLink(
  449. $product,
  450. null,
  451. Tools::strtolower($productCategory->link_rewrite),
  452. null,
  453. (int) Context::getContext()->language->id,
  454. (int) Context::getContext()->shop->id,
  455. 0,
  456. true
  457. ) . '?spr_is_posted=1';
  458.  
  459. $review = new Reviews();
  460. $star = $this->getRatingValue();
  461.  
  462. $this->setReviewData($review, $customerId, $orderId, $productId, $star);
  463.  
  464. if (!$review->add()) {
  465. return false;
  466. }
  467.  
  468. $this->handleReviewCreated($review, $customerId, $orderId, $productId, $star);
  469.  
  470. if (!empty($criteria)) {
  471. $this->handleCriteriaReviews($criteria, $review, $productId);
  472. }
  473.  
  474. ModuleUtils::storeReviewPhotos($_FILES['review_photos'], $review, $customerId, $productId, $orderId);
  475.  
  476. if ($this->shouldCreateDispute($star)) {
  477. $this->createDispute($review, $star);
  478. }
  479.  
  480. Tools::redirect($productUrl);
  481. } catch (Exception $e) {
  482. \PrestaShopLogger::addLog($e->getMessage(), 1, $e->getCode(), null, null, true);
  483. return false;
  484. }
  485. }
  486.  
  487. /**
  488. * Get rating value from input
  489. *
  490. * @return int
  491. */
  492. private function getRatingValue()
  493. {
  494. $rating = (int) Tools::getValue('star');
  495. return !empty($rating) ? $rating : 3;
  496. }
  497.  
  498. /**
  499. * Set review data
  500. *
  501. * @param Reviews $review
  502. * @param int $customerId
  503. * @param int $orderId
  504. * @param int $productId
  505. * @param int $rating
  506. * @return void
  507. */
  508. private function setReviewData($review, $customerId, $orderId, $productId, $rating)
  509. {
  510. $review->id_order = $orderId;
  511. $review->id_customer = $customerId;
  512. $review->id_product = $productId;
  513. $review->id_lang = (int) Context::getContext()->customer->id_lang;
  514. $review->title_review = Tools::getValue('review_title');
  515. $review->text_review = Tools::getValue('review_text');
  516. $review->rating_value = $rating;
  517. $review->review_status = !empty(Configuration::get('BT_GSR_COMMENTS_APPROVAL')) ? false : true;
  518. $review->id_shop = (int) $this->shop_id;
  519. }
  520.  
  521. /**
  522. * Handle review creation tasks
  523. *
  524. * @param Reviews $review
  525. * @param int $customerId
  526. * @param int $orderId
  527. * @param int $productId
  528. * @param int $rating
  529. * @return void
  530. */
  531. private function handleReviewCreated($review, $customerId, $orderId, $productId, $rating)
  532. {
  533. IncentiveUtils::generateVoucher($customerId, $orderId, $productId, (int) $review->id);
  534.  
  535. $this->updateCallback($review);
  536. $this->notifyMerchant($review, $rating);
  537. }
  538.  
  539. /**
  540. * Update callback status
  541. *
  542. * @param Reviews $review
  543. * @return void
  544. */
  545. private function updateCallback($review)
  546. {
  547. $callback = Callback::getCallbacks((int) $review->id_customer, (int) $review->id_order, (int) $review->id_product);
  548. if (!empty($callback)) {
  549. $callbackObj = new Callback((int) $callback[0]['id_callback']);
  550. $callbackObj->callback_status = 3;
  551. $callbackObj->update();
  552. }
  553. }
  554.  
  555. /**
  556. * Send merchant notification
  557. *
  558. * @param Reviews $review
  559. * @param int $rating
  560. * @return void
  561. */
  562. private function notifyMerchant($review, $rating)
  563. {
  564. if (empty(Configuration::get('BT_GSR_NOTIFY_EMAIL'))) {
  565. return;
  566. }
  567.  
  568. $subject = $this->module->l('You have received a new product review', 'addReviewProductPage');
  569. $emailFolder = _PS_MODULE_DIR_ . 'gsnippetsreviews/mails';
  570.  
  571. $vars = [
  572. '{message}' => $this->module->l('A customer has posted a new review', 'addReviewProductPage') . ' ' . $rating . '/5',
  573. '{review_title}' => $review->title_review,
  574. '{review_text}' => $review->text_review,
  575. ];
  576.  
  577. Mail::Send(
  578. (int) $this->customer->id_lang,
  579. 'new_review',
  580. $subject,
  581. $vars,
  582. Configuration::get('BT_GSR_NOTIFY_EMAIL'),
  583. null,
  584. null,
  585. null,
  586. null,
  587. null,
  588. $emailFolder
  589. );
  590. }
  591.  
  592. /**
  593. * Handle criteria reviews
  594. *
  595. * @param array $criteria
  596. * @param Reviews $review
  597. * @param int $productId
  598. * @return void
  599. */
  600. private function handleCriteriaReviews($criteria, $review, $productId)
  601. {
  602. foreach ($criteria as $data) {
  603. $criteriaProduct = new CriteriaProduct();
  604. $criteriaProduct->id_criteria = (int) $data['id_criteria'];
  605. $criteriaProduct->id_review = (int) $review->id;
  606. $criteriaProduct->id_product = $productId;
  607. $criteriaProduct->rating_value = (int) Tools::getValue('star_criteria_' . $data['id_criteria'], 3);
  608. $criteriaProduct->id_shop = (int) $this->shop_id;
  609. $criteriaProduct->add();
  610. }
  611. }
  612.  
  613. /**
  614. * Check if dispute should be created
  615. *
  616. * @param int $rating
  617. * @return bool
  618. */
  619. private function shouldCreateDispute($rating)
  620. {
  621. return $rating <= Configuration::get('BT_GSR_RATING_DISPUTE_LEVEL');
  622. }
  623.  
  624. /**
  625. * Create dispute for low rating
  626. *
  627. * @param Reviews $review
  628. * @param int $rating
  629. * @return void
  630. */
  631. private function createDispute($review, $rating)
  632. {
  633. $dispute = new Dispute();
  634. $dispute->id_review = (int) $review->id;
  635. $dispute->new_rating_value = $rating;
  636. $dispute->status = 0;
  637. $dispute->id_shop = (int) $this->shop_id;
  638.  
  639. if (!$dispute->add() || empty(Configuration::get('BT_GSR_RATING_DISPUTE_EMAIL'))) {
  640. return;
  641. }
  642.  
  643. $this->sendDisputeNotification($rating);
  644. }
  645.  
  646. /**
  647. * Send dispute notification email
  648. *
  649. * @param int $rating
  650. * @return void
  651. */
  652. private function sendDisputeNotification($rating)
  653. {
  654. $emailFolder = _PS_MODULE_DIR_ . 'gsnippetsreviews/mails';
  655. $customer = new Customer((int) Tools::getValue('customer_id'));
  656. $subject = $this->module->l('A bad review has been sent', 'reviewForm');
  657.  
  658. $reviewText = !empty(Tools::getValue('review_text'))
  659. ? Tools::getValue('review_text')
  660. : $this->module->l('The customer did not leave a comment.');
  661.  
  662. $reviewTitle = !empty(Tools::getValue('review_title'))
  663. ? Tools::getValue('review_title')
  664. : $this->module->l('The customer did not give a title to his review.');
  665.  
  666. $vars = [
  667. '{firstname}' => $customer->firstname,
  668. '{lastname}' => $customer->lastname,
  669. '{review_title}' => $reviewTitle,
  670. '{review_text}' => $reviewText,
  671. '{rating}' => $rating,
  672. ];
  673.  
  674. Mail::Send(
  675. (int) $this->customer->id_lang,
  676. 'alert',
  677. $subject,
  678. $vars,
  679. Configuration::get('BT_GSR_RATING_DISPUTE_EMAIL'),
  680. null,
  681. null,
  682. null,
  683. null,
  684. null,
  685. $emailFolder
  686. );
  687. }
  688. }
  689.  
Advertisement
Add Comment
Please, Sign In to add comment