File: /home4/cca63905/www/nueva/modules/pmproductvideoreviews/pmproductvideoreviews.php
<?php
/**
* rec.reviews
*
* @author Presta-Module.com <support@presta-module.com> - https://www.presta-module.com
* @copyright Presta-Module 2023 - https://www.presta-module.com
* @license see file: LICENSE.txt
*
* @version 1.0.4
*
* ____ __ __
* | _ \ | \/ |
* | |_) | | |\/| |
* | __/ | | | |
* |_| |_| |_|
*/
if (!defined('_PS_VERSION_')) {
exit;
}
require_once dirname(__FILE__) . '/vendor/autoload.php';
use RecReviews\Client as RecReviewsClient;
use PrestaModule\ProductVideoReviews\Utils;
use PrestaModule\ProductVideoReviews\Ratings;
class pmproductvideoreviews extends Module
{
private $container;
private $emailSupport;
public static $moduleVersion;
public $adminTab = [
'name' => [
'en' => 'Video reviews',
'fr' => 'Avis vidéo',
],
'class_name' => 'AdminRecReviews',
'visible' => true,
'parent_class_name' => 'AdminParentCustomer',
];
public function __construct()
{
$this->name = 'pmproductvideoreviews';
$this->tab = 'advertising_marketing';
$this->version = '1.0.4';
$this->author = 'Presta-Module';
$this->module_key = '5e991133e38608ca5e0f0b138936ee07';
$this->need_instance = 0;
$this->emailSupport = 'support@presta-module.com';
self::$moduleVersion = $this->version;
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('rec.reviews');
$this->description = $this->l('Allow your customers to record themselves on video to give an authentic review of your products. Post these videos on your store and increase your conversion rate with certified and original reviews that will make you stand out from the competition.');
$this->confirmUninstall = $this->l('Are you sure you want to remove the module ?');
$this->ps_versions_compliancy['min'] = '1.7.4.0';
if (Tools::getValue('module_name') == $this->name || Tools::getValue('configure') == $this->name) {
if (RecReviewsClient::MODULE_SOURCE == 'addons') {
$this->ps_versions_compliancy['max'] = '1.7.8.99';
if ($this->container === null) {
$this->container = new \PrestaShop\ModuleLibServiceContainer\DependencyInjection\ServiceContainer($this->name, $this->getLocalPath());
}
}
}
}
public function install()
{
include dirname(__FILE__) . '/sql/install.php';
$hooks = [
'displayHeader',
'displayBackOfficeHeader',
'actionOrderStatusUpdate',
'actionValidateOrder',
'displayFooterProduct',
'actionObjectLanguageAddAfter',
'actionEmailSendBefore',
];
if (RecReviewsClient::MODULE_SOURCE == 'addons') {
$this->getService('ps_accounts.installer')->install();
}
return parent::install()
&& $this->registerHook($hooks)
&& $this->installTab()
&& $this->initModuleConf();
}
public function uninstall()
{
include dirname(__FILE__) . '/sql/uninstall.php';
return parent::uninstall() && Configuration::updateValue('PVR_OAUTH', '') && Configuration::updateValue('PVR_RBM_SUB_ID', '');
}
public function getLanguageIsoCode()
{
return $this->context->language !== null ? $this->context->language->iso_code : 'en';
}
public function getTosLink()
{
$iso_lang = $this->getLanguageIsoCode();
switch ($iso_lang) {
case 'fr':
$url = 'https://www.prestashop.com/fr/prestashop-account-cgu';
break;
default:
$url = 'https://www.prestashop.com/en/prestashop-account-terms-conditions';
break;
}
return $url;
}
public function getContent()
{
if (Shop::getContext() != Shop::CONTEXT_SHOP) {
$this->context->controller->warnings[] = $this->l('You must select a specific shop in order to continue, configuration cannot be edited for all shops simultaneously.');
return;
}
if (RecReviewsClient::MODULE_SOURCE == 'addons') {
if (PHP_VERSION_ID < 70205) {
$this->context->controller->warnings[] = $this->l('This module and its dependencies require at least PHP 7.2.5 to work. Please upgrade your PHP version to continue.');
return;
}
if (version_compare(_PS_VERSION_, '8.0.0', '>=')) {
$mboStatus = (new \Prestashop\ModuleLibMboInstaller\Presenter)->present();
if (empty($mboStatus)) {
$this->context->controller->errors[] = $this->l('Could not locate the MBO installer library. Please reach out to our support.');
return;
}
if (empty($mboStatus['isPresentOnDisk']) || empty($mboStatus['isInstalled'])) {
try {
$mboInstaller = new \Prestashop\ModuleLibMboInstaller\Installer(_PS_VERSION_);
$result = $mboInstaller->installModule();
if (!$result) {
throw new \Exception('MBO install returned false');
}
} catch (\Exception $e) {
$this->context->controller->errors[] = sprintf($this->l('An error occurred while attempting to install the MBO module: %s'), $e->getMessage());
return;
}
}
}
}
Utils::generateCronUrl();
if (empty(Configuration::get('PVR_API_SHOP_ID'))) {
Utils::generateDashboardShopLink();
}
if (((bool)Tools::isSubmit('submit' . $this->name . 'Module')) == true) {
$this->postProcess();
}
if ((bool)Tools::isSubmit('linkRbm') == true) {
if ((!Tools::getIsset('firstName') || !Tools::getIsset('lastName')) || (!Tools::getValue('firstName') || !Tools::getValue('lastName'))) {
$this->context->controller->errors[] = $this->l('First or last name missing. Please fill in the required fields');
} else {
return $this->initRbmLink();
}
}
if (RecReviewsClient::MODULE_SOURCE == 'addons') {
try {
$facade = $this->getService('ps_accounts.facade');
$accountsService = $facade->getPsAccountsService();
} catch (\PrestaShop\PsAccountsInstaller\Installer\Exception\InstallerException $e) {
$accountsInstaller = $this->getService('ps_accounts.installer');
$accountsInstaller->install();
$facade = $this->getService('ps_accounts.facade');
$accountsService = $facade->getPsAccountsService();
}
if (!empty(Configuration::get('PVR_API_SHOP_ID')) && !$accountsService->isAccountLinked()) {
Configuration::updateValue('PVR_RBM_SUB_ID', null);
Configuration::updateValue('PVR_API_SHOP_ID', null);
Configuration::updateValue('PVR_OAUTH', '');
return Tools::redirectAdmin(Context::getContext()->link->getAdminLink('AdminModules') . '&configure=pmproductvideoreviews');
}
try {
$contextPsAccount = $facade->getPsAccountsPresenter()->present($this->name);
Media::addJsDef([
'contextPsAccounts' => $contextPsAccount,
]);
$billingFacade = $this->getService('ps_billings.facade')
->present([
'logo' => 'https://dashboard.recreviews.com/images/logo-black.svg',
'tosLink' => 'https://dashboard.recreviews.com/conditions',
'privacyLink' => 'https://dashboard.recreviews.com/privacy',
'emailSupport' => 'support@recreviews.com',
]);
$recReviewsLogo = Tools::file_get_contents(dirname(__FILE__) . '/views/img/recreviews.png');
$billingFacade['psBillingContext']['context']['partnerLogo'] = 'data:image/png;base64,' . base64_encode($recReviewsLogo);
Media::addJsDef($billingFacade);
$this->context->smarty->assign('urlBilling', "https://unpkg.com/@prestashopcorp/billing-cdc/dist/bundle.js");
$this->context->smarty->assign('urlAccountsCdn', $accountsService->getAccountsCdn());
$this->context->smarty->assign('img_path', _MODULE_DIR_ . $this->name . '/views/img/');
$this->context->smarty->assign('isAddons', RecReviewsClient::MODULE_SOURCE == 'addons');
if (RecReviewsClient::MODULE_SOURCE == 'addons') {
$this->context->smarty->assign('isAccountLinked', $accountsService->isAccountLinked());
$this->context->smarty->assign('submitLabel', sprintf($this->l('Continue with %s'), $billingFacade['psBillingContext']['context']['user']['email']));
$this->context->smarty->assign('helpLabel', $this->l('By clicking on this button, you will create an account on our service and start a free trial. Make sure your first and last name are correctly spelled, as they will be used for the transfer of image rights.'));
$this->context->smarty->assign('firstNameLabel', $this->l('First name'));
$this->context->smarty->assign('lastNameLabel', $this->l('Last name'));
$this->context->smarty->assign('termsLabel', $this->l('I agree to the terms of use and privacy policy of Rec.Reviews'));
$this->context->smarty->assign('accountCreationUrl', $this->context->link->getAdminLink('AdminModules') . '&configure=pmproductvideoreviews');
}
$this->context->smarty->assign('generatedLink', '');
$this->context->smarty->assign('onboardingLink', RecReviewsClient::ONBOARDING_URL);
} catch (Exception $e) {
$this->context->controller->errors[] = sprintf($this->l('An error occurred. Please try again or contact our support (%s)', $e->getMessage()));
return;
}
}
$this->context->smarty->assign('module_dir', $this->_path);
if (!empty(Utils::isOauthed())) {
$api_token = json_decode(Configuration::get('PVR_OAUTH'));
$jsDefs['unlink_message'] = $this->l('Warning: Please note that unsubscribing will remove the link between your store and our services. All the reviews previously collected will be definitively lost.');
Media::addJsDef([$this->name => $jsDefs]);
$this->context->smarty->assign([
'dashboard' => !empty(Configuration::get('PVR_API_SHOP_ID')) ? RecReviewsClient::API_URL . 'dashboard/' . Configuration::get('PVR_API_SHOP_ID') . '/' : '#',
'img_path' => _MODULE_DIR_ . $this->name . '/views/img/',
'moderation_wating' => count(RecReviewsClient::getReviewData($api_token->access_token, ['published' => false])),
'is_active_connection' => Utils::isOauthed(),
]);
$output = $this->context->smarty->fetch($this->local_path . 'views/templates/admin/gis_linked.tpl');
return $output . $this->renderForm();
} else {
if (RecReviewsClient::MODULE_SOURCE == 'prestamodule') {
if (Tools::getIsset('code') && Tools::getIsset('state') && Tools::getIsset('client_id')) {
$moduleConfiguration = json_decode(Configuration::get('PVR_OAUTH'));
$oAuthQueryParams = '';
if (Tools::getValue('state') != $moduleConfiguration->state) {
$this->context->controller->errors[] = $this->l('An error occurred while verifying the authorization request. Please try again.');
$this->context->smarty->assign([
'generatedLink' => RecReviewsClient::API_URL . 'oauth/authorize?' . $oAuthQueryParams,
'onboardingLink' => RecReviewsClient::ONBOARDING_URL,
'linkTitle' => $this->l('Link my subscription'),
'isError' => false,
'register_link' => RecReviewsClient::API_URL,
'is_oauth' => Utils::isOauthed(),
'img_path' => _MODULE_DIR_ . $this->name . '/views/img/',
]);
$output = $this->context->smarty->fetch($this->local_path . 'views/templates/admin/onboarding.tpl');
}
$moduleConfiguration->code = Tools::getValue('code');
$moduleConfiguration->clientId = Tools::getValue('client_id');
Configuration::updateValue('PVR_OAUTH', json_encode($moduleConfiguration));
$tokenData = RecReviewsClient::getClient()->getAccessToken($moduleConfiguration->code, Utils::generatePublicModuleUrl(), $moduleConfiguration->clientId, $moduleConfiguration->codeVerifier);
if (empty($tokenData)) {
$this->context->controller->errors[] = $this->l('An error occurred while verifying the authorization request. Please try again.');
return;
}
$moduleConfiguration->access_token = $tokenData->access_token;
$moduleConfiguration->refresh_token = $tokenData->refresh_token;
$moduleConfiguration->expires_in = time() + $tokenData->expires_in;
$moduleConfiguration->token_type = $tokenData->token_type;
Configuration::updateValue('PVR_OAUTH', json_encode($moduleConfiguration));
Utils::updateApiModuleConfiguration();
Utils::generateDashboardShopLink();
return Tools::redirectAdmin(Context::getContext()->link->getAdminLink('AdminModules') . '&configure=' . $this->name);
} else {
$moduleConfiguration['state'] = RecReviewsClient::codeVerifierGen(40);
$moduleConfiguration['codeVerifier'] = RecReviewsClient::codeVerifierGen();
Configuration::updateValue('PVR_OAUTH', json_encode($moduleConfiguration));
$oAuthQueryParams = http_build_query([
'redirect_uri' => Utils::generatePublicModuleUrl(),
'response_type' => 'code',
'code_challenge' => RecReviewsClient::createCodeChallengeFromVerifier($moduleConfiguration['codeVerifier']),
'code_challenge_method' => 'S256',
'scope' => '',
'state' => $moduleConfiguration['state'],
'cms_name' => 'PrestaShop',
'shop_url' => rtrim((string) Context::getContext()->link->getBaseLink(), '/'),
]);
$this->context->smarty->assign([
'generatedLink' => RecReviewsClient::API_URL . 'oauth/authorize?' . $oAuthQueryParams,
'onboardingLink' => RecReviewsClient::ONBOARDING_URL,
'linkTitle' => $this->l('Link my subscription'),
'isError' => false,
'register_link' => RecReviewsClient::API_URL,
'is_oauth' => Utils::isOauthed(),
'img_path' => _MODULE_DIR_ . $this->name . '/views/img/',
'isAddons' => false,
]);
$output = $this->context->smarty->fetch($this->local_path . 'views/templates/admin/onboarding.tpl');
}
} else {
if (!empty(Configuration::get('PVR_RBM_SUB_ID'))) {
$tokenData = RecReviewsClient::getClient()->getAccessTokenRbm(Configuration::get('PVR_RBM_SUB_ID'));
if (!empty($tokenData)) {
Configuration::updateValue('PVR_OAUTH', json_encode($tokenData));
Utils::updateApiModuleConfiguration();
Utils::generateDashboardShopLink();
}
return Tools::redirectAdmin(Context::getContext()->link->getAdminLink('AdminModules') . '&configure=pmproductvideoreviews');
} else {
$output = $this->context->smarty->fetch($this->local_path . 'views/templates/admin/onboarding.tpl');
}
}
return $output;
}
}
protected function renderForm()
{
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->table = $this->table;
$helper->module = $this;
$helper->default_form_language = $this->context->language->id;
$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG', 0);
$helper->identifier = $this->identifier;
$helper->submit_action = 'submit' . $this->name . 'Module';
$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 = [
'fields_value' => $this->getConfigFormValues(),
'languages' => $this->context->controller->getLanguages(),
'id_language' => $this->context->language->id,
];
if (RecReviewsClient::MODULE_SOURCE == 'addons') {
if (empty(Configuration::get('PVR_RBM_SUB_ID'))) {
$facade = $this->getService('ps_accounts.facade');
$psAccountsService = $facade->getPsAccountsService();
$rmb_id = RecReviewsClient::getRmbSubscriptionId($psAccountsService->getToken(), $psAccountsService->getShopUuidV4());
if (!empty($rmb_id)) {
Configuration::updateValue('PVR_RBM_SUB_ID', $rmb_id);
}
}
}
return $helper->generateForm([$this->getConfigForm()]);
}
protected function getConfigForm()
{
$form = [
'form' => [
'tabs' => [
'basic-settings' => $this->l('Configuration'),
'voucher' => $this->l('Incentive vouchers'),
],
'input' => [
[
'type' => 'hidden',
'name' => 'selected_tab',
],
[
'type' => 'subtitle',
'content' => $this->l('Order status for notification'),
'name' => '',
'tab' => 'basic-settings',
],
[
'type' => 'select',
'label' => $this->l('Order status for notification'),
'name' => 'PVR_STATUS_SELECTION',
'desc' => $this->l('Choose the order status that will trigger the email inviting your customer to rate and record his product review on video'),
'tab' => 'basic-settings',
'class' => 'module_field',
'options' => [
'query' => Utils::getOrderStates((int)Context::getContext()->language->id, 'delivery'),
'id' => 'id_order_state',
'name' => 'name',
],
],
[
'type' => 'subtitle',
'content' => $this->l('Synchronization of video reviews'),
'name' => '',
'tab' => 'basic-settings',
],
[
'type' => 'text',
'label' => $this->l('CRON URL'),
'name' => 'PVR_CRON_URL',
'desc' => $this->l('Install a CRON task on your server to automatically synchronize the publication status of video reviews between your rec.reviews dashboard and your store, at a given frequency. Use the CRON URL given below.'),
'class' => 'module_field_suffix ',
'tab' => 'basic-settings',
'prefix' => $this->renderTemplate($this->local_path . 'views/templates/admin/copy.tpl', ['url' => Configuration::get('PVR_CRON_URL')]),
],
[
'type' => 'subtitle',
'content' => $this->l('Offer an incentive voucher'),
'name' => '',
'tab' => 'voucher',
],
[
'type' => 'switch',
'label' => $this->l('Activate'),
'name' => 'PVR_ENABLE_VOUCHER',
'tab' => 'voucher',
'hint' => $this->l('Select "Yes" if you want to offer a voucher in exchange for submitting a review'),
'is_bool' => true,
'values' => [
[
'id' => 'voucher_on',
'value' => 1,
],
[
'id' => 'voucher_off',
'value' => 0,
],
],
],
[
'type' => 'voucherOptions',
'content' => $this->l('Indicate below if you want to offer:'),
'options' => [
$this->l('One voucher per order: the customer will get a voucher each time he/she rates at least one product of an order (only one voucher per order, no matter how many products of the order are rated)'),
$this->l('One voucher per customer: after rating a product, the customer receives a voucher only if he has never rated a product (only one voucher per customer account)'),
],
'name' => '',
'form_group_class' => 'pvr-incentive-block',
'tab' => 'voucher',
],
[
'type' => 'select',
'label' => $this->l('Voucher awarding mode'),
'name' => 'PVR_VOUCHER_GENERATE',
'tab' => 'voucher',
'form_group_class' => 'pvr-incentive-block',
'class' => 'module_field',
'options' => [
'query' => [
[
'voucher_mode' => 'order',
'name' => $this->l('One voucher per order'),
],
[
'voucher_mode' => 'customer',
'name' => $this->l('One voucher per customer'),
],
],
'id' => 'voucher_mode',
'name' => 'name',
],
],
[
'type' => 'subtitle',
'content' => $this->l('How to obtain a voucher'),
'name' => '',
'tab' => 'voucher',
'form_group_class' => 'pvr-incentive-block',
],
[
'type' => 'textarea',
'label' => $this->l('Text inviting to rate in exchange for a voucher'),
'required' => true,
'name' => 'PVR_VOUCHER_INCENTIVE_TEXT',
'desc' => $this->l('Tip: Enter the string {voucher_amount} where you want the voucher amount to appear and its value will be replaced dynamically.'),
'lang' => 1,
'cols' => 50,
'rows' => 10,
'tab' => 'voucher',
'form_group_class' => 'pvr-incentive-block',
],
[
'type' => 'textarea',
'label' => $this->l('Text informing about the minimum purchase amount required to use the voucher'),
'required' => true,
'name' => 'PVR_VOUCHER_MIN_AMOUNT_DESC',
'desc' => $this->l('Tip: Enter the string {order_amount} where you want the minimum purchase requirement to appear and its value will be replaced dynamically.'),
'lang' => 1,
'cols' => 50,
'rows' => 10,
'tab' => 'voucher',
'form_group_class' => 'pvr-incentive-block',
],
[
'type' => 'subtitle',
'content' => $this->l('Voucher configuration'),
'name' => '',
'tab' => 'voucher',
'form_group_class' => 'pvr-incentive-block',
],
[
'type' => 'text',
'label' => $this->l('Voucher code prefix'),
'name' => 'PVR_VOUCHER_PREFIX',
'tab' => 'voucher',
'required' => 1,
'form_group_class' => 'pvr-incentive-block',
'desc' => $this->l('Invalid characters: numbers and !<>,;?=+()@#"�{}_$%:'),
'class' => 'module_field',
],
[
'type' => 'select',
'label' => $this->l('Voucher type'),
'name' => 'PVR_VOUCHER_TYPE',
'tab' => 'voucher',
'form_group_class' => 'pvr-incentive-block',
'options' => [
'query' => [
[
'voucher_type' => 'percent',
'name' => $this->l('Percentage'),
],
[
'voucher_type' => 'amount',
'name' => $this->l('Amount'),
],
],
'id' => 'voucher_type',
'name' => 'name',
],
],
[
'type' => 'text',
'label' => $this->l('Value'),
'name' => 'PVR_VOUCHER_AMOUNT',
'tab' => 'voucher',
'required' => true,
'form_group_class' => 'pvr-incentive-block pvr-incentive-amount-block',
'class' => 'fixed-width-md',
],
[
'type' => 'select',
'label' => $this->l('Currency'),
'name' => 'PVR_VOUCHER_CURRENCY',
'form_group_class' => 'pvr-incentive-block pvr-incentive-amount-block',
'tab' => 'voucher',
'options' => [
'query' => Currency::getCurrencies(),
'id' => 'id',
'name' => 'iso_code',
],
],
[
'type' => 'select',
'label' => $this->l('Tax'),
'name' => 'PVR_VOUCHER_TAX',
'form_group_class' => 'pvr-incentive-block pvr-incentive-amount-block',
'tab' => 'voucher',
'options' => [
'query' => [
[
'voucher_tax' => '0',
'name' => $this->l('Tax excluded'),
],
[
'voucher_tax' => '1',
'name' => $this->l('Tax included'),
],
],
'id' => 'voucher_tax',
'name' => 'name',
],
],
[
'type' => 'text',
'label' => $this->l('Value'),
'name' => 'PVR_VOUCHER_PERCENT',
'tab' => 'voucher',
'required' => true,
'suffix' => '%',
'form_group_class' => 'pvr-incentive-block pvr-incentive-percent-block',
'class' => 'fixed-width-md',
],
[
'type' => 'text',
'label' => $this->l('Maximum number of uses of the same voucher'),
'name' => 'PVR_VOUCHER_QTY',
'tab' => 'voucher',
'required' => true,
'form_group_class' => 'pvr-incentive-block',
'class' => 'fixed-width-md',
'hint' => $this->l('Enter the number of times the same voucher can be used by the customer'),
],
[
'type' => 'categories',
'name' => 'PVR_VOUCHER_CAT',
'label' => $this->l('Categories'),
'tab' => 'voucher',
'tree' => [
'id' => 'category',
'selected_categories' => json_decode(Configuration::get('PVR_VOUCHER_CAT')),
'root_category' => 1,
'use_checkbox' => true,
'use_search' => true,
],
'form_group_class' => 'pvr-incentive-block',
'class' => 'module_field',
],
[
'type' => 'text',
'label' => $this->l('Minimum purchase amount required to use the voucher'),
'name' => 'PVR_VOUCHER_MIN_AMOUNT',
'tab' => 'voucher',
'required' => true,
'form_group_class' => 'pvr-incentive-block',
'class' => 'fixed-width-md',
'hint' => $this->l('Enter the minimum purchase amount required for the voucher to be valid. Enter 0 if there is no required minimum."'),
],
[
'type' => 'text',
'label' => $this->l('Validity period'),
'name' => 'PVR_VOUCHER_VALIDITY',
'tab' => 'voucher',
'required' => true,
'form_group_class' => 'pvr-incentive-block',
'class' => 'fixed-width-md',
'hint' => $this->l('Enter the minimum purchase amount required for the voucher to be valid. Enter 0 if there is no required minimum."'),
'suffix' => $this->l('Days'),
],
[
'type' => 'switch',
'label' => $this->l('Highlight the voucher'),
'name' => 'PVR_VOUCHER_HIGHLIGHT',
'tab' => 'voucher',
'form_group_class' => 'pvr-incentive-block',
'is_bool' => true,
'hint' => $this->l('Select "Yes" to highlight the voucher in the cart summary, if it has not already been added.'),
'values' => [
[
'id' => 'highlight_on',
'value' => 1,
],
[
'id' => 'highlight_off',
'value' => 0,
],
],
],
[
'type' => 'switch',
'label' => $this->l('Disallow cumulation with other discounts'),
'name' => 'PVR_VOUCHER_CUMULATE',
'tab' => 'voucher',
'is_bool' => true,
'form_group_class' => 'pvr-incentive-block',
'values' => [
[
'id' => 'allow_with_ohter_on',
'value' => 1,
],
[
'id' => 'allow_with_ohter_off',
'value' => 0,
],
],
],
],
'submit' => [
'title' => $this->l('Save'),
'class' => 'pvrSubmit',
],
],
];
if (RecReviewsClient::MODULE_SOURCE == 'addons') {
$form['form']['tabs']['subscription'] = $this->l('Subscription');
$form['form']['input'][] = ['type' => 'rmb_sub', 'name' => 'rmb_sub', 'tab' => 'subscription', 'col' => 12];
}
if (RecReviewsClient::MODULE_SOURCE == 'prestamodule') {
$form['form']['tabs']['subscription'] = $this->l('Subscription');
$form['form']['input'][] = ['type' => 'disconnect', 'name' => 'disconnect', 'tab' => 'subscription'];
}
return $form;
}
protected function getConfigFormValues()
{
if (Tools::getIsset('selected_tab')) {
$selectedTab = Tools::getValue('selected_tab');
}
return [
'PVR_EMAIL_DELAY' => Configuration::get('PVR_EMAIL_DELAY'),
'PVR_STATUS_SELECTION' => Configuration::get('PVR_STATUS_SELECTION'),
'PVR_ENABLE_VOUCHER' => Configuration::get('PVR_ENABLE_VOUCHER'),
'PVR_VOUCHER_PREFIX' => Configuration::get('PVR_VOUCHER_PREFIX'),
'PVR_VOUCHER_TYPE' => Configuration::get('PVR_VOUCHER_TYPE'),
'PVR_VOUCHER_AMOUNT' => Configuration::get('PVR_VOUCHER_AMOUNT'),
'PVR_VOUCHER_PERCENT' => Configuration::get('PVR_VOUCHER_PERCENT'),
'PVR_VOUCHER_CURRENCY' => Configuration::get('PVR_VOUCHER_CURRENCY'),
'PVR_VOUCHER_TAX' => Configuration::get('PVR_VOUCHER_TAX'),
'PVR_VOUCHER_DESC' => Configuration::get('PVR_VOUCHER_DESC'),
'PVR_VOUCHER_GENERATE' => Configuration::get('PVR_VOUCHER_GENERATE'),
'PVR_VOUCHER_QTY' => Configuration::get('PVR_VOUCHER_QTY'),
'PVR_VOUCHER_MIN_AMOUNT' => Configuration::get('PVR_VOUCHER_MIN_AMOUNT'),
'PVR_VOUCHER_MIN_AMOUNT_DESC' => json_decode(Configuration::get('PVR_VOUCHER_MIN_AMOUNT_DESC'), true),
'PVR_VOUCHER_CAT' => json_decode(Configuration::get('PVR_VOUCHER_CAT')),
'PVR_VOUCHER_VALIDITY' => Configuration::get('PVR_VOUCHER_VALIDITY'),
'PVR_VOUCHER_HIGHLIGHT' => Configuration::get('PVR_VOUCHER_HIGHLIGHT'),
'PVR_VOUCHER_CUMULATE' => Configuration::get('PVR_VOUCHER_CUMULATE'),
'PVR_VOUCHER_INCENTIVE_TEXT' => json_decode(Configuration::get('PVR_VOUCHER_INCENTIVE_TEXT'), true),
'PVR_OAUTH' => Configuration::get('PVR_OAUTH'),
'PVR_ENABLE_BATTLE' => Configuration::get('PVR_ENABLE_BATTLE'),
'PVR_LAST_REVIEW_SYNC' => Configuration::get('PVR_LAST_REVIEW_SYNC'),
'PVR_CRON_TOKEN' => Configuration::get('PVR_CRON_TOKEN'),
'PVR_CRON_URL' => Configuration::get('PVR_CRON_URL'),
'PVR_API_SHOP_ID' => Configuration::get('PVR_API_SHOP_ID'),
'selected_tab' => !empty($selectedTab) ? $selectedTab : 'gis',
];
}
protected function postProcess()
{
if (Tools::isSubmit('submitDisconnect')) {
$api_token = json_decode(Configuration::get('PVR_OAUTH'));
if (RecReviewsClient::revoke($api_token->access_token, [])) {
Configuration::updateValue('PVR_RBM_SUB_ID', null);
Configuration::updateValue('PVR_API_SHOP_ID', null);
Configuration::updateValue('PVR_OAUTH', '');
}
}
if (Tools::isSubmit('submitRbmDisconnect')) {
Configuration::updateValue('PVR_RBM_SUB_ID', null);
Configuration::updateValue('PVR_API_SHOP_ID', null);
Configuration::updateValue('PVR_OAUTH', '');
}
$form_values = $this->getConfigFormValues();
$text_fields = [
'PVR_VOUCHER_INCENTIVE_TEXT',
'PVR_VOUCHER_MIN_AMOUNT_DESC',
];
$requiered_field = [
'PVR_VOUCHER_PREFIX',
'PVR_VOUCHER_PERCENT',
'PVR_VOUCHER_AMOUNT',
'PVR_VOUCHER_QTY',
'PVR_VOUCHER_MIN_AMOUNT',
'PVR_VOUCHER_VALIDITY',
];
$tree_field = [
'PVR_VOUCHER_CAT',
];
foreach (array_keys($form_values) as $key) {
if (in_array($key, $text_fields)) {
$content = [];
foreach (Language::getLanguages(false) as $langs) {
$id_lang = $langs['id_lang'];
$field_content = Tools::getValue($key . '_' . $id_lang);
if (!empty($field_content)) {
$content[$id_lang] = Tools::getValue($key . '_' . $id_lang);
} else {
$content[$id_lang] = Utils::defaultSentences($key);
}
}
Configuration::updateValue($key, json_encode($content), true);
} else {
if (in_array($key, $requiered_field)) {
$field_content = Tools::getValue($key);
if (!empty($field_content)) {
Configuration::updateValue($key, $field_content);
} else {
$default_value = Utils::defaultValueField($key);
Configuration::updateValue($key, $default_value);
}
} elseif (in_array($key, $tree_field)) {
if (is_array(Tools::getValue($key))) {
Configuration::updateValue($key, json_encode(Tools::getValue($key)));
}
} else {
if ($key != 'PVR_OAUTH' && $key != 'PVR_CRON_TOKEN' && $key != 'PVR_API_SHOP_ID') {
Configuration::updateValue($key, Tools::getValue($key));
}
}
}
$this->context->controller->confirmations[] = $this->l('Configuration updated');
}
if (!empty(Utils::isOauthed())) {
Utils::updateApiModuleConfiguration();
}
}
public function hookBackOfficeHeader()
{
if (Tools::getValue('module_name') == $this->name || Tools::getValue('configure') == $this->name) {
$this->context->controller->addJS($this->_path . 'views/js/owl.carousel.js');
$this->context->controller->addJS($this->_path . 'views/js/back.js');
$this->context->controller->addCSS($this->_path . 'views/css/admin/back.css');
$this->context->controller->addCSS($this->_path . 'views/css/admin/owl.carousel.min.css');
$this->context->controller->addCSS($this->_path . 'views/css/admin/owl.theme.default.min.css');
}
}
public function hookDisplayHeader()
{
$jsDefs = [];
$jsDefs['ajaxUrl'] = Context::getContext()->link->getModuleLink($this->name, 'ajax', []);
$jsDefs['token'] = Tools::getToken(false);
$jsDefs['pvr_script'] = _MODULE_DIR_ . $this->name . '/views/js/' . $this->name . '.js';
Media::addJsDef([$this->name => $jsDefs]);
Context::getContext()->controller->addCSS(_MODULE_DIR_ . $this->name . '/views/css/front/front.css');
Context::getContext()->controller->addCSS(_MODULE_DIR_ . $this->name . '/views/css/front/stars.css');
Context::getContext()->controller->addCSS(_MODULE_DIR_ . $this->name . '/views/css/front/battle.css');
Context::getContext()->controller->addCSS(_MODULE_DIR_ . $this->name . '/views/css/front/player.css');
Context::getContext()->controller->addCSS(_MODULE_DIR_ . $this->name . '/views/css/front/distribution.css');
Context::getContext()->controller->addCSS(_MODULE_DIR_ . $this->name . '/views/css/front/progress.css');
Context::getContext()->controller->addCSS(_MODULE_DIR_ . $this->name . '/views/css/front/grid.css');
Context::getContext()->controller->addCSS(_MODULE_DIR_ . $this->name . '/views/css/front/spinner.css');
Context::getContext()->controller->addJS(_MODULE_DIR_ . $this->name . '/views/js/' . $this->name . '.js');
}
public function hookActionOrderStatusUpdate($params)
{
try {
if (!empty(Utils::isOauthed())) {
$api_token = json_decode(Configuration::get('PVR_OAUTH'));
$order = new Order((int)$params['id_order']);
if (Validate::isLoadedObject($order)) {
if ((int)Configuration::get('PVR_STATUS_SELECTION') == $params['newOrderStatus']->id) {
$data = [
'order' => [
'reference' => $order->reference,
'validStatus' => true,
],
];
RecReviewsClient::sendUpdateStatus($api_token->access_token, $data);
}
}
}
} catch (Exception $e) {
PrestaShopLogger::addLog($e->getMessage(), 1, $e->getCode(), null, null, true);
}
}
public function hookActionValidateOrder($params)
{
try {
if (!empty(Utils::isOauthed())) {
if (!empty($params['order']) && Validate::isLoadedObject($params['order']) && $params['order']->module != $this->name && $params['order']->getCurrentState() != Configuration::get('PS_OS_ERROR')) {
$api_token = json_decode(Configuration::get('PVR_OAUTH'));
$gender = new Gender($params['customer']->id_gender);
$lang = new Language((int)$params['customer']->id_lang);
$phone = '';
$gender = $gender->type == 0 ? 'M' : 'F';
$order_api_date = [];
$voucher_api_data = [];
$api_data = [];
$data = [];
$products = $params['order']->getProductsDetail();
if (!empty($params['order']->id_address_invoice)) {
$address = new Address((int)$params['order']->id_address_invoice);
if (!empty($address->phone)) {
$phone = $address->phone;
} elseif (!empty($address->phone_mobile)) {
$phone = $address->phone_mobile;
}
}
if (is_array($products) && !empty($products)) {
foreach ($products as $product) {
$product_obj = new Product((int)$product['product_id']);
$image_size = ImageType::getFormattedName('large');
$currency = new Currency((int)$params['order']->id_currency);
$image_url = Utils::getProductImage($product_obj, $image_size, (int)$params['customer']->id_lang);
$data['products'][] = [
'id' => $product['product_id'],
'name' => $product_obj->name[(int)$params['customer']->id_lang],
'image' => !empty($image_url) ? $image_url : $this->context->shop->getBaseURL(true, false) . _PS_IMG_ . Configuration::get('PS_LOGO', null, null, Context::getContext()->shop->id),
'ratingUrl' => rtrim((string) Context::getContext()->link->getBaseLink(), '/'),
'price' => number_format((float)$product['product_price'], 2, '.', ''),
'currency' => (string)$currency->iso_code,
];
}
}
$order_api_date = [
'order' => [
'reference' => $params['order']->reference,
'order_date' => $params['order']->date_add . ' ' . Configuration::get('PS_TIMEZONE'),
'products' => $data['products'],
],
'customer' => [
'id' => $params['customer']->id,
'first_name' => $params['customer']->firstname,
'last_name' => $params['customer']->lastname,
'email' => $params['customer']->email,
'birthdate' => !empty($params['customer']->birthday) && $params['customer']->birthday != '0000-00-00' ? str_replace('/', '-', $params['customer']->birthday) : null,
'gender' => $gender,
'lang' => $lang->iso_code,
'id_shop_lang' => (int)$params['customer']->id_lang,
'phone' => !empty($phone) ? $phone : '0000000000',
],
];
$api_data = array_merge($order_api_date, $voucher_api_data);
RecReviewsClient::sendOrderData($api_token->access_token, $api_data);
}
}
} catch (Exception $e) {
PrestaShopLogger::addLog($e->getMessage(), 1, $e->getCode(), null, null, true);
}
}
public function hookDisplayFooterProduct($params)
{
$product_id = !empty($params['product']->id) ? $params['product']->id : Tools::getValue('idProduct');
if (empty($product_id)) {
return;
}
$sort = Tools::getValue('pvrRwSort', 'recent');
$reviews = [];
$show_more_value = Tools::getValue('show_more_value', (int)Configuration::get('PVR_PRODUCT_REVIEW_LINES'));
$show_more_value_with_sort = Tools::getValue('show_more_value_with_sort');
$product_obj = new Product((int)$product_id, 1);
$reviews = Ratings::getProductReviews($product_id);
if (empty($reviews)) {
return;
}
$distribution_data = Utils::getDistribution($product_id, $reviews);
$reviews_details = Utils::formatReviewsDetail($reviews, $product_id);
$show_more_data = Utils::showMoreData($reviews, (int)$reviews_details['total_reviews'], $show_more_value);
Context::getContext()->smarty->assign([
'total_review' => !empty($reviews_details['total_reviews']) ? $reviews_details['total_reviews'] : [],
'reviews' => !empty($show_more_data['display_reviews']) ? $show_more_data['display_reviews'] : [],
'reviews_detail' => !empty($reviews_details['reviews_detail']) ? $reviews_details['reviews_detail'] : [],
'product_id' => $product_id,
'pvrRwSort' => $sort,
'max_rating' => 5,
'has_half_star' => false,
'token' => Tools::getToken(false),
'review_average_int' => !empty($reviews_details['average']['review_average_int']) ? $reviews_details['average']['review_average_int'] : [],
'review_average_float' => !empty($reviews_details['average']['review_average_float']) ? $reviews_details['average']['review_average_float'] : [],
'max_distribution_block' => 5,
'max_rating_block' => !empty($reviews_details['average']['has_half']) ? 10 : 5,
'has_half_stars' => !empty($reviews_details['average']['has_half']) ? $reviews_details['average']['has_half'] : [],
'distribution_data' => !empty($distribution_data['distribution']) ? $distribution_data['distribution'] : [],
'percentage' => !empty($reviews_details['average']['review_average_float']) ? ((float)$reviews_details['average']['review_average_float'] * 100) / 5 : 0,
'percent_per_note' => !empty($distribution_data['percent_note']) ? $distribution_data['percent_note'] : [],
'battle' => !empty($reviews_details['battles']) ? $reviews_details['battles'] : [],
'battle_details' => !empty($reviews_details['battle_details']) ? $reviews_details['battle_details'] : [],
'show_more_value' => !empty($show_more_data['show_more_value']) ? $show_more_data['show_more_value'] : 4,
'has_show_more' => !empty($show_more_data['has_show_more']) ? $show_more_data['has_show_more'] : false,
'review_per_ligne' => (int)Configuration::get('PVR_PRODUCT_REVIEW_LINES'),
'logo_path' => _MODULE_DIR_ . $this->name . '/views/img/recreviews-logo.svg',
'product_name' => $product_obj->name[(int)Context::getContext()->language->id],
'show_more_value_default' => (int)Configuration::get('PVR_PRODUCT_REVIEW_LINES'),
]);
return $this->fetch('module:' . $this->name . '/views/templates/hook/product-footer.tpl');
}
public function hookActionObjectLanguageAddAfter()
{
$this->updateTexts();
}
public function hookActionEmailSendBefore($params)
{
$recShopId = Configuration::get('PVR_API_SHOP_ID');
if (empty($recShopId) || empty(Module::isInstalled('pmproductvideoreviews')) || empty(Module::isEnabled('pmproductvideoreviews'))) {
return;
}
$orderRef = Utils::handleOrderReferenceForRecorderLink($params['templateVars']);
if (!empty($orderRef)) {
$params['templateVars']['{rec_recorder_url}'] = RecReviewsClient::API_URL . 'record-review-from-email/' . (string)$recShopId . '?' . http_build_query([
'order' => $orderRef,
'email' => $params['to'],
]);
}
}
protected function updateTexts()
{
Language::loadLanguages();
$availableLanguages = Language::getLanguages(false);
$voucherMinAmountDesc = json_decode(Configuration::get('PVR_VOUCHER_MIN_AMOUNT_DESC'), true);
$voucherIncentiveText = json_decode(Configuration::get('PVR_VOUCHER_INCENTIVE_TEXT'), true);
foreach ($availableLanguages as $availableLang) {
if (!isset($voucherMinAmountDesc[$availableLang['id_lang']])) {
$voucherMinAmountDesc[$availableLang['id_lang']] = Utils::defaultSentences('PVR_VOUCHER_MIN_AMOUNT_DESC');
}
if (!isset($voucherIncentiveText[$availableLang['id_lang']])) {
$voucherIncentiveText[$availableLang['id_lang']] = Utils::defaultSentences('PVR_VOUCHER_INCENTIVE_TEXT');
}
}
Configuration::updateValue('PVR_VOUCHER_MIN_AMOUNT_DESC', json_encode($voucherMinAmountDesc));
Configuration::updateValue('PVR_VOUCHER_INCENTIVE_TEXT', json_encode($voucherIncentiveText));
}
private function installTab()
{
$tabId = (int)Tab::getIdFromClassName($this->adminTab['class_name']);
if (!$tabId) {
$tabId = null;
}
$tab = new Tab($tabId);
$tab->active = 1;
$tab->class_name = $this->adminTab['class_name'];
foreach (Language::getLanguages() as $lang) {
$tab->name[$lang['id_lang']] = !empty($this->adminTab['name'][$lang['iso_code']]) ? $this->adminTab['name'][$lang['iso_code']] : $this->adminTab['name']['en'];
}
if (!empty($this->adminTab['parent_class_name'])) {
$tab->id_parent = (int) Tab::getIdFromClassName($this->adminTab['parent_class_name']);
} else {
$tab->id_parent = 0;
}
$tab->module = $this->name;
return $tab->save();
}
private function initModuleConf()
{
$this->updateTexts();
Configuration::updateValue('PVR_EMAIL_DELAY', 5);
Configuration::updateValue('PVR_STATUS_SELECTION', 5);
Configuration::updateValue('PVR_ENABLE_VOUCHER', false);
Configuration::updateValue('PVR_VOUCHER_PREFIX', 'REVIEW-');
Configuration::updateValue('PVR_VOUCHER_TYPE', 'amount');
Configuration::updateValue('PVR_VOUCHER_AMOUNT', '10');
Configuration::updateValue('PVR_VOUCHER_PERCENT', '10');
Configuration::updateValue('PVR_VOUCHER_CURRENCY', '1');
Configuration::updateValue('PVR_VOUCHER_TAX', true);
Configuration::updateValue('PVR_VOUCHER_DESC', 'Voucher for video reviews');
Configuration::updateValue('PVR_VOUCHER_GENERATE', 'order');
Configuration::updateValue('PVR_VOUCHER_QTY', '1');
Configuration::updateValue('PVR_VOUCHER_MIN_AMOUNT', '10');
Configuration::updateValue('PVR_VOUCHER_CAT', []);
Configuration::updateValue('PVR_VOUCHER_VALIDITY', '365');
Configuration::updateValue('PVR_VOUCHER_HIGHLIGHT', false);
Configuration::updateValue('PVR_VOUCHER_CUMULATE', false);
Configuration::updateValue('PVR_PRODUCT_REVIEW_LINES', '4');
Configuration::updateValue('PVR_PRODUCT_NB_LOAD_ITEM', '4');
Configuration::updateValue('PVR_ENABLE_BATTLE', true);
return true;
}
public function getService($serviceName)
{
if ($this->container === null) {
$this->container = new \PrestaShop\ModuleLibServiceContainer\DependencyInjection\ServiceContainer(
$this->name,
$this->getLocalPath()
);
}
return $this->container->getService($serviceName);
}
public function initRbmLink()
{
$facade = $this->getService('ps_accounts.facade');
$presentedAccount = $facade->getPsAccountsPresenter()->present($this->name);
$data = [
'email' => $presentedAccount['user']['email'],
'userId' => $presentedAccount['user']['uuid'],
'shopUrl' => $presentedAccount['currentShop']['frontUrl'],
'shopId' => $presentedAccount['currentShop']['uuid'],
'shopName' => Configuration::get('PS_SHOP_NAME'),
'lang' => $this->context->language->iso_code == 'fr' ? 'fr' : 'en',
'logo' => $this->context->shop->getBaseURL(true, false) . _PS_IMG_ . Configuration::get('PS_LOGO', null, null, Context::getContext()->shop->id),
'firstName' => Tools::getValue('firstName'),
'lastName' => Tools::getValue('lastName'),
];
$client = RecReviewsClient::getClient();
$createdData = $client->createLimitedTrialSubscription($data);
if (empty($createdData['subscription']) || empty($createdData['shop'])) {
$this->context->controller->errors[] = $this->l('An error occurred');
} else {
Configuration::updateValue('PVR_RBM_SUB_ID', $createdData['subscription']);
Configuration::updateValue('PVR_API_SHOP_ID', $createdData['shop']);
}
return Tools::redirectAdmin(Context::getContext()->link->getAdminLink('AdminModules') . '&configure=pmproductvideoreviews');
}
protected function renderTemplate($template, $params = [])
{
$templateContent = '';
$scope = $this->context->smarty->createData(
$this->context->smarty
);
$scope->assign($params);
$tpl = $this->context->smarty->createTemplate(
$this->getTemplatePath($template) . $template,
$scope
);
return $tpl->fetch();
}
}