From 72639aadbbd42bfe7d579a692155854b71076d01 Mon Sep 17 00:00:00 2001 From: max-baranikov Date: Tue, 27 Jul 2021 13:25:44 +0300 Subject: [PATCH] Generate Icml in settings tab --- .gitignore | 1 + doc/1. Setup/Catalog.md | 38 ++++ .../CLI & Job Manager/Job Manager.md | 6 + .../Forward Synchronization/Icml.md | 7 + doc/2. Workflow/Multistore.md | 4 + retailcrm/lib/RetailcrmCatalog.php | 10 ++ retailcrm/lib/RetailcrmCatalogHelper.php | 149 +++++++++++++++ retailcrm/lib/RetailcrmCli.php | 3 +- retailcrm/lib/RetailcrmContextSwitcher.php | 129 +++++++++++++ retailcrm/lib/RetailcrmJobManager.php | 170 +++++++++++------- retailcrm/lib/RetailcrmLogger.php | 96 +++++++--- retailcrm/lib/RetailcrmReferences.php | 45 +++++ retailcrm/lib/RetailcrmTools.php | 55 ++++-- .../events/RetailcrmAbandonedCartsEvent.php | 4 +- .../lib/events/RetailcrmAbstractEvent.php | 16 +- .../lib/events/RetailcrmEventInterface.php | 7 + retailcrm/lib/events/RetailcrmExportEvent.php | 4 +- retailcrm/lib/events/RetailcrmIcmlEvent.php | 12 +- .../events/RetailcrmIcmlUpdateUrlEvent.php | 95 ++++++++++ .../lib/events/RetailcrmInventoriesEvent.php | 2 +- .../lib/events/RetailcrmMissingEvent.php | 2 +- retailcrm/lib/events/RetailcrmSyncEvent.php | 2 +- .../events/RetailcrmUpdateSinceIdEvent.php | 4 +- .../templates/RetailcrmSettingsTemplate.php | 2 + retailcrm/retailcrm.php | 94 +++++++++- retailcrm/translations/es.php | 128 +++++++------ retailcrm/translations/ru.php | 128 +++++++------ retailcrm/upgrade/upgrade-3.3.2.php | 3 +- .../views/css/less/retailcrm-export.less | 1 + retailcrm/views/css/less/styles.less | 52 ++++++ retailcrm/views/css/retailcrm-export.min.css | 2 +- retailcrm/views/css/styles.min.css | 2 +- retailcrm/views/js/retailcrm-export.js | 2 +- retailcrm/views/js/retailcrm-export.min.js | 3 +- retailcrm/views/js/retailcrm-icml.js | 95 ++++++++++ retailcrm/views/js/retailcrm-icml.min.js | 42 +++++ retailcrm/views/js/retailcrm.js | 26 ++- retailcrm/views/js/retailcrm.min.js | 3 +- retailcrm/views/templates/admin/settings.tpl | 104 ++++++++++- 39 files changed, 1284 insertions(+), 264 deletions(-) create mode 100644 doc/1. Setup/Catalog.md create mode 100644 doc/2. Workflow/CLI & Job Manager/Job Manager.md create mode 100644 retailcrm/lib/RetailcrmCatalogHelper.php create mode 100644 retailcrm/lib/RetailcrmContextSwitcher.php create mode 100644 retailcrm/lib/events/RetailcrmIcmlUpdateUrlEvent.php create mode 100644 retailcrm/views/js/retailcrm-icml.js create mode 100644 retailcrm/views/js/retailcrm-icml.min.js diff --git a/.gitignore b/.gitignore index 8d80310..f825fbf 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ retailcrm/views/css/less/*.map retailcrm/views/css/*.css retailcrm/views/css/*.map !retailcrm/views/css/*.min.css +retailcrm/views/js/*.map retailcrm/config*.xml retailcrm/custom coverage.xml \ No newline at end of file diff --git a/doc/1. Setup/Catalog.md b/doc/1. Setup/Catalog.md new file mode 100644 index 0000000..da37c10 --- /dev/null +++ b/doc/1. Setup/Catalog.md @@ -0,0 +1,38 @@ +# Catalog + +## Generate Icml + +По кнопке Generate now можно вручную сгенерировать каталог. Для сгенерированного каталога отображается время его +последней генерации, количество товаров и торговых предложений. Если с момента генерации прошло более 4-х часов, то +будет отображено соответствующее уведомление. + +## Update URL + +При загрузке страницы выполняется проверка URL адреса файла Icml каталога, указанного в настройках магазина в CRM. Если +адрес в системе не совпадает с фактическим адресом сгенерированного файла, то на странице отображается соответствующее +уведомление и кнопка, позволяющая обновить URL. + +## Jobs run + +Задачи генерации каталога и обновления URL выполняются через **JobManager** +в [`force` режиме](../2.%20Workflow/CLI%20&%20Job%20Manager/Job%20Manager.md#force-option). + +## Multistore + +При включенной опции **Multistore** есть возможность запустить процесс генерации каталога/обновления URL сразу для +нескольких или всех магазинов. Для этого нужно перейти в контекст конкретной группы или всех магазинов и нажать +соответствующую кнопку. + +В контексте группы отображается информация о каталогах для каждого магазина, входящего в эту группу. Можно перейти в +контекст конкретного магазина, кликнув по его имени. + +## Manage site settings + +Можно перейти в настройки каталога в CRM, кликнув по `Manage site settings`. Если не удалось сформировать ссылку на +настройки каталога, то вместо этого для магазина будет предоставлена ссылка на список всех магазинов CRM + +## Errors + +При наличии каких либо проблем с каталогом — отсутствие файла, устаревший файл или несовпадение URL, +вкладка `Icml catalog` будет подсвечиваться красным цветом, сигнализируя об ошибках. В случае отсутствия файла каталога +в первые 4 часа после установки и первичной настройки модуля ошибка возникать не будет diff --git a/doc/2. Workflow/CLI & Job Manager/Job Manager.md b/doc/2. Workflow/CLI & Job Manager/Job Manager.md new file mode 100644 index 0000000..f5dc409 --- /dev/null +++ b/doc/2. Workflow/CLI & Job Manager/Job Manager.md @@ -0,0 +1,6 @@ +# Job Manager + +## Force option + +Режим принудительного запуска позволяет запустить задачу независимо от того, запущена ли сейчас другая задача через Job +Manager. Запущенная таким образом задача не блокирует работу Job Manager diff --git a/doc/2. Workflow/Forward Synchronization/Icml.md b/doc/2. Workflow/Forward Synchronization/Icml.md index c724893..a1a3cd7 100644 --- a/doc/2. Workflow/Forward Synchronization/Icml.md +++ b/doc/2. Workflow/Forward Synchronization/Icml.md @@ -1,2 +1,9 @@ # Icml +При генерации каталога подсчитывается количество продуктов и торговых предложений. Это сохраняется в +настройку `RETAILCRM_ICML_INFO` в базу данных CMS. + +Дата генерации каталога берется непосредственно из содержимого файла из +строки `` + +Методы по работе с сохраненными настройками и файлом вынесены в класс `RetailcrmCatalogHelper` \ No newline at end of file diff --git a/doc/2. Workflow/Multistore.md b/doc/2. Workflow/Multistore.md index 45d7fa1..2d477bb 100644 --- a/doc/2. Workflow/Multistore.md +++ b/doc/2. Workflow/Multistore.md @@ -1,2 +1,6 @@ # Multistore +## Context Switcher + +Класс `RetailcrmContextSwitcher` отвечает за переключение текущего контекста, а также позволяет запустить какую-нибудь +функцию поочередно для всех магазинов в текущем контексте (в рамках одного магазина, одной группы или всех магазинов) diff --git a/retailcrm/lib/RetailcrmCatalog.php b/retailcrm/lib/RetailcrmCatalog.php index a07060a..41f0f0b 100644 --- a/retailcrm/lib/RetailcrmCatalog.php +++ b/retailcrm/lib/RetailcrmCatalog.php @@ -38,6 +38,7 @@ */ class RetailcrmCatalog { + public $default_lang; public $default_currency; public $default_country; @@ -105,6 +106,9 @@ class RetailcrmCatalog public function getOffers() { + $productsCount = 0; + $offersCount = 0; + $id_lang = $this->default_lang; $homeCategory = $this->home_category; @@ -156,6 +160,7 @@ class RetailcrmCatalog if (empty($categoriesLeft)) { continue; } + $productsCount++; if ($this->version == "1.3") { $available_for_order = $product['active'] && $product['quantity']; @@ -206,6 +211,7 @@ class RetailcrmCatalog $offers = Product::getProductAttributesIds($product['id_product']); if (!empty($offers)) { + $offersCount+= count($offers); $productForCombination = new Product($product['id_product']); foreach ($offers as $offer) { @@ -298,6 +304,7 @@ class RetailcrmCatalog ); } } else { + $offersCount++; $pictures = array(); $covers = Image::getImages($id_lang, $product['id_product'], null); @@ -343,6 +350,8 @@ class RetailcrmCatalog $start += $limit; } while ($start < $count && count($products) > 0); + + RetailcrmCatalogHelper::setIcmlFileInfo($productsCount, $offersCount); } private static function getProductsCount( @@ -430,4 +439,5 @@ class RetailcrmCatalog return $parentId; } + } diff --git a/retailcrm/lib/RetailcrmCatalogHelper.php b/retailcrm/lib/RetailcrmCatalogHelper.php new file mode 100644 index 0000000..c98a827 --- /dev/null +++ b/retailcrm/lib/RetailcrmCatalogHelper.php @@ -0,0 +1,149 @@ + + * @copyright 2020 DIGITAL RETAIL TECHNOLOGIES SL + * @license https://opensource.org/licenses/MIT The MIT License + * + * Don't forget to prefix your containers with your own identifier + * to avoid any conflicts with others containers. + */ +class RetailcrmCatalogHelper +{ + const ICML_INFO_NAME = 'RETAILCRM_ICML_INFO'; + + public static function getIcmlFileDate() + { + $date = null; + $filePath = self::getIcmlFilePath(); + if (!file_exists($filePath) || ($fileHandler = fopen($filePath, 'rb')) === false) { + return null; + } + + while ($line = fgets($fileHandler)) { + if (strpos($line, 'yml_catalog date=') !== false) { + preg_match_all('/date="([\d\- :]+)"/', $line, $matches); + if (count($matches) == 2) { + $date = $matches[1][0]; + } + break; + } + } + + fclose($fileHandler); + + return $date; + } + + public static function getIcmlFileLink() + { + return _PS_BASE_URL_ . '/' . self::getIcmlFilename(); + } + + public static function getIcmlFileName() + { + $isMultiStoreActive = Shop::isFeatureActive(); + $shop = Context::getContext()->shop; + + if ($isMultiStoreActive) { + $icmlFileName = 'simla_' . $shop->id . '.xml'; + } else { + $icmlFileName = 'simla.xml'; + } + + return $icmlFileName; + } + + public static function getIcmlFilePath() + { + return _PS_ROOT_DIR_ . '/' . self::getIcmlFileName(); + } + + public static function getIcmlFileInfo() + { + $icmlInfo = json_decode((string)Configuration::get(self::ICML_INFO_NAME), true); + + if (json_last_error() != JSON_ERROR_NONE) { + $icmlInfo = array(); + } + $lastGenerated = DateTime::createFromFormat('Y-m-d H:i:s', self::getIcmlFileDate()); + + if ($lastGenerated instanceof DateTime) { + $icmlInfo['lastGenerated'] = $lastGenerated; + $now = new DateTime(); + /** @var DateInterval $diff */ + $diff = $lastGenerated->diff($now); + + $icmlInfo['lastGeneratedDiff'] = array( + 'days' => $diff->days, + 'hours' => $diff->h, + 'minutes' => $diff->i + ); + + $icmlInfo['isOutdated'] = ( + $icmlInfo['lastGeneratedDiff']['days'] > 0 + || $icmlInfo['lastGeneratedDiff']['hours'] > 4 + ); + } + + $api = RetailcrmTools::getApiClient(); + + if ($api !== null) { + $reference = new RetailcrmReferences($api); + + $site = $reference->getSite(); + $icmlInfo['isUrlActual'] = !empty($site['ymlUrl']) && $site['ymlUrl'] === self::getIcmlFileLink(); + if (!empty($site['catalogId'])) { + $icmlInfo['siteId'] = $site['catalogId']; + } + } + + return (array)$icmlInfo; + } + + public static function getIcmlFileInfoMultistore() + { + return RetailcrmContextSwitcher::runInContext(array(self::class, 'getIcmlFileInfo')); + } + + /** + * @param int $productsCount + * @param int $offersCount + */ + public static function setIcmlFileInfo($productsCount, $offersCount) + { + $icmlInfo = array( + 'productsCount' => $productsCount, + 'offersCount' => $offersCount + ); + Configuration::updateValue(self::ICML_INFO_NAME, (string)json_encode($icmlInfo)); + } +} \ No newline at end of file diff --git a/retailcrm/lib/RetailcrmCli.php b/retailcrm/lib/RetailcrmCli.php index 3802c42..8dbc8fa 100644 --- a/retailcrm/lib/RetailcrmCli.php +++ b/retailcrm/lib/RetailcrmCli.php @@ -159,7 +159,7 @@ class RetailcrmCli private function runJob($jobName, $shopId) { try { - $result = RetailcrmJobManager::runJob($jobName, true, true, $shopId); + $result = RetailcrmJobManager::runJob($jobName, true, false, $shopId); RetailcrmLogger::output(sprintf( 'Job %s was executed, result: %s', $jobName, @@ -372,6 +372,7 @@ class RetailcrmCli return array( 'RetailcrmAbandonedCartsEvent', 'RetailcrmIcmlEvent', + 'RetailcrmIcmlUpdateUrlEvent', 'RetailcrmSyncEvent', 'RetailcrmInventoriesEvent', 'RetailcrmExportEvent', diff --git a/retailcrm/lib/RetailcrmContextSwitcher.php b/retailcrm/lib/RetailcrmContextSwitcher.php new file mode 100644 index 0000000..4607c54 --- /dev/null +++ b/retailcrm/lib/RetailcrmContextSwitcher.php @@ -0,0 +1,129 @@ + + * @copyright 2020 DIGITAL RETAIL TECHNOLOGIES SL + * @license https://opensource.org/licenses/MIT The MIT License + * + * Don't forget to prefix your containers with your own identifier + * to avoid any conflicts with others containers. + */ +class RetailcrmContextSwitcher +{ + /** + * @var int + */ + private static $contextShopType; + /** + * @var Shop + */ + private static $contextShop; + + /** + * Runs given callback function in all context shops + * + * @param callable $callback + * @param array $arguments Arguments that will be passed to callback function + * @return array + */ + public static function runInContext($callback, $arguments = array()) + { + $result = array(); + self::storeContext(); + + foreach (self::getShops() as $shop) { + self::setShopContext(intval($shop['id_shop'])); + $result[intval($shop['id_shop'])] = call_user_func_array($callback, $arguments); + } + + self::restoreContext(); + + return $result; + } + + private static function storeContext() + { + static::$contextShopType = Shop::getContext(); + static::$contextShop = Context::getContext()->shop; + } + + private static function restoreContext() + { + switch (static::$contextShopType) { + case Shop::CONTEXT_GROUP: + $contextShopId = static::$contextShop->id_shop_group; + break; + case Shop::CONTEXT_SHOP: + $contextShopId = static::$contextShop->id; + break; + default: + $contextShopId = null; + break; + } + + try { + Shop::setContext(static::$contextShopType, $contextShopId); + } catch (PrestaShopException $e) { + RetailcrmLogger::writeCaller(__METHOD__, 'Unable to set shop context'); + } + Context::getContext()->shop = static::$contextShop; + } + + /** + * + * Change shop in the context + * + * @param $id_shop + */ + public static function setShopContext($id_shop) + { + try { + Shop::setContext(Shop::CONTEXT_SHOP, $id_shop); + } catch (PrestaShopException $e) { + RetailcrmLogger::writeCaller(__METHOD__, 'Unable to set shop context'); + } + Context::getContext()->shop = new Shop($id_shop); + } + + /** + * @return array + */ + public static function getShops() + { + $idShop = Shop::getContextShopID(); + + if (Shop::isFeatureActive() && $idShop === null) { + return Shop::getShops(true, Shop::getContextShopGroupID(true)); + } else { + return array(Shop::getShop($idShop)); + } + } +} \ No newline at end of file diff --git a/retailcrm/lib/RetailcrmJobManager.php b/retailcrm/lib/RetailcrmJobManager.php index 9976424..f2257c5 100644 --- a/retailcrm/lib/RetailcrmJobManager.php +++ b/retailcrm/lib/RetailcrmJobManager.php @@ -74,8 +74,7 @@ class RetailcrmJobManager * RetailcrmJobManager::startJobs( * array( * 'jobName' => DateInterval::createFromDateString('1 hour') - * ), - * true + * ) * ); * * File `jobName.php` must exist in retailcrm/job and must contain everything to run job. @@ -84,27 +83,24 @@ class RetailcrmJobManager * any delay - in other words, jobs without interval will be executed every time. * * @param array $jobs Jobs list - * @param bool $runOnceInContext Use require_once instead of require * * @throws \Exception */ public static function startJobs( - $jobs = array(), - $runOnceInContext = true + $jobs = array() ) { RetailcrmLogger::writeDebug(__METHOD__,'starting JobManager'); - static::execJobs($jobs, $runOnceInContext); + static::execJobs($jobs); } /** * Run scheduled jobs with request * * @param array $jobs - * @param bool $runOnceInContext * * @throws \Exception */ - public static function execJobs($jobs = array(), $runOnceInContext = false) + public static function execJobs($jobs = array()) { $current = date_create('now'); $lastRuns = array(); @@ -185,7 +181,7 @@ class RetailcrmJobManager if (isset($shouldRunAt) && $shouldRunAt <= $current) { RetailcrmLogger::writeDebug(__METHOD__, sprintf('Executing job %s', $job)); - $result = RetailcrmJobManager::runJob($job, $runOnceInContext); + $result = RetailcrmJobManager::runJob($job); RetailcrmLogger::writeDebug( __METHOD__, sprintf('Executed job %s, result: %s', $job, $result ? 'true' : 'false') @@ -198,39 +194,25 @@ class RetailcrmJobManager if ($exception instanceof RetailcrmJobManagerException && $exception->getPrevious() instanceof \Exception ) { - $lastRunsDetails[$job] = [ - 'success' => false, - 'lastRun' => new \DateTime('now'), - 'error' => [ - 'message' => $exception->getPrevious()->getMessage(), - 'trace' => $exception->getPrevious()->getTraceAsString(), - ], - ]; - - static::handleError( - $exception->getPrevious()->getFile(), - $exception->getPrevious()->getMessage(), - $exception->getPrevious()->getTraceAsString(), - $job - ); - } else { - $lastRunsDetails[$job] = [ - 'success' => false, - 'lastRun' => new \DateTime('now'), - 'error' => [ - 'message' => $exception->getMessage(), - 'trace' => $exception->getTraceAsString(), - ], - ]; - - static::handleError( - $exception->getFile(), - $exception->getMessage(), - $exception->getTraceAsString(), - $job - ); + $exception = $exception->getPrevious(); } + $lastRunsDetails[$job] = [ + 'success' => false, + 'lastRun' => new \DateTime('now'), + 'error' => [ + 'message' => $exception->getMessage(), + 'trace' => $exception->getTraceAsString(), + ], + ]; + + static::handleError( + $exception->getFile(), + $exception->getMessage(), + $exception->getTraceAsString(), + $job + ); + self::clearCurrentJob($job); } } @@ -261,6 +243,50 @@ class RetailcrmJobManager static::unlock(); } + + /** + * Run job in the force mode so it will run even if there's another job running + * + * @param $jobName + * @return bool + * @throws Exception + */ + public static function execManualJob($jobName) + { + try { + $result = static::runJob($jobName, false, true, Shop::getContextShopID()); + + if ($result) { + static::updateLastRunDetail($jobName, [ + 'success' => true, + 'lastRun' => new \DateTime('now'), + 'error' => null, + ]); + } + + return $result; + } catch (\Exception $exception) { + if ($exception instanceof RetailcrmJobManagerException + && $exception->getPrevious() instanceof \Exception + ) { + $exception = $exception->getPrevious(); + } + + RetailcrmLogger::printException($exception, '', false); + self::updateLastRunDetail($jobName, [ + 'success' => false, + 'lastRun' => new \DateTime('now'), + 'error' => [ + 'message' => $exception->getMessage(), + 'trace' => $exception->getTraceAsString(), + ], + ]); + + throw $exception; + } + } + + /** * Extracts jobs last runs from db * @@ -319,6 +345,17 @@ class RetailcrmJobManager Configuration::updateGlobalValue(self::LAST_RUN_NAME, (string)json_encode($lastRuns)); } + /** + * @param string $jobName + * @param Datetime|null $data + * @throws Exception + */ + public static function updateLastRun($jobName, $data) + { + $lastRuns = static::getLastRuns(); + $lastRuns[$jobName] = $data; + static::setLastRuns($lastRuns); + } /** * Extracts jobs last runs from db @@ -361,7 +398,7 @@ class RetailcrmJobManager } foreach ($lastRuns as $job => $details) { - if ($details['lastRun'] instanceof DateTime) { + if (isset($details['lastRun']) && $details['lastRun'] instanceof DateTime) { $lastRuns[$job]['lastRun'] = $details['lastRun']->format(DATE_RFC3339); } else { $lastRuns[$job]['lastRun'] = null; @@ -371,41 +408,40 @@ class RetailcrmJobManager Configuration::updateGlobalValue(self::LAST_RUN_DETAIL_NAME, (string)json_encode($lastRuns)); } + /** + * @param string $jobName + * @param array $data + * @throws Exception + */ + public static function updateLastRunDetail($jobName, $data) + { + $lastRunsDetails = static::getLastRunDetails(); + $lastRunsDetails[$jobName] = $data; + static::setLastRunDetails($lastRunsDetails); + } + /** * Runs job * * @param string $job * @param bool $once * @param bool $cliMode + * @param bool $force + * @param int $shopId * * @return bool * @throws \RetailcrmJobManagerException */ - public static function runJob($job, $once = false, $cliMode = false, $shopId = null) + public static function runJob($job, $cliMode = false, $force = false, $shopId = null) { $jobName = self::escapeJobName($job); - $jobFile = implode( - DIRECTORY_SEPARATOR, - array(_PS_ROOT_DIR_, 'modules', 'retailcrm_custom','classes', 'lib', 'events', $jobName . '.php') - ); - - if (!file_exists($jobFile)) { - $jobFile = implode( - DIRECTORY_SEPARATOR, - array(_PS_ROOT_DIR_, 'modules', 'retailcrm', 'lib', 'events', $jobName . '.php') - ); - - if (!file_exists($jobFile)) { - throw new \RetailcrmJobManagerException('Cannot find job', $job); - } - } try { - return static::execHere($jobName, $jobFile, $once, $cliMode, $shopId); + return static::execHere($jobName, $cliMode, $force, $shopId); } catch (\RetailcrmJobManagerException $exception) { throw $exception; } catch (\Exception $exception) { - throw new RetailcrmJobManagerException($exception->getMessage(), $jobFile, array(), 0, $exception); + throw new RetailcrmJobManagerException($exception->getMessage(), $job, array(), 0, $exception); } } @@ -601,15 +637,17 @@ class RetailcrmJobManager * @param string $phpScript * @param bool $once * @param bool $cliMode + * @param bool $force + * @param int $shopId * * @return bool * @throws \RetailcrmJobManagerException */ - private static function execHere($jobName, $phpScript, $once = false, $cliMode = false, $shopId = null) + private static function execHere($jobName, $cliMode = false, $force = false, $shopId = null) { set_time_limit(static::getTimeLimit()); - if (!$cliMode) { + if (!$cliMode && !$force) { ignore_user_abort(true); if (version_compare(phpversion(), '7.0.16', '>=') && @@ -624,16 +662,9 @@ class RetailcrmJobManager } } - if ($once) { - require_once($phpScript); - } else { - require($phpScript); - } - if (!class_exists($jobName)) { throw new \RetailcrmJobManagerException(sprintf( - 'The job file "%s" has been found, but job class "%s" was not present in there.', - $phpScript, + 'The job class "%s" was not found.', $jobName )); } @@ -648,6 +679,7 @@ class RetailcrmJobManager } $job->setCliMode($cliMode); + $job->setForce($force); $job->setShopId($shopId); self::registerShutdownHandler(); diff --git a/retailcrm/lib/RetailcrmLogger.php b/retailcrm/lib/RetailcrmLogger.php index 8bbf666..76b5f54 100644 --- a/retailcrm/lib/RetailcrmLogger.php +++ b/retailcrm/lib/RetailcrmLogger.php @@ -122,6 +122,22 @@ class RetailcrmLogger } } + /** + * Output error info to stdout + * + * @param $exception + * @param string $header + */ + public static function printException($exception, $header = 'Error while executing a job: ', $toOutput = true) + { + $method = $toOutput ? 'output' : 'writeNoCaller'; + + self::$method(sprintf('%s%s', $header, $exception->getMessage())); + self::$method(sprintf('%s:%d', $exception->getFile(), $exception->getLine())); + self::$method(''); + self::$method($exception->getTraceAsString()); + } + /** * Write debug log record * @@ -179,6 +195,11 @@ class RetailcrmLogger return self::getLogDir() . '/retailcrm_' . self::getLogFilePrefix() . '_' . date('Y_m_d') . '.log'; } + /** + * Returns log files directory based on current Prestashop version + * + * @return string + */ public static function getLogDir() { $logDir = version_compare(_PS_VERSION_, '1.7', '<') ? '/log' : '/var/logs'; @@ -205,9 +226,47 @@ class RetailcrmLogger } /** - * Removes module log files from var/logs which is older than 30 days + * Removes module log files that are older than 30 days */ public static function clearObsoleteLogs() + { + $logFiles = self::getLogFiles(); + + foreach ($logFiles as $logFile) { + if (filemtime($logFile) < strtotime('-30 days')) { + unlink($logFile); + } + } + } + + /** + * Retrieves log files basic info for advanced tab + * + * @return array + */ + public static function getLogFilesInfo() + { + $fileNames = []; + $logFiles = self::getLogFiles(); + + foreach ($logFiles as $logFile) { + $fileNames[] = [ + 'name' => basename($logFile), + 'path' => $logFile, + 'size' => number_format(filesize($logFile), 0, '.', ' ') . ' bytes', + 'modified' => date('Y-m-d H:i:s', filemtime($logFile)), + ]; + } + + return $fileNames; + } + + /** + * Retrieves log files paths + * + * @return Generator|void + */ + private static function getLogFiles() { $logDir = self::getLogDir(); @@ -218,40 +277,19 @@ class RetailcrmLogger $handle = opendir($logDir); while (($file = readdir($handle)) !== false) { if (self::checkFileName($file) !== false) { - $path = "$logDir/$file"; - if (filemtime($path) < strtotime('-30 days')) { - unlink($path); - } + yield "$logDir/$file"; } } - } - public static function getLogFilesInfo() - { - $fileNames = []; - $logDir = self::getLogDir(); - - if (!is_dir($logDir)) { - return; - } - - $handle = opendir($logDir); - while ($file = readdir($handle) !== false) { - if (self::checkFileName($file) !== false) { - $path = "$logDir/$file"; - $fileNames[] = [ - 'name' => $file, - 'path' => $path, - 'size' => number_format(filesize($path), 0, '.', ' ') . ' bytes', - 'modified' => date('Y-m-d H:i:s', filemtime($path)), - ]; - } - } closedir($handle); - - return $fileNames; } + /** + * Checks if given logs filename relates to the module + * + * @param string $file + * @return false|string + */ public static function checkFileName($file) { $logDir = self::getLogDir(); diff --git a/retailcrm/lib/RetailcrmReferences.php b/retailcrm/lib/RetailcrmReferences.php index 84c808a..81d29b9 100644 --- a/retailcrm/lib/RetailcrmReferences.php +++ b/retailcrm/lib/RetailcrmReferences.php @@ -43,6 +43,9 @@ class RetailcrmReferences public $carriers; public $payment_modules = array(); + /** + * @var bool|RetailcrmApiClientV5|RetailcrmProxy $api + */ private $api; public function __construct($client) @@ -340,6 +343,48 @@ class RetailcrmReferences return $crmPaymentTypes; } + public function getSite() + { + try { + $response = $this->api->credentials(); + + if (!($response instanceof RetailcrmApiResponse) || !$response->isSuccessful() + || $response['siteAccess'] !== 'access_selective' + || count($response['sitesAvailable']) !== 1 + || !in_array('/api/reference/sites', $response['credentials']) + || !in_array('/api/reference/sites/{code}/edit', $response['credentials']) + ) { + RetailcrmLogger::writeCaller( + __METHOD__, + sprintf( + 'ShopID=%s: Error with CRM credentials: need an valid apiKey assigned to one certain site', + Shop::getContextShopID() + ) + ); + + return null; + } + + $response = $this->api->sitesList(); + + if ($response instanceof RetailcrmApiResponse && $response->isSuccessful() + && $response->offsetExists('sites') && $response['sites']) { + + return current($response['sites']); + } + } catch (Exception $e) { + RetailcrmLogger::writeCaller( + __METHOD__, + sprintf( + 'Error: %s', + $e->getMessage() + ) + ); + } + + return null; + } + public function getStores() { $storesShop = $this->getShopStores(); diff --git a/retailcrm/lib/RetailcrmTools.php b/retailcrm/lib/RetailcrmTools.php index b48e950..8a3b15e 100644 --- a/retailcrm/lib/RetailcrmTools.php +++ b/retailcrm/lib/RetailcrmTools.php @@ -479,6 +479,7 @@ class RetailcrmTools if (!empty($apiUrl) && !empty($apiKey)) { return new RetailcrmProxy($apiUrl, $apiKey, RetailcrmLogger::getLogFile()); } + RetailcrmLogger::writeCaller(__METHOD__, 'Set api key & url first'); return null; } @@ -758,17 +759,6 @@ class RetailcrmTools return true; } - /** - * Change shop in the context - * - * @param $id_shop - */ - public static function setShopContext($id_shop) - { - Shop::setContext(Shop::CONTEXT_SHOP, $id_shop); - Context::getContext()->shop = new Shop($id_shop); - } - /** * Call custom filters for the object * @@ -808,4 +798,47 @@ class RetailcrmTools return $object; } + + /** + * @param $name + * @return array|false|mixed + */ + public static function getConfigurationByName($name) + { + $idShop = Shop::getContextShopID(true); + $idShopGroup = Shop::getContextShopGroupID(true); + + $sql = 'SELECT * + FROM ' . _DB_PREFIX_ . 'configuration c + WHERE NAME = \'' . pSQL($name) . '\' + AND ( ' . + ($idShop ? 'c.id_shop = \'' . pSQL($idShop) . '\' OR ' : '') . + ($idShopGroup ? '( c.id_shop IS NULL AND c.id_shop_group = \'' . pSQL($idShopGroup) . '\') OR ' : '') . ' + (c.id_shop IS NULL AND c.id_shop_group IS NULL) + ) + ORDER BY c.id_shop DESC, c.id_shop_group DESC + LIMIT 1 + '; + + try { + return current(Db::getInstance()->executeS($sql)); + } catch (PrestaShopDatabaseException $e) { + return array(); + } + } + + /** + * @param $name + * @return DateTime|false + */ + public static function getConfigurationCreatedAtByName($name) + { + $config = self::getConfigurationByName($name); + + if (empty($config)) { + return false; + } + + return DateTime::createFromFormat('Y-m-d H:i:s', $config['date_add']); + } } diff --git a/retailcrm/lib/events/RetailcrmAbandonedCartsEvent.php b/retailcrm/lib/events/RetailcrmAbandonedCartsEvent.php index 0274129..adb5864 100644 --- a/retailcrm/lib/events/RetailcrmAbandonedCartsEvent.php +++ b/retailcrm/lib/events/RetailcrmAbandonedCartsEvent.php @@ -58,7 +58,7 @@ class RetailcrmAbandonedCartsEvent extends RetailcrmAbstractEvent implements Ret } foreach ($shops as $shop) { - RetailcrmTools::setShopContext(intval($shop['id_shop'])); + RetailcrmContextSwitcher::setShopContext(intval($shop['id_shop'])); $syncCartsActive = Configuration::get(RetailCRM::SYNC_CARTS_ACTIVE); @@ -71,8 +71,6 @@ class RetailcrmAbandonedCartsEvent extends RetailcrmAbstractEvent implements Ret $api = RetailcrmTools::getApiClient(); if (empty($api)) { - RetailcrmLogger::writeCaller(__METHOD__, 'Set API key & URL first'); - continue; } diff --git a/retailcrm/lib/events/RetailcrmAbstractEvent.php b/retailcrm/lib/events/RetailcrmAbstractEvent.php index 16058d9..4704855 100644 --- a/retailcrm/lib/events/RetailcrmAbstractEvent.php +++ b/retailcrm/lib/events/RetailcrmAbstractEvent.php @@ -41,6 +41,7 @@ require_once(dirname(__FILE__) . '/../RetailcrmPrestashopLoader.php'); abstract class RetailcrmAbstractEvent implements RetailcrmEventInterface { private $cliMode; + private $force; private $shopId; /** @@ -66,6 +67,14 @@ abstract class RetailcrmAbstractEvent implements RetailcrmEventInterface $this->cliMode = (bool)$mode; } + /** + * @param mixed $force + */ + public function setForce($force) + { + $this->force = (bool)$force; + } + /** * Sets context shop id. * @@ -84,8 +93,7 @@ abstract class RetailcrmAbstractEvent implements RetailcrmEventInterface */ protected function isRunning() { - return (strcmp(RetailcrmJobManager::getCurrentJob(), $this->getName() === 0)) - || (strcmp(RetailcrmCli::getCurrentJob(), $this->getName() === 0)); + return !$this->force && (RetailcrmJobManager::getCurrentJob() !== '' || RetailcrmCli::getCurrentJob() !== ''); } /** @@ -95,6 +103,10 @@ abstract class RetailcrmAbstractEvent implements RetailcrmEventInterface */ protected function setRunning() { + if($this->force) { + return true; + } + if ($this->cliMode) { return RetailcrmCli::setCurrentJob($this->getName()); } diff --git a/retailcrm/lib/events/RetailcrmEventInterface.php b/retailcrm/lib/events/RetailcrmEventInterface.php index 704c1bf..5679b52 100644 --- a/retailcrm/lib/events/RetailcrmEventInterface.php +++ b/retailcrm/lib/events/RetailcrmEventInterface.php @@ -60,6 +60,13 @@ interface RetailcrmEventInterface */ public function setCliMode($mode); + /** + * Sets force mode to true. Force mode here stands for any execution outside of JobManager & CLI context. + * + * @param bool $force + */ + public function setForce($force); + /** * Sets context shop id. * diff --git a/retailcrm/lib/events/RetailcrmExportEvent.php b/retailcrm/lib/events/RetailcrmExportEvent.php index df0ab32..f21e871 100644 --- a/retailcrm/lib/events/RetailcrmExportEvent.php +++ b/retailcrm/lib/events/RetailcrmExportEvent.php @@ -54,13 +54,11 @@ class RetailcrmExportEvent extends RetailcrmAbstractEvent implements RetailcrmEv $shops = $this->getShops(); foreach ($shops as $shop) { - RetailcrmTools::setShopContext(intval($shop['id_shop'])); + RetailcrmContextSwitcher::setShopContext(intval($shop['id_shop'])); $api = RetailcrmTools::getApiClient(); if (empty($api)) { - RetailcrmLogger::writeCaller(__METHOD__, 'Set API key & URL first'); - continue; } diff --git a/retailcrm/lib/events/RetailcrmIcmlEvent.php b/retailcrm/lib/events/RetailcrmIcmlEvent.php index 2bdc220..3355dc3 100644 --- a/retailcrm/lib/events/RetailcrmIcmlEvent.php +++ b/retailcrm/lib/events/RetailcrmIcmlEvent.php @@ -53,21 +53,13 @@ class RetailcrmIcmlEvent extends RetailcrmAbstractEvent implements RetailcrmEven $shops = $this->getShops(); - $isMultiStoreActive = Shop::isFeatureActive(); - foreach ($shops as $shop) { - RetailcrmTools::setShopContext(intval($shop['id_shop'])); + RetailcrmContextSwitcher::setShopContext(intval($shop['id_shop'])); $job = new RetailcrmCatalog(); $data = $job->getData(); - if ($isMultiStoreActive) { - $icmlFileName = 'simla_' . $shop['id_shop'] . '.xml'; - } else { - $icmlFileName = 'simla.xml'; - } - - $icml = new RetailcrmIcml($shop['name'], _PS_ROOT_DIR_ . '/' . $icmlFileName); + $icml = new RetailcrmIcml($shop['name'], RetailcrmCatalogHelper::getIcmlFilePath()); $icml->generate($data[0], $data[1]); } diff --git a/retailcrm/lib/events/RetailcrmIcmlUpdateUrlEvent.php b/retailcrm/lib/events/RetailcrmIcmlUpdateUrlEvent.php new file mode 100644 index 0000000..39ba1e2 --- /dev/null +++ b/retailcrm/lib/events/RetailcrmIcmlUpdateUrlEvent.php @@ -0,0 +1,95 @@ + + * @copyright 2020 DIGITAL RETAIL TECHNOLOGIES SL + * @license https://opensource.org/licenses/MIT The MIT License + * + * Don't forget to prefix your containers with your own identifier + * to avoid any conflicts with others containers. + */ + +require_once(dirname(__FILE__) . '/../RetailcrmPrestashopLoader.php'); + +class RetailcrmIcmlUpdateUrlEvent extends RetailcrmAbstractEvent implements RetailcrmEventInterface +{ + /** + * @inheritDoc + */ + public function execute() + { + if ($this->isRunning()) { + return false; + } + + $this->setRunning(); + + $shops = $this->getShops(); + + foreach ($shops as $shop) { + RetailcrmContextSwitcher::setShopContext(intval($shop['id_shop'])); + + if (!file_exists(RetailcrmCatalogHelper::getIcmlFilePath())) { + continue; + } + + $api = RetailcrmTools::getApiClient(); + if (empty($api)) { + continue; + } + + $reference = new RetailcrmReferences($api); + $site = $reference->getSite(); + if (empty($site)) { + continue; + } + + $newYmlUrl = RetailcrmCatalogHelper::getIcmlFileLink(); + $siteCode = $site['code']; + + if ($newYmlUrl !== $site['ymlUrl']) { + $api->sitesEdit([ + 'code' => $siteCode, + 'ymlUrl' => $newYmlUrl, + ]); + } + } + + return true; + } + + /** + * @inheritDoc + */ + public function getName() + { + return 'RetailcrmIcmlUpdateUrlEvent'; + } +} diff --git a/retailcrm/lib/events/RetailcrmInventoriesEvent.php b/retailcrm/lib/events/RetailcrmInventoriesEvent.php index 58c2011..00b6676 100644 --- a/retailcrm/lib/events/RetailcrmInventoriesEvent.php +++ b/retailcrm/lib/events/RetailcrmInventoriesEvent.php @@ -54,7 +54,7 @@ class RetailcrmInventoriesEvent extends RetailcrmAbstractEvent implements Retail $shops = $this->getShops(); foreach ($shops as $shop) { - RetailcrmTools::setShopContext(intval($shop['id_shop'])); + RetailcrmContextSwitcher::setShopContext(intval($shop['id_shop'])); if (!Configuration::get(RetailCRM::ENABLE_BALANCES_RECEIVING)) { RetailcrmLogger::writeDebug( diff --git a/retailcrm/lib/events/RetailcrmMissingEvent.php b/retailcrm/lib/events/RetailcrmMissingEvent.php index 8fe5f62..93d1e06 100644 --- a/retailcrm/lib/events/RetailcrmMissingEvent.php +++ b/retailcrm/lib/events/RetailcrmMissingEvent.php @@ -61,7 +61,7 @@ class RetailcrmMissingEvent extends RetailcrmAbstractEvent implements RetailcrmE } $orderInstance = new Order($options['o']); - RetailcrmTools::setShopContext($orderInstance->id_shop); + RetailcrmContextSwitcher::setShopContext($orderInstance->id_shop); $apiUrl = Configuration::get(RetailCRM::API_URL); $apiKey = Configuration::get(RetailCRM::API_KEY); diff --git a/retailcrm/lib/events/RetailcrmSyncEvent.php b/retailcrm/lib/events/RetailcrmSyncEvent.php index c2bcee7..c394ee0 100644 --- a/retailcrm/lib/events/RetailcrmSyncEvent.php +++ b/retailcrm/lib/events/RetailcrmSyncEvent.php @@ -54,7 +54,7 @@ class RetailcrmSyncEvent extends RetailcrmAbstractEvent implements RetailcrmEven $shops = $this->getShops(); foreach ($shops as $shop) { - RetailcrmTools::setShopContext(intval($shop['id_shop'])); + RetailcrmContextSwitcher::setShopContext(intval($shop['id_shop'])); if (!Configuration::get(RetailCRM::ENABLE_HISTORY_UPLOADS)) { RetailcrmLogger::writeDebug( diff --git a/retailcrm/lib/events/RetailcrmUpdateSinceIdEvent.php b/retailcrm/lib/events/RetailcrmUpdateSinceIdEvent.php index e75b750..740892d 100644 --- a/retailcrm/lib/events/RetailcrmUpdateSinceIdEvent.php +++ b/retailcrm/lib/events/RetailcrmUpdateSinceIdEvent.php @@ -54,13 +54,11 @@ class RetailcrmUpdateSinceIdEvent extends RetailcrmAbstractEvent implements Reta $shops = $this->getShops(); foreach ($shops as $shop) { - RetailcrmTools::setShopContext(intval($shop['id_shop'])); + RetailcrmContextSwitcher::setShopContext(intval($shop['id_shop'])); $api = RetailcrmTools::getApiClient(); if (empty($api)) { - RetailcrmLogger::writeCaller(__METHOD__, 'Set api key & url first'); - continue; } diff --git a/retailcrm/lib/templates/RetailcrmSettingsTemplate.php b/retailcrm/lib/templates/RetailcrmSettingsTemplate.php index 755767a..02c0475 100644 --- a/retailcrm/lib/templates/RetailcrmSettingsTemplate.php +++ b/retailcrm/lib/templates/RetailcrmSettingsTemplate.php @@ -83,6 +83,8 @@ class RetailcrmSettingsTemplate extends RetailcrmAbstractTemplate $params['currentJob'] = Configuration::get(RetailcrmJobManager::CURRENT_TASK); $params['currentJobCli'] = Configuration::get(RetailcrmCli::CURRENT_TASK_CLI); $params['retailcrmLogsInfo'] = RetailcrmLogger::getLogFilesInfo(); + $params['catalogInfoMultistore'] = RetailcrmCatalogHelper::getIcmlFileInfoMultistore(); + $params['shopsInfo'] = RetailcrmContextSwitcher::getShops(); $params['errorTabs'] = $this->module->validateStoredSettings(); } diff --git a/retailcrm/retailcrm.php b/retailcrm/retailcrm.php index 6d2b24c..2444ddf 100644 --- a/retailcrm/retailcrm.php +++ b/retailcrm/retailcrm.php @@ -63,6 +63,7 @@ class RetailCRM extends Module const SYNC_CARTS_STATUS = 'RETAILCRM_API_SYNCHRONIZED_CART_STATUS'; const SYNC_CARTS_DELAY = 'RETAILCRM_API_SYNCHRONIZED_CART_DELAY'; const UPLOAD_ORDERS = 'RETAILCRM_UPLOAD_ORDERS_ID'; + const RUN_JOB = 'RETAILCRM_RUN_JOB'; const EXPORT_ORDERS = 'RETAILCRM_EXPORT_ORDERS_STEP'; const EXPORT_CUSTOMERS = 'RETAILCRM_EXPORT_CUSTOMERS_STEP'; const UPDATE_SINCE_ID = 'RETAILCRM_UPDATE_SINCE_ID'; @@ -81,6 +82,7 @@ class RetailCRM extends Module const JOBS_NAMES = [ 'RetailcrmAbandonedCartsEvent' => 'Abandoned Carts', 'RetailcrmIcmlEvent' => 'Icml generation', + 'RetailcrmIcmlUpdateUrlEvent' => 'Icml update URL', 'RetailcrmSyncEvent' => 'History synchronization', 'RetailcrmInventoriesEvent' => 'Inventories uploads', 'RetailcrmClearLogsEvent' => 'Clearing logs' @@ -245,6 +247,7 @@ class RetailCRM extends Module Configuration::deleteByName('RETAILCRM_LAST_CUSTOMERS_SYNC') && Configuration::deleteByName(RetailcrmJobManager::LAST_RUN_NAME) && Configuration::deleteByName(RetailcrmJobManager::LAST_RUN_DETAIL_NAME) && + Configuration::deleteByName(RetailcrmCatalogHelper::ICML_INFO_NAME) && Configuration::deleteByName(RetailcrmJobManager::IN_PROGRESS_NAME) && Configuration::deleteByName(RetailcrmJobManager::CURRENT_TASK) && Configuration::deleteByName(RetailcrmCli::CURRENT_TASK_CLI) && @@ -276,6 +279,8 @@ class RetailCRM extends Module $token = Configuration::get(static::API_KEY); if (Tools::isSubmit('submit' . $this->name)) { + // todo all those vars & ifs to one $command var and check in switch + $jobName = (string)(Tools::getValue(static::RUN_JOB)); $ordersIds = (string)(Tools::getValue(static::UPLOAD_ORDERS)); $exportOrders = (int)(Tools::getValue(static::EXPORT_ORDERS)); $exportCustomers = (int)(Tools::getValue(static::EXPORT_CUSTOMERS)); @@ -285,6 +290,8 @@ class RetailCRM extends Module if (!empty($ordersIds)) { $output .= $this->uploadOrders(RetailcrmTools::partitionId($ordersIds)); + } elseif (!empty($jobName)) { + $this->runJobMultistore($jobName); } elseif (!empty($exportOrders)) { return $this->export($exportOrders); } elseif (!empty($exportCustomers)) { @@ -401,6 +408,43 @@ class RetailCRM extends Module } } + /** + * @param string $jobName + * @return string + */ + public function runJob($jobName) + { + $jobNameFront = (empty(static::JOBS_NAMES[$jobName]) ? $jobName : static::JOBS_NAMES[$jobName]); + + try { + if (RetailcrmJobManager::execManualJob($jobName)) { + return $this->displayConfirmation(sprintf( + '%s %s', + $this->l($jobNameFront), + $this->l('was completed successfully') + )); + } else { + return $this->displayError(sprintf( + '%s %s', + $this->l($jobNameFront), + $this->l('was not executed') + )); + } + } catch (Exception $e) { + return $this->displayError(sprintf( + '%s %s: %s', + $this->l($jobNameFront), + $this->l('was completed with errors'), + $e->getMessage() + )); + } + } + + public function runJobMultistore($jobName) + { + RetailcrmContextSwitcher::runInContext(array($this, 'runJob'), array($jobName)); + } + /** * @param int $step * @param string $entity @@ -420,7 +464,6 @@ class RetailCRM extends Module $api = RetailcrmTools::getApiClient(); if (empty($api)) { - RetailcrmLogger::writeCaller(__METHOD__, 'Set API key & URL first'); return RetailcrmJsonResponse::invalidResponse('Set API key & URL first'); } @@ -453,7 +496,6 @@ class RetailCRM extends Module $api = RetailcrmTools::getApiClient(); if (empty($api)) { - RetailcrmLogger::writeCaller(__METHOD__, 'Set API key & URL first'); return RetailcrmJsonResponse::invalidResponse('Set API key & URL first'); } @@ -1124,6 +1166,10 @@ class RetailCRM extends Module } } + if (!$this->validateCatalogMultistore()) { + $output[] = 'catalog'; + } + return $output; } @@ -1144,6 +1190,49 @@ class RetailCRM extends Module return true; } + /** + * Catalog info validator + * + * @return bool + */ + public function validateCatalog() + { + $icmlInfo = RetailcrmCatalogHelper::getIcmlFileInfo(); + + if (!$icmlInfo || !isset($icmlInfo['lastGenerated'])) { + $urlConfiguredAt = RetailcrmTools::getConfigurationCreatedAtByName(self::API_KEY); + + if ($urlConfiguredAt instanceof DateTime) { + $now = new DateTime(); + /** @var DateInterval $diff */ + $diff = $urlConfiguredAt->diff($now); + + if (($diff->days * 24 + $diff->h) > 4) { + return false; + } + } + } elseif ($icmlInfo['isOutdated'] || !$icmlInfo['isUrlActual']) { + return false; + } + + return true; + } + + /** + * Catalog info validator for multistore + * + * @return bool + */ + private function validateCatalogMultistore() + { + $results = RetailcrmContextSwitcher::runInContext(array($this, 'validateCatalog')); + $results = array_filter($results, function ($item) { + return !$item; + }); + + return empty($results); + } + /** * Settings form validator * @@ -1298,6 +1387,7 @@ class RetailCRM extends Module 'synchronizedCartStatusName' => static::SYNC_CARTS_STATUS, 'synchronizedCartDelayName' => static::SYNC_CARTS_DELAY, 'uploadOrders' => static::UPLOAD_ORDERS, + 'runJobName' => static::RUN_JOB, 'consultantScriptName' => static::CONSULTANT_SCRIPT, 'enableCorporateName' => static::ENABLE_CORPORATE_CLIENTS, 'enableHistoryUploadsName' => static::ENABLE_HISTORY_UPLOADS, diff --git a/retailcrm/translations/es.php b/retailcrm/translations/es.php index e032e68..494cacf 100644 --- a/retailcrm/translations/es.php +++ b/retailcrm/translations/es.php @@ -8,6 +8,9 @@ $_MODULE['<{retailcrm}prestashop>retailcrm_876f23178c29dc2552c0b48bf23cd9bd'] = $_MODULE['<{retailcrm}prestashop>retailcrm_6bd461d1fc51b3294c6513cecc24758d'] = 'Los pedidos han sido cargados con éxito'; $_MODULE['<{retailcrm}prestashop>retailcrm_9a7fc06b4b2359f1f26f75fbbe27a3e8'] = 'No todos los pedidos se han cargado con existo'; $_MODULE['<{retailcrm}prestashop>retailcrm_e7244a5e543ba692ebc495aee934ee9b'] = 'Orden omitida por inexistencia: %s'; +$_MODULE['<{retailcrm}prestashop>retailcrm_474b50f70e008454f1f2bf0d63f5262a'] = 'se completó con éxito'; +$_MODULE['<{retailcrm}prestashop>retailcrm_7f3df1b66ce2d61ae3d31c97ac08b065'] = 'no fue ejecutado'; +$_MODULE['<{retailcrm}prestashop>retailcrm_8bc2706bb353ba02b05135127122e406'] = 'se completó con errores '; $_MODULE['<{retailcrm}prestashop>retailcrm_b9b2d9f66d0112f3aae7dbdbd4e22a43'] = 'La dirección del CRM es incorrecta o está vacía'; $_MODULE['<{retailcrm}prestashop>retailcrm_942010ef43f3fec28741f62a0d9ff29c'] = 'La clave CRM es incorrecta o está vacía'; $_MODULE['<{retailcrm}prestashop>retailcrm_1bd340aeb42a5ee0318784c2cffed8a9'] = 'La versión seleccionada de la API no está disponible'; @@ -23,6 +26,76 @@ $_MODULE['<{retailcrm}prestashop>retailcrm_d5bb7c2cb1565fb1568924b01847b330'] = $_MODULE['<{retailcrm}prestashop>retailcrm_9d3095e54f694bb41ef4a3e62ed90e7a'] = 'Tras 30 minutos'; $_MODULE['<{retailcrm}prestashop>retailcrm_dfb403fd86851c7d9f97706dff5a2327'] = 'Tras 45 minutos'; $_MODULE['<{retailcrm}prestashop>retailcrm_4b5e6470d5d85448fcd89c828352d25e'] = 'Tras 1 hora'; +$_MODULE['<{retailcrm}prestashop>settings_2b65c584b7b4d7bd19d36f7d2b690c6a'] = 'Catálogo Icml'; +$_MODULE['<{retailcrm}prestashop>settings_c2cc7082a89c1ad6631a2f66af5f00c0'] = 'Conexión'; +$_MODULE['<{retailcrm}prestashop>settings_065ab3a28ca4f16f55f103adc7d0226f'] = 'Los métodos del envío'; +$_MODULE['<{retailcrm}prestashop>settings_33af8066d3c83110d4bd897f687cedd2'] = 'Los estados de pedidos'; +$_MODULE['<{retailcrm}prestashop>settings_bab959acc06bb03897b294fbb892be6b'] = 'Los métodos de pago'; +$_MODULE['<{retailcrm}prestashop>settings_7a1920d61156abc05a60135aefe8bc67'] = 'Por defecto'; +$_MODULE['<{retailcrm}prestashop>settings_20cacc01d0de8bc6e9c9846f477e886b'] = 'Subir pedidos'; +$_MODULE['<{retailcrm}prestashop>settings_6bcde6286f8d1b76063ee52104a240cf'] = 'Carritos abandonados'; +$_MODULE['<{retailcrm}prestashop>settings_52a13123e134b8b72b6299bc14a36aad'] = 'Daemon Collector'; +$_MODULE['<{retailcrm}prestashop>settings_71098155ccc0a0d6e0b501fbee37e7a9'] = 'LiveChat'; +$_MODULE['<{retailcrm}prestashop>settings_9b6545e4cea9b4ad4979d41bb9170e2b'] = 'Avanzado'; +$_MODULE['<{retailcrm}prestashop>settings_061b368c43f85d3fe2c7ccc842883a40'] = 'La configuración de la conexión'; +$_MODULE['<{retailcrm}prestashop>settings_22a65bd0ef1919aa4e6dee849a7a2925'] = 'Simla.com URL'; +$_MODULE['<{retailcrm}prestashop>settings_656a6828d7ef1bb791e42087c4b5ee6e'] = 'API key'; +$_MODULE['<{retailcrm}prestashop>settings_8ffa3281a35a0d80fef2cac0fa680523'] = 'Habilitar la carga del historial'; +$_MODULE['<{retailcrm}prestashop>settings_65dd9f6e8bf4eaf54c3dc96f011dade1'] = 'Recibir las existencias del Simla.com'; +$_MODULE['<{retailcrm}prestashop>settings_f8d7c52aa84f358caedb96fda86809da'] = 'Permitir el soporte a clientes corporativos'; +$_MODULE['<{retailcrm}prestashop>settings_6c3c1845e109a9ef67378effea0c0503'] = 'Activar solo si está habilitada la opción \"Clientes corporativos\" en Simla.com'; +$_MODULE['<{retailcrm}prestashop>settings_917afe348e09163269225a89a825e634'] = 'Sincronización de carritos de compradores'; +$_MODULE['<{retailcrm}prestashop>settings_d8e002d770b6f98af7b7ae9a0e5acfe9'] = 'Crear pedidos para carritos abandonados de compradores'; +$_MODULE['<{retailcrm}prestashop>settings_35b5a9139a54caeb925556ceb2c38086'] = 'Estado del pedido para carritos abandonados de compradores'; +$_MODULE['<{retailcrm}prestashop>settings_9b9cf9f8778f69b4c6cf37e66f886be8'] = 'Elige el estado'; +$_MODULE['<{retailcrm}prestashop>settings_a0d135501a738c3c98de385dc28cda61'] = 'Cargar carritos abandonados'; +$_MODULE['<{retailcrm}prestashop>settings_27096e1243f98e1b3300f57ff1c76456'] = 'Elige la demora'; +$_MODULE['<{retailcrm}prestashop>settings_1f8246b1e6ada8897902eff8d8cd8f35'] = 'está desactualizado'; +$_MODULE['<{retailcrm}prestashop>settings_4a15f35e8d386dd1d96faa83c1e44a22'] = 'Actualizar URL'; +$_MODULE['<{retailcrm}prestashop>settings_5b55e5aeb08a372d36f7e4b7b35d1cd1'] = 'URL del catalogo Icml en Prestashop y en %s no coinciden'; +$_MODULE['<{retailcrm}prestashop>settings_06aa6fa8bdc2078e7e1bd903e70c8f6a'] = 'esta conectado'; +$_MODULE['<{retailcrm}prestashop>settings_7892a1894478824c07b62af2df839291'] = 'Más de 7 días'; +$_MODULE['<{retailcrm}prestashop>settings_8277e0910d750195b448797616e091ad'] = 'd'; +$_MODULE['<{retailcrm}prestashop>settings_2510c39011c5be704182423e3a695e91'] = 'h'; +$_MODULE['<{retailcrm}prestashop>settings_d8bd79cc131920d5de426f914d17405a'] = 'min'; +$_MODULE['<{retailcrm}prestashop>settings_3baa7e02e09dba2ba2a188a7c9a055cb'] = 'pasado desde la última ejecución'; +$_MODULE['<{retailcrm}prestashop>settings_068f80c7519d0528fb08e82137a72131'] = 'Productos'; +$_MODULE['<{retailcrm}prestashop>settings_9461bed8b71377318436990e57106729'] = 'Ofertas'; +$_MODULE['<{retailcrm}prestashop>settings_64ef97a8fe9db8b672287a53c5d836f2'] = 'aún no se generó'; +$_MODULE['<{retailcrm}prestashop>settings_79c07dbacf542d283944685e1538a1bb'] = 'Presione el botón de abajo para generar el %s'; +$_MODULE['<{retailcrm}prestashop>settings_cc84d5b49b62c0959f1af64bffaec3b7'] = 'Generar ahora'; +$_MODULE['<{retailcrm}prestashop>settings_4e537de8dd108eafec4c37603c8ab7fb'] = 'Administrar tipos de entrega'; +$_MODULE['<{retailcrm}prestashop>settings_5b385947acf10ac0c5521161ce96aaa7'] = 'Elige la entrega'; +$_MODULE['<{retailcrm}prestashop>settings_c0fd6d31d096a5845f1d1abb4c132b7d'] = 'Administrar estados de pedidos'; +$_MODULE['<{retailcrm}prestashop>settings_dd53d9b3603b3279b25c74f6f3f189a4'] = 'Administrar tipos de pago'; +$_MODULE['<{retailcrm}prestashop>settings_7dcc1208fa03381346955c6732d9ea85'] = 'Elige el tipo'; +$_MODULE['<{retailcrm}prestashop>settings_6f1f9a3e435963417d08849fbef139c1'] = 'Ingrese los ID de los pedidos para cargar en Simla.com, divididos por una coma. También puede especificar rangos, como \"1-10\". Se permite subir hasta 10 pedidos a la vez.'; +$_MODULE['<{retailcrm}prestashop>settings_acfa058ec9e6e4745eddc0cae3f0f881'] = 'Identificador del pedido'; +$_MODULE['<{retailcrm}prestashop>settings_91412465ea9169dfd901dd5e7c96dd99'] = 'Subir'; +$_MODULE['<{retailcrm}prestashop>settings_f4af7f6987dfee28741ce77ff2d09d46'] = 'Exportar pedidos y clientes'; +$_MODULE['<{retailcrm}prestashop>settings_418faff1c9df0d297ff586ac3230be97'] = 'Puede exportar todos los pedidos y clientes de CMS a Simla.com presionando el botón \"Exportar\". Este proceso puede llevar mucho tiempo y es necesario que mantenga la pestaña abierta hasta que termine.'; +$_MODULE['<{retailcrm}prestashop>settings_7442e29d7d53e549b78d93c46b8cdcfc'] = 'Pedidos'; +$_MODULE['<{retailcrm}prestashop>settings_e6d0e1c8fc6a4fcf47869df87e04cd88'] = 'Clientes'; +$_MODULE['<{retailcrm}prestashop>settings_f8f36c02fa6f370808135c66cfc788aa'] = 'Clientes sin pedidos'; +$_MODULE['<{retailcrm}prestashop>settings_0095a9fa74d1713e43e370a7d7846224'] = 'Exportar'; +$_MODULE['<{retailcrm}prestashop>settings_4d3d769b812b6faa6b76e1a8abaece2d'] = 'Active'; +$_MODULE['<{retailcrm}prestashop>settings_f75d8fa5c89351544d372cf90528ccf2'] = 'Clave de la página web'; +$_MODULE['<{retailcrm}prestashop>settings_c9cc8cce247e49bae79f15173ce97354'] = 'Guardar'; +$_MODULE['<{retailcrm}prestashop>settings_4f18e3f1c9941a6ec5a38bc716c521b4'] = 'Código que necesita insertar en la web'; +$_MODULE['<{retailcrm}prestashop>settings_ec3028a12402ab7f43962a6f3a667b6e'] = 'Modo de depuración'; +$_MODULE['<{retailcrm}prestashop>settings_9082f68bc90113d8950e4ed7fe8fa0a4'] = 'Administrador de tareas'; +$_MODULE['<{retailcrm}prestashop>settings_9194de58ce560c095f02cefc1c1c61e6'] = 'Nombre de la tarea'; +$_MODULE['<{retailcrm}prestashop>settings_05a3a24340b7b9cc8d4e08f0ef4f4dd9'] = 'Última ejecución'; +$_MODULE['<{retailcrm}prestashop>settings_ec53a8c4f07baed5d8825072c89799be'] = 'Estado'; +$_MODULE['<{retailcrm}prestashop>settings_0be8406951cdfda82f00f79328cf4efc'] = 'Comentario'; +$_MODULE['<{retailcrm}prestashop>settings_fe5b6cd4d7a31615bbec8d1505089d87'] = 'StackTrace'; +$_MODULE['<{retailcrm}prestashop>settings_b2d37ae1cedf42ff874289b721860af2'] = 'Registros'; +$_MODULE['<{retailcrm}prestashop>settings_34082694d21dbdcfc31e6e32d9fb2b9f'] = 'Nombre del archivo'; +$_MODULE['<{retailcrm}prestashop>settings_a4b7f1864cfdb47cd05b54eb10337506'] = 'Fecha de modificación'; +$_MODULE['<{retailcrm}prestashop>settings_6f6cb72d544962fa333e2e34ce64f719'] = 'Tamaño'; +$_MODULE['<{retailcrm}prestashop>settings_06df33001c1d7187fdd81ea1f5b277aa'] = 'Comportamiento'; +$_MODULE['<{retailcrm}prestashop>settings_801ab24683a4a8c433c6eb40c48bcd9d'] = 'Descargar'; +$_MODULE['<{retailcrm}prestashop>settings_61b0ada67b7f40bf3d40dcc88ae4f3e6'] = 'Descargar todo'; $_MODULE['<{retailcrm}prestashop>index_dd259436b3f29f0ba1778d220b343ec9'] = 'Simla.com es un servicio para tiendas online, el cual ayuda a dejar de perder pedidos y así mejorar las ganancias de tu comercio online en todas las etapas del embudo de ventas.'; $_MODULE['<{retailcrm}prestashop>index_c7476a92e20715b855d72b1786a71017'] = 'Tengo una cuenta en Simla.com'; $_MODULE['<{retailcrm}prestashop>index_e81c4e4f2b7b93b481e13a8553c2ae1b'] = 'o'; @@ -79,58 +152,3 @@ $_MODULE['<{retailcrm}prestashop>index_95428f32e5c696cf71baccb776bc5c15'] = 'Tra $_MODULE['<{retailcrm}prestashop>index_e7f9e382dc50889098cbe56f2554c77b'] = 'Tarjeta bancaria'; $_MODULE['<{retailcrm}prestashop>index_7088f1d1d9c91d8b75e9882ffd78540c'] = 'Datos de contacto'; $_MODULE['<{retailcrm}prestashop>index_50f158e2507321f1a5b6f8fb9e350818'] = 'Escríbenos en caso de preguntas o dudas'; -$_MODULE['<{retailcrm}prestashop>settings_c2cc7082a89c1ad6631a2f66af5f00c0'] = 'Conexión'; -$_MODULE['<{retailcrm}prestashop>settings_065ab3a28ca4f16f55f103adc7d0226f'] = 'Los métodos del envío'; -$_MODULE['<{retailcrm}prestashop>settings_33af8066d3c83110d4bd897f687cedd2'] = 'Los estados de pedidos'; -$_MODULE['<{retailcrm}prestashop>settings_bab959acc06bb03897b294fbb892be6b'] = 'Los métodos de pago'; -$_MODULE['<{retailcrm}prestashop>settings_7a1920d61156abc05a60135aefe8bc67'] = 'Por defecto'; -$_MODULE['<{retailcrm}prestashop>settings_20cacc01d0de8bc6e9c9846f477e886b'] = 'Subir pedidos'; -$_MODULE['<{retailcrm}prestashop>settings_6bcde6286f8d1b76063ee52104a240cf'] = 'Carritos abandonados'; -$_MODULE['<{retailcrm}prestashop>settings_52a13123e134b8b72b6299bc14a36aad'] = 'Daemon Collector'; -$_MODULE['<{retailcrm}prestashop>settings_71098155ccc0a0d6e0b501fbee37e7a9'] = 'LiveChat'; -$_MODULE['<{retailcrm}prestashop>settings_9b6545e4cea9b4ad4979d41bb9170e2b'] = 'Avanzado'; -$_MODULE['<{retailcrm}prestashop>settings_061b368c43f85d3fe2c7ccc842883a40'] = 'La configuración de la conexión'; -$_MODULE['<{retailcrm}prestashop>settings_22a65bd0ef1919aa4e6dee849a7a2925'] = 'Simla.com URL'; -$_MODULE['<{retailcrm}prestashop>settings_656a6828d7ef1bb791e42087c4b5ee6e'] = 'API key'; -$_MODULE['<{retailcrm}prestashop>settings_8ffa3281a35a0d80fef2cac0fa680523'] = 'Habilitar la carga del historial'; -$_MODULE['<{retailcrm}prestashop>settings_65dd9f6e8bf4eaf54c3dc96f011dade1'] = 'Recibir las existencias del Simla.com'; -$_MODULE['<{retailcrm}prestashop>settings_f8d7c52aa84f358caedb96fda86809da'] = 'Permitir el soporte a clientes corporativos'; -$_MODULE['<{retailcrm}prestashop>settings_6c3c1845e109a9ef67378effea0c0503'] = 'Activar solo si está habilitada la opción \"Clientes corporativos\" en Simla.com'; -$_MODULE['<{retailcrm}prestashop>settings_917afe348e09163269225a89a825e634'] = 'Sincronización de carritos de compradores'; -$_MODULE['<{retailcrm}prestashop>settings_d8e002d770b6f98af7b7ae9a0e5acfe9'] = 'Crear pedidos para carritos abandonados de compradores'; -$_MODULE['<{retailcrm}prestashop>settings_35b5a9139a54caeb925556ceb2c38086'] = 'Estado del pedido para carritos abandonados de compradores'; -$_MODULE['<{retailcrm}prestashop>settings_9b9cf9f8778f69b4c6cf37e66f886be8'] = 'Elige el estado'; -$_MODULE['<{retailcrm}prestashop>settings_a0d135501a738c3c98de385dc28cda61'] = 'Cargar carritos abandonados'; -$_MODULE['<{retailcrm}prestashop>settings_27096e1243f98e1b3300f57ff1c76456'] = 'Elige la demora'; -$_MODULE['<{retailcrm}prestashop>settings_4e537de8dd108eafec4c37603c8ab7fb'] = 'Administrar tipos de entrega'; -$_MODULE['<{retailcrm}prestashop>settings_5b385947acf10ac0c5521161ce96aaa7'] = 'Elige la entrega'; -$_MODULE['<{retailcrm}prestashop>settings_c0fd6d31d096a5845f1d1abb4c132b7d'] = 'Administrar estados de pedidos'; -$_MODULE['<{retailcrm}prestashop>settings_dd53d9b3603b3279b25c74f6f3f189a4'] = 'Administrar tipos de pago'; -$_MODULE['<{retailcrm}prestashop>settings_7dcc1208fa03381346955c6732d9ea85'] = 'Elige el tipo'; -$_MODULE['<{retailcrm}prestashop>settings_6f1f9a3e435963417d08849fbef139c1'] = 'Ingrese los ID de los pedidos para cargar en Simla.com, divididos por una coma. También puede especificar rangos, como \"1-10\". Se permite subir hasta 10 pedidos a la vez.'; -$_MODULE['<{retailcrm}prestashop>settings_acfa058ec9e6e4745eddc0cae3f0f881'] = 'Identificador del pedido'; -$_MODULE['<{retailcrm}prestashop>settings_91412465ea9169dfd901dd5e7c96dd99'] = 'Subir'; -$_MODULE['<{retailcrm}prestashop>settings_f4af7f6987dfee28741ce77ff2d09d46'] = 'Exportar pedidos y clientes'; -$_MODULE['<{retailcrm}prestashop>settings_418faff1c9df0d297ff586ac3230be97'] = 'Puede exportar todos los pedidos y clientes de CMS a Simla.com presionando el botón \"Exportar\". Este proceso puede llevar mucho tiempo y es necesario que mantenga la pestaña abierta hasta que termine.'; -$_MODULE['<{retailcrm}prestashop>settings_7442e29d7d53e549b78d93c46b8cdcfc'] = 'Pedidos'; -$_MODULE['<{retailcrm}prestashop>settings_e6d0e1c8fc6a4fcf47869df87e04cd88'] = 'Clientes'; -$_MODULE['<{retailcrm}prestashop>settings_f8f36c02fa6f370808135c66cfc788aa'] = 'Clientes sin pedidos'; -$_MODULE['<{retailcrm}prestashop>settings_0095a9fa74d1713e43e370a7d7846224'] = 'Exportar'; -$_MODULE['<{retailcrm}prestashop>settings_4d3d769b812b6faa6b76e1a8abaece2d'] = 'Active'; -$_MODULE['<{retailcrm}prestashop>settings_f75d8fa5c89351544d372cf90528ccf2'] = 'Clave de la página web'; -$_MODULE['<{retailcrm}prestashop>settings_c9cc8cce247e49bae79f15173ce97354'] = 'Guardar'; -$_MODULE['<{retailcrm}prestashop>settings_4f18e3f1c9941a6ec5a38bc716c521b4'] = 'Código que necesita insertar en la web'; -$_MODULE['<{retailcrm}prestashop>settings_ec3028a12402ab7f43962a6f3a667b6e'] = 'Modo de depuración'; -$_MODULE['<{retailcrm}prestashop>settings_9082f68bc90113d8950e4ed7fe8fa0a4'] = 'Administrador de tareas'; -$_MODULE['<{retailcrm}prestashop>settings_9194de58ce560c095f02cefc1c1c61e6'] = 'Nombre de la tarea'; -$_MODULE['<{retailcrm}prestashop>settings_05a3a24340b7b9cc8d4e08f0ef4f4dd9'] = 'Última ejecución'; -$_MODULE['<{retailcrm}prestashop>settings_ec53a8c4f07baed5d8825072c89799be'] = 'Estado'; -$_MODULE['<{retailcrm}prestashop>settings_0be8406951cdfda82f00f79328cf4efc'] = 'Comentario'; -$_MODULE['<{retailcrm}prestashop>settings_fe5b6cd4d7a31615bbec8d1505089d87'] = 'StackTrace'; -$_MODULE['<{retailcrm}prestashop>settings_b2d37ae1cedf42ff874289b721860af2'] = 'Registros'; -$_MODULE['<{retailcrm}prestashop>settings_34082694d21dbdcfc31e6e32d9fb2b9f'] = 'Nombre del archivo'; -$_MODULE['<{retailcrm}prestashop>settings_a4b7f1864cfdb47cd05b54eb10337506'] = 'Fecha de modificación'; -$_MODULE['<{retailcrm}prestashop>settings_6f6cb72d544962fa333e2e34ce64f719'] = 'Tamaño'; -$_MODULE['<{retailcrm}prestashop>settings_06df33001c1d7187fdd81ea1f5b277aa'] = 'Comportamiento'; -$_MODULE['<{retailcrm}prestashop>settings_801ab24683a4a8c433c6eb40c48bcd9d'] = 'Descargar'; -$_MODULE['<{retailcrm}prestashop>settings_61b0ada67b7f40bf3d40dcc88ae4f3e6'] = 'Descargar todo'; diff --git a/retailcrm/translations/ru.php b/retailcrm/translations/ru.php index 3e167f5..d90cc23 100644 --- a/retailcrm/translations/ru.php +++ b/retailcrm/translations/ru.php @@ -8,6 +8,9 @@ $_MODULE['<{retailcrm}prestashop>retailcrm_876f23178c29dc2552c0b48bf23cd9bd'] = $_MODULE['<{retailcrm}prestashop>retailcrm_6bd461d1fc51b3294c6513cecc24758d'] = 'Все заказы успешно загружены'; $_MODULE['<{retailcrm}prestashop>retailcrm_9a7fc06b4b2359f1f26f75fbbe27a3e8'] = 'Не все заказы загружены успешно'; $_MODULE['<{retailcrm}prestashop>retailcrm_e7244a5e543ba692ebc495aee934ee9b'] = 'Заказы не найдены и пропущены: %s'; +$_MODULE['<{retailcrm}prestashop>retailcrm_474b50f70e008454f1f2bf0d63f5262a'] = 'завершена успешно'; +$_MODULE['<{retailcrm}prestashop>retailcrm_7f3df1b66ce2d61ae3d31c97ac08b065'] = 'не была запущена'; +$_MODULE['<{retailcrm}prestashop>retailcrm_8bc2706bb353ba02b05135127122e406'] = 'завершена с ошибками'; $_MODULE['<{retailcrm}prestashop>retailcrm_b9b2d9f66d0112f3aae7dbdbd4e22a43'] = 'Некорректный или пустой адрес CRM'; $_MODULE['<{retailcrm}prestashop>retailcrm_942010ef43f3fec28741f62a0d9ff29c'] = 'Некорректный или пустой ключ CRM'; $_MODULE['<{retailcrm}prestashop>retailcrm_1bd340aeb42a5ee0318784c2cffed8a9'] = 'Выбранная версия API недоступна'; @@ -23,6 +26,76 @@ $_MODULE['<{retailcrm}prestashop>retailcrm_d5bb7c2cb1565fb1568924b01847b330'] = $_MODULE['<{retailcrm}prestashop>retailcrm_9d3095e54f694bb41ef4a3e62ed90e7a'] = 'Через 30 минут'; $_MODULE['<{retailcrm}prestashop>retailcrm_dfb403fd86851c7d9f97706dff5a2327'] = 'Через 45 минут'; $_MODULE['<{retailcrm}prestashop>retailcrm_4b5e6470d5d85448fcd89c828352d25e'] = 'Через 1 час'; +$_MODULE['<{retailcrm}prestashop>settings_2b65c584b7b4d7bd19d36f7d2b690c6a'] = 'Каталог Icml'; +$_MODULE['<{retailcrm}prestashop>settings_c2cc7082a89c1ad6631a2f66af5f00c0'] = 'Соединение'; +$_MODULE['<{retailcrm}prestashop>settings_065ab3a28ca4f16f55f103adc7d0226f'] = 'Способы доставки'; +$_MODULE['<{retailcrm}prestashop>settings_33af8066d3c83110d4bd897f687cedd2'] = 'Статусы заказов'; +$_MODULE['<{retailcrm}prestashop>settings_bab959acc06bb03897b294fbb892be6b'] = 'Способы оплаты'; +$_MODULE['<{retailcrm}prestashop>settings_7a1920d61156abc05a60135aefe8bc67'] = 'По умолчанию'; +$_MODULE['<{retailcrm}prestashop>settings_20cacc01d0de8bc6e9c9846f477e886b'] = 'Выгрузка заказов'; +$_MODULE['<{retailcrm}prestashop>settings_6bcde6286f8d1b76063ee52104a240cf'] = 'Брошенные корзины'; +$_MODULE['<{retailcrm}prestashop>settings_52a13123e134b8b72b6299bc14a36aad'] = 'Daemon Collector'; +$_MODULE['<{retailcrm}prestashop>settings_71098155ccc0a0d6e0b501fbee37e7a9'] = 'Онлайн-консультант'; +$_MODULE['<{retailcrm}prestashop>settings_9b6545e4cea9b4ad4979d41bb9170e2b'] = 'Дополнительно'; +$_MODULE['<{retailcrm}prestashop>settings_061b368c43f85d3fe2c7ccc842883a40'] = 'Настройка соединения'; +$_MODULE['<{retailcrm}prestashop>settings_22a65bd0ef1919aa4e6dee849a7a2925'] = 'URL адрес Simla.com'; +$_MODULE['<{retailcrm}prestashop>settings_656a6828d7ef1bb791e42087c4b5ee6e'] = 'API-ключ'; +$_MODULE['<{retailcrm}prestashop>settings_8ffa3281a35a0d80fef2cac0fa680523'] = 'Включить выгрузку истории'; +$_MODULE['<{retailcrm}prestashop>settings_65dd9f6e8bf4eaf54c3dc96f011dade1'] = 'Получать остатки из Simla.com'; +$_MODULE['<{retailcrm}prestashop>settings_f8d7c52aa84f358caedb96fda86809da'] = 'Включить поддержку корпоративных клиентов'; +$_MODULE['<{retailcrm}prestashop>settings_6c3c1845e109a9ef67378effea0c0503'] = 'Активировать только при включенной опции \"Корпоративные клиенты\" в Simla.com'; +$_MODULE['<{retailcrm}prestashop>settings_917afe348e09163269225a89a825e634'] = 'Синхронизация корзин покупателей'; +$_MODULE['<{retailcrm}prestashop>settings_d8e002d770b6f98af7b7ae9a0e5acfe9'] = 'Создавать заказы для брошенных корзин покупателей'; +$_MODULE['<{retailcrm}prestashop>settings_35b5a9139a54caeb925556ceb2c38086'] = 'Статус заказа для брошенных корзин покупателей'; +$_MODULE['<{retailcrm}prestashop>settings_9b9cf9f8778f69b4c6cf37e66f886be8'] = 'Выберите статус'; +$_MODULE['<{retailcrm}prestashop>settings_a0d135501a738c3c98de385dc28cda61'] = 'Выгружать брошенные корзины'; +$_MODULE['<{retailcrm}prestashop>settings_27096e1243f98e1b3300f57ff1c76456'] = 'Выберите задержку'; +$_MODULE['<{retailcrm}prestashop>settings_1f8246b1e6ada8897902eff8d8cd8f35'] = 'устарел'; +$_MODULE['<{retailcrm}prestashop>settings_4a15f35e8d386dd1d96faa83c1e44a22'] = 'Обновить URL'; +$_MODULE['<{retailcrm}prestashop>settings_5b55e5aeb08a372d36f7e4b7b35d1cd1'] = 'URL для ICML каталога в Prestashop и в %s не совпадают'; +$_MODULE['<{retailcrm}prestashop>settings_06aa6fa8bdc2078e7e1bd903e70c8f6a'] = 'подключен'; +$_MODULE['<{retailcrm}prestashop>settings_7892a1894478824c07b62af2df839291'] = 'Более 7 дней'; +$_MODULE['<{retailcrm}prestashop>settings_8277e0910d750195b448797616e091ad'] = 'д'; +$_MODULE['<{retailcrm}prestashop>settings_2510c39011c5be704182423e3a695e91'] = 'ч'; +$_MODULE['<{retailcrm}prestashop>settings_d8bd79cc131920d5de426f914d17405a'] = 'мин'; +$_MODULE['<{retailcrm}prestashop>settings_3baa7e02e09dba2ba2a188a7c9a055cb'] = 'прошло с момента последнего запуска'; +$_MODULE['<{retailcrm}prestashop>settings_068f80c7519d0528fb08e82137a72131'] = 'Продукты'; +$_MODULE['<{retailcrm}prestashop>settings_9461bed8b71377318436990e57106729'] = 'Торговые предложения'; +$_MODULE['<{retailcrm}prestashop>settings_64ef97a8fe9db8b672287a53c5d836f2'] = 'еще не был сгенерирован'; +$_MODULE['<{retailcrm}prestashop>settings_79c07dbacf542d283944685e1538a1bb'] = 'Нажмите кнопку ниже чтобы сгенерировать %s'; +$_MODULE['<{retailcrm}prestashop>settings_cc84d5b49b62c0959f1af64bffaec3b7'] = 'Генерировать сейчас'; +$_MODULE['<{retailcrm}prestashop>settings_4e537de8dd108eafec4c37603c8ab7fb'] = 'Управление типами доставки'; +$_MODULE['<{retailcrm}prestashop>settings_5b385947acf10ac0c5521161ce96aaa7'] = 'Выберите доставку'; +$_MODULE['<{retailcrm}prestashop>settings_c0fd6d31d096a5845f1d1abb4c132b7d'] = 'Управление статусами заказов'; +$_MODULE['<{retailcrm}prestashop>settings_dd53d9b3603b3279b25c74f6f3f189a4'] = 'Управление типами оплаты'; +$_MODULE['<{retailcrm}prestashop>settings_7dcc1208fa03381346955c6732d9ea85'] = 'Выберите тип'; +$_MODULE['<{retailcrm}prestashop>settings_6f1f9a3e435963417d08849fbef139c1'] = 'Введите идентификаторы заказов для загрузки в Simla.com, разделив их запятыми. Вы также можете указать диапазоны, например \"1-10\". Одновременно можно загружать до 10 заказов.'; +$_MODULE['<{retailcrm}prestashop>settings_acfa058ec9e6e4745eddc0cae3f0f881'] = 'ID заказов'; +$_MODULE['<{retailcrm}prestashop>settings_91412465ea9169dfd901dd5e7c96dd99'] = 'Выгрузить'; +$_MODULE['<{retailcrm}prestashop>settings_f4af7f6987dfee28741ce77ff2d09d46'] = 'Экспортировать заказы и клиентов'; +$_MODULE['<{retailcrm}prestashop>settings_418faff1c9df0d297ff586ac3230be97'] = 'Вы можете экспортировать все заказы и клиентов из CMS в Simla.com, нажав кнопку «Экспорт». Этот процесс может занять много времени, и до его завершения необходимо держать вкладку открытой.'; +$_MODULE['<{retailcrm}prestashop>settings_7442e29d7d53e549b78d93c46b8cdcfc'] = 'Заказы'; +$_MODULE['<{retailcrm}prestashop>settings_e6d0e1c8fc6a4fcf47869df87e04cd88'] = 'Клиенты'; +$_MODULE['<{retailcrm}prestashop>settings_f8f36c02fa6f370808135c66cfc788aa'] = 'Клиенты без заказов'; +$_MODULE['<{retailcrm}prestashop>settings_0095a9fa74d1713e43e370a7d7846224'] = 'Экспортировать'; +$_MODULE['<{retailcrm}prestashop>settings_4d3d769b812b6faa6b76e1a8abaece2d'] = 'Активно'; +$_MODULE['<{retailcrm}prestashop>settings_f75d8fa5c89351544d372cf90528ccf2'] = 'Ключ сайта'; +$_MODULE['<{retailcrm}prestashop>settings_c9cc8cce247e49bae79f15173ce97354'] = 'Сохранить'; +$_MODULE['<{retailcrm}prestashop>settings_4f18e3f1c9941a6ec5a38bc716c521b4'] = 'Код для вставки на сайт'; +$_MODULE['<{retailcrm}prestashop>settings_ec3028a12402ab7f43962a6f3a667b6e'] = 'Режим отладки'; +$_MODULE['<{retailcrm}prestashop>settings_9082f68bc90113d8950e4ed7fe8fa0a4'] = 'Менеджер задач'; +$_MODULE['<{retailcrm}prestashop>settings_9194de58ce560c095f02cefc1c1c61e6'] = 'Имя задачи'; +$_MODULE['<{retailcrm}prestashop>settings_05a3a24340b7b9cc8d4e08f0ef4f4dd9'] = 'Последний запуск'; +$_MODULE['<{retailcrm}prestashop>settings_ec53a8c4f07baed5d8825072c89799be'] = 'Статус'; +$_MODULE['<{retailcrm}prestashop>settings_0be8406951cdfda82f00f79328cf4efc'] = 'Комментарий'; +$_MODULE['<{retailcrm}prestashop>settings_fe5b6cd4d7a31615bbec8d1505089d87'] = 'StackTrace'; +$_MODULE['<{retailcrm}prestashop>settings_b2d37ae1cedf42ff874289b721860af2'] = 'Лог-файлы'; +$_MODULE['<{retailcrm}prestashop>settings_34082694d21dbdcfc31e6e32d9fb2b9f'] = 'Имя файла'; +$_MODULE['<{retailcrm}prestashop>settings_a4b7f1864cfdb47cd05b54eb10337506'] = 'Дата изменения'; +$_MODULE['<{retailcrm}prestashop>settings_6f6cb72d544962fa333e2e34ce64f719'] = 'Размер'; +$_MODULE['<{retailcrm}prestashop>settings_06df33001c1d7187fdd81ea1f5b277aa'] = 'Действия'; +$_MODULE['<{retailcrm}prestashop>settings_801ab24683a4a8c433c6eb40c48bcd9d'] = 'Скачать'; +$_MODULE['<{retailcrm}prestashop>settings_61b0ada67b7f40bf3d40dcc88ae4f3e6'] = 'Скачать все'; $_MODULE['<{retailcrm}prestashop>index_dd259436b3f29f0ba1778d220b343ec9'] = 'Simla.com — сервис для интернет магазинов, который поможет перестать терять заказы и увеличить доход на всех этапах воронки.'; $_MODULE['<{retailcrm}prestashop>index_c7476a92e20715b855d72b1786a71017'] = 'У меня уже есть аккаунт Simla.com'; $_MODULE['<{retailcrm}prestashop>index_e81c4e4f2b7b93b481e13a8553c2ae1b'] = 'или'; @@ -79,58 +152,3 @@ $_MODULE['<{retailcrm}prestashop>index_95428f32e5c696cf71baccb776bc5c15'] = 'Б $_MODULE['<{retailcrm}prestashop>index_e7f9e382dc50889098cbe56f2554c77b'] = 'Кредитной картой'; $_MODULE['<{retailcrm}prestashop>index_7088f1d1d9c91d8b75e9882ffd78540c'] = 'Наши контакты'; $_MODULE['<{retailcrm}prestashop>index_50f158e2507321f1a5b6f8fb9e350818'] = 'Пишите нам если у Вас есть вопросы'; -$_MODULE['<{retailcrm}prestashop>settings_c2cc7082a89c1ad6631a2f66af5f00c0'] = 'Соединение'; -$_MODULE['<{retailcrm}prestashop>settings_065ab3a28ca4f16f55f103adc7d0226f'] = 'Способы доставки'; -$_MODULE['<{retailcrm}prestashop>settings_33af8066d3c83110d4bd897f687cedd2'] = 'Статусы заказов'; -$_MODULE['<{retailcrm}prestashop>settings_bab959acc06bb03897b294fbb892be6b'] = 'Способы оплаты'; -$_MODULE['<{retailcrm}prestashop>settings_7a1920d61156abc05a60135aefe8bc67'] = 'По умолчанию'; -$_MODULE['<{retailcrm}prestashop>settings_20cacc01d0de8bc6e9c9846f477e886b'] = 'Выгрузка заказов'; -$_MODULE['<{retailcrm}prestashop>settings_6bcde6286f8d1b76063ee52104a240cf'] = 'Брошенные корзины'; -$_MODULE['<{retailcrm}prestashop>settings_52a13123e134b8b72b6299bc14a36aad'] = 'Daemon Collector'; -$_MODULE['<{retailcrm}prestashop>settings_71098155ccc0a0d6e0b501fbee37e7a9'] = 'Онлайн-консультант'; -$_MODULE['<{retailcrm}prestashop>settings_9b6545e4cea9b4ad4979d41bb9170e2b'] = 'Дополнительно'; -$_MODULE['<{retailcrm}prestashop>settings_061b368c43f85d3fe2c7ccc842883a40'] = 'Настройка соединения'; -$_MODULE['<{retailcrm}prestashop>settings_22a65bd0ef1919aa4e6dee849a7a2925'] = 'URL адрес Simla.com'; -$_MODULE['<{retailcrm}prestashop>settings_656a6828d7ef1bb791e42087c4b5ee6e'] = 'API-ключ'; -$_MODULE['<{retailcrm}prestashop>settings_8ffa3281a35a0d80fef2cac0fa680523'] = 'Включить выгрузку истории'; -$_MODULE['<{retailcrm}prestashop>settings_65dd9f6e8bf4eaf54c3dc96f011dade1'] = 'Получать остатки из Simla.com'; -$_MODULE['<{retailcrm}prestashop>settings_f8d7c52aa84f358caedb96fda86809da'] = 'Включить поддержку корпоративных клиентов'; -$_MODULE['<{retailcrm}prestashop>settings_6c3c1845e109a9ef67378effea0c0503'] = 'Активировать только при включенной опции \"Корпоративные клиенты\" в Simla.com'; -$_MODULE['<{retailcrm}prestashop>settings_917afe348e09163269225a89a825e634'] = 'Синхронизация корзин покупателей'; -$_MODULE['<{retailcrm}prestashop>settings_d8e002d770b6f98af7b7ae9a0e5acfe9'] = 'Создавать заказы для брошенных корзин покупателей'; -$_MODULE['<{retailcrm}prestashop>settings_35b5a9139a54caeb925556ceb2c38086'] = 'Статус заказа для брошенных корзин покупателей'; -$_MODULE['<{retailcrm}prestashop>settings_9b9cf9f8778f69b4c6cf37e66f886be8'] = 'Выберите статус'; -$_MODULE['<{retailcrm}prestashop>settings_a0d135501a738c3c98de385dc28cda61'] = 'Выгружать брошенные корзины'; -$_MODULE['<{retailcrm}prestashop>settings_27096e1243f98e1b3300f57ff1c76456'] = 'Выберите задержку'; -$_MODULE['<{retailcrm}prestashop>settings_4e537de8dd108eafec4c37603c8ab7fb'] = 'Управление типами доставки'; -$_MODULE['<{retailcrm}prestashop>settings_5b385947acf10ac0c5521161ce96aaa7'] = 'Выберите доставку'; -$_MODULE['<{retailcrm}prestashop>settings_c0fd6d31d096a5845f1d1abb4c132b7d'] = 'Управление статусами заказов'; -$_MODULE['<{retailcrm}prestashop>settings_dd53d9b3603b3279b25c74f6f3f189a4'] = 'Управление типами оплаты'; -$_MODULE['<{retailcrm}prestashop>settings_7dcc1208fa03381346955c6732d9ea85'] = 'Выберите тип'; -$_MODULE['<{retailcrm}prestashop>settings_6f1f9a3e435963417d08849fbef139c1'] = 'Введите идентификаторы заказов для загрузки в Simla.com, разделив их запятыми. Вы также можете указать диапазоны, например \"1-10\". Одновременно можно загружать до 10 заказов.'; -$_MODULE['<{retailcrm}prestashop>settings_acfa058ec9e6e4745eddc0cae3f0f881'] = 'ID заказов'; -$_MODULE['<{retailcrm}prestashop>settings_91412465ea9169dfd901dd5e7c96dd99'] = 'Выгрузить'; -$_MODULE['<{retailcrm}prestashop>settings_f4af7f6987dfee28741ce77ff2d09d46'] = 'Экспортировать заказы и клиентов'; -$_MODULE['<{retailcrm}prestashop>settings_418faff1c9df0d297ff586ac3230be97'] = 'Вы можете экспортировать все заказы и клиентов из CMS в Simla.com, нажав кнопку «Экспорт». Этот процесс может занять много времени, и до его завершения необходимо держать вкладку открытой.'; -$_MODULE['<{retailcrm}prestashop>settings_7442e29d7d53e549b78d93c46b8cdcfc'] = 'Заказы'; -$_MODULE['<{retailcrm}prestashop>settings_e6d0e1c8fc6a4fcf47869df87e04cd88'] = 'Клиенты'; -$_MODULE['<{retailcrm}prestashop>settings_f8f36c02fa6f370808135c66cfc788aa'] = 'Клиенты без заказов'; -$_MODULE['<{retailcrm}prestashop>settings_0095a9fa74d1713e43e370a7d7846224'] = 'Экспортировать'; -$_MODULE['<{retailcrm}prestashop>settings_4d3d769b812b6faa6b76e1a8abaece2d'] = 'Активно'; -$_MODULE['<{retailcrm}prestashop>settings_f75d8fa5c89351544d372cf90528ccf2'] = 'Ключ сайта'; -$_MODULE['<{retailcrm}prestashop>settings_c9cc8cce247e49bae79f15173ce97354'] = 'Сохранить'; -$_MODULE['<{retailcrm}prestashop>settings_4f18e3f1c9941a6ec5a38bc716c521b4'] = 'Код для вставки на сайт'; -$_MODULE['<{retailcrm}prestashop>settings_ec3028a12402ab7f43962a6f3a667b6e'] = 'Режим отладки'; -$_MODULE['<{retailcrm}prestashop>settings_9082f68bc90113d8950e4ed7fe8fa0a4'] = 'Менеджер задач'; -$_MODULE['<{retailcrm}prestashop>settings_9194de58ce560c095f02cefc1c1c61e6'] = 'Имя задачи'; -$_MODULE['<{retailcrm}prestashop>settings_05a3a24340b7b9cc8d4e08f0ef4f4dd9'] = 'Последний запуск'; -$_MODULE['<{retailcrm}prestashop>settings_ec53a8c4f07baed5d8825072c89799be'] = 'Статус'; -$_MODULE['<{retailcrm}prestashop>settings_0be8406951cdfda82f00f79328cf4efc'] = 'Комментарий'; -$_MODULE['<{retailcrm}prestashop>settings_fe5b6cd4d7a31615bbec8d1505089d87'] = 'StackTrace'; -$_MODULE['<{retailcrm}prestashop>settings_b2d37ae1cedf42ff874289b721860af2'] = 'Лог-файлы'; -$_MODULE['<{retailcrm}prestashop>settings_34082694d21dbdcfc31e6e32d9fb2b9f'] = 'Имя файла'; -$_MODULE['<{retailcrm}prestashop>settings_a4b7f1864cfdb47cd05b54eb10337506'] = 'Дата изменения'; -$_MODULE['<{retailcrm}prestashop>settings_6f6cb72d544962fa333e2e34ce64f719'] = 'Размер'; -$_MODULE['<{retailcrm}prestashop>settings_06df33001c1d7187fdd81ea1f5b277aa'] = 'Действия'; -$_MODULE['<{retailcrm}prestashop>settings_801ab24683a4a8c433c6eb40c48bcd9d'] = 'Скачать'; -$_MODULE['<{retailcrm}prestashop>settings_61b0ada67b7f40bf3d40dcc88ae4f3e6'] = 'Скачать все'; diff --git a/retailcrm/upgrade/upgrade-3.3.2.php b/retailcrm/upgrade/upgrade-3.3.2.php index 8f67eb9..5ae1d0b 100644 --- a/retailcrm/upgrade/upgrade-3.3.2.php +++ b/retailcrm/upgrade/upgrade-3.3.2.php @@ -62,11 +62,10 @@ function upgrade_module_3_3_2($module) } foreach ($shops as $shop) { - RetailcrmTools::setShopContext((int) $shop['id_shop']); + RetailcrmContextSwitcher::setShopContext((int) $shop['id_shop']); $api = RetailcrmTools::getApiClient(); if (empty($api)) { - RetailcrmLogger::writeCaller(__METHOD__, 'Set api key & url first'); continue; } diff --git a/retailcrm/views/css/less/retailcrm-export.less b/retailcrm/views/css/less/retailcrm-export.less index 39d63b8..88dde45 100644 --- a/retailcrm/views/css/less/retailcrm-export.less +++ b/retailcrm/views/css/less/retailcrm-export.less @@ -9,6 +9,7 @@ font-size: 18px; margin-bottom: 20px; } + &__content, input&__content { width: 120px; height: 120px; diff --git a/retailcrm/views/css/less/styles.less b/retailcrm/views/css/less/styles.less index 84c178a..05d9719 100644 --- a/retailcrm/views/css/less/styles.less +++ b/retailcrm/views/css/less/styles.less @@ -12,6 +12,8 @@ @grayBtnHover: rgba(122, 122, 122, 0.15); @grayBtnActive: fadein(@grayBtnHover, 10%); @darkGray: #363A41; +@yellow: #fcc94f; +@yellowActive: #edbe4c; @lightYellow: #fcf3b5; @shadowGray: #fdd0d0; @bord: #DFDFDF; @@ -578,6 +580,13 @@ body, html { &_submit { min-width: 218px; } + &_warning { + min-width: 218px; + background: @yellow; + &:hover { + background: @yellowActive; + } + } } .toggle-box { display: none; @@ -607,6 +616,11 @@ body, html { max-width: 300px; vertical-align: middle; } + &__row { + &-bold { + font-weight: bold; + } + } &-no-wrap { white-space: nowrap; } @@ -674,6 +688,7 @@ body, html { background: #fff; border: 1px solid rgba(122,122,122,0.15); position: absolute; + z-index: 5; top: 20px; left: 0; padding: 18px; @@ -696,4 +711,41 @@ body, html { color: #dd2e44; } } + &-alert { + position: relative; + height: 60px; + padding: 0 50px; + line-height: 30px; + &-text { + font-size: 1.5em; + } + &-note { + color: @gray; + font-size: 1.2em; + } + &:before { + display: block; + position: absolute; + left: 0; + top: 0; + padding: 10px 5px; + font: normal normal normal 40px/1 FontAwesome; + } + &-success:before { + content: "\F058"; + color: @green; + } + &-warning:before { + content: "\F06A"; + color: @yellow; + } + &-danger:before { + content: "\F071"; + color: @red; + } + &-info:before { + content: "\F059"; + color: @blue; + } + } } diff --git a/retailcrm/views/css/retailcrm-export.min.css b/retailcrm/views/css/retailcrm-export.min.css index 2a9c514..09d255f 100644 --- a/retailcrm/views/css/retailcrm-export.min.css +++ b/retailcrm/views/css/retailcrm-export.min.css @@ -1 +1 @@ -.retail-circle{float:left;width:50%;text-align:center;padding:20px;margin:20px 0}.retail-circle__title{font-size:18px;margin-bottom:20px}input.retail-circle__content{width:120px;height:120px;border-radius:120px;text-align:center;font-size:20px;line-height:60px}.retail-progress{border-radius:60px;border:1px solid rgba(122,122,122,0.15);width:100%;height:60px;overflow:hidden;transition:height .25s ease}.retail-progress__loader{width:0;border-radius:60px;background:#0068FF;color:white;text-align:center;padding:0 30px;font-size:18px;font-weight:600;transition:width .4s ease-in;line-height:60px}.retail-hidden{visibility:hidden;height:0!important} \ No newline at end of file +.retail-circle{float:left;width:50%;text-align:center;padding:20px;margin:20px 0}.retail-circle__title{font-size:18px;margin-bottom:20px}.retail-circle__content,input.retail-circle__content{width:120px;height:120px;border-radius:120px;text-align:center;font-size:20px;line-height:60px}.retail-progress{border-radius:60px;border:1px solid rgba(122,122,122,0.15);width:100%;height:60px;overflow:hidden;transition:height .25s ease}.retail-progress__loader{width:0;border-radius:60px;background:#0068FF;color:white;text-align:center;padding:0 30px;font-size:18px;font-weight:600;transition:width .4s ease-in;line-height:60px}.retail-hidden{visibility:hidden;height:0!important} \ No newline at end of file diff --git a/retailcrm/views/css/styles.min.css b/retailcrm/views/css/styles.min.css index 2a0c3a1..421b90b 100644 --- a/retailcrm/views/css/styles.min.css +++ b/retailcrm/views/css/styles.min.css @@ -1 +1 @@ -@font-face{font-family:OpenSans;src:url(../fonts/OpenSans/opensans-regular.eot);src:url(../fonts/OpenSans/opensans-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/OpenSans/opensans-regular.woff2) format('woff2'),url(../fonts/OpenSans/opensans-regular.woff) format('woff'),url(../fonts/OpenSans/opensans-regular.ttf) format('truetype'),url(../fonts/OpenSans/opensans-regular.svg#open_sansregular) format('svg');font-weight:400;font-style:normal}@font-face{font-family:OpenSans;src:url(../fonts/OpenSansBold/opensans-bold.eot);src:url(../fonts/OpenSansBold/opensans-bold.eot?#iefix) format('embedded-opentype'),url(../fonts/OpenSansBold/opensans-bold.woff2) format('woff2'),url(../fonts/OpenSansBold/opensans-bold.woff) format('woff'),url(../fonts/OpenSansBold/opensans-bold.ttf) format('truetype'),url(../fonts/OpenSansBold/opensans-bold.svg#open_sansbold) format('svg');font-weight:600;font-style:normal}body,html{margin:0;padding:0;height:100%}.hidden{visibility:hidden}.retail-wrap{font-family:OpenSans,Arial,sans-serif;padding:0 15px;height:100%}.retail-wrap *,.retail-wrap ::after,.retail-wrap ::before{box-sizing:border-box}.retail-container{margin:0 auto;width:100%;max-width:950px}.retail-title{margin:60px 0 0;font-weight:400;text-align:center;font-size:28px;line-height:38px}.retail-title_content{text-align:left;margin-top:40px}.retail-txt{color:#7A7A7A;font-size:18px;line-height:26px}.retail-descript{margin-top:45px;text-align:center}.retail-tab__enabled{display:block}.retail-tab__disabled{display:none!important}.retail-video{margin:30px auto 0;text-align:center;position:relative}.retail-video-trigger{position:absolute;top:0;bottom:0;right:0;left:0;width:100%;height:100%;cursor:pointer}.retail-video iframe{pointer-events:none}.retail-video__btn{position:absolute;left:0;right:0;top:0;bottom:0;margin:auto;width:100px;height:100px;cursor:pointer;opacity:.4;transition:.25s ease}.retail-video__btn svg{width:100%}.retail-video__btn:hover{opacity:.6}.retail-btns{margin:56px auto 0;display:flex;justify-content:space-between;max-width:815px;transition:50ms ease}.retail-btns__separate{padding:0 20px;display:flex;align-items:center;color:#7A7A7A;font-size:16px}.retail-btns_hide{opacity:0}.retail-form{margin-top:60px}.retail-form__title{font-size:16px;font-weight:600;line-height:24px;margin-bottom:22px}.retail-form__title_link{color:#0068FF;transition:.25s ease;float:right}.retail-form__title_link:hover{color:#005add}.retail-form__label{width:100%!important;text-align:left!important;margin:15px 12px;font-size:15px}.retail-form__row{margin-top:15px}.retail-form__row_submit{margin-top:23px}.retail-form__message-warning{padding:13px 18px;margin:1px 13px;border-radius:8px;border:1px solid #fcf3b5;font-size:1rem;box-shadow:0 0 6px 0 #fdd0d0}.retail-form__checkbox{display:flex;flex-direction:row;align-items:center;padding:4px 12px}.retail-form__checkbox input[type=checkbox]{width:24px;height:24px}.retail-form__checkbox label{width:auto;margin-left:8px;font-size:16px}.retail-form__area{display:inline-block!important;vertical-align:top;width:430px!important;height:60px!important;border:1px solid rgba(122,122,122,.15)!important;box-shadow:none!important;border-radius:58px!important;padding:0 28px!important;line-height:normal;color:#7A7A7A!important;font-size:16px!important;appearance:none}.retail-form__area:focus{color:#363A41}.retail-form__area:focus::-webkit-input-placeholder{color:#363A41}.retail-form__area:focus::-moz-placeholder{color:#363A41}.retail-form__area:focus:-moz-placeholder{color:#363A41}.retail-form__area:focus:-ms-input-placeholder{color:#363A41}.retail-form__area_txt{padding:20px 28px!important;line-height:24px!important;height:487px!important;border-radius:20px!important;resize:none!important;font-family:OpenSans,Arial,sans-serif!important}.retail-form input:focus,.retail-form textarea:focus{outline:0!important}.retail-form_main{margin-top:34px;max-width:900px;width:100%}.retail-form_main .retail-form__area{width:100%!important}.retail-tabs{margin-top:60px}.retail-tabs__btn{display:inline-block;vertical-align:top;padding:19px 30px;font-size:16px;font-weight:600;line-height:22px;color:#7A7A7A;text-align:center;min-width:152px;text-decoration:none!important;position:relative;transition:.25s ease}.retail-tabs__btn:hover{color:#363A41}.retail-tabs__btn::after{content:"";height:3px;width:100%;position:absolute;bottom:-1px;left:0;right:0;opacity:0;visibility:hidden;background:#0068FF;transition:.25s ease}.retail-tabs__btn_active{color:#363A41}.retail-tabs__btn_active::after{opacity:1;visibility:visible}.retail-tabs__head{display:flex;justify-content:space-between;border-bottom:1px solid #DFDFDF}.retail-tabs__body{padding-top:18px}.retail-tabs__body p{margin-top:23px;margin-bottom:0;color:#7A7A7A;font-size:16px;line-height:24px}.retail-tabs__item{display:none}.retail-list{margin:0;padding:0;list-style:none}.retail-list__item{padding-left:2px;position:relative;color:#7A7A7A;font-size:16px;line-height:24px}.retail-list__item::before{content:"-";display:inline-block;vertical-align:top;color:#7A7A7A;font-size:16px;line-height:24px;margin-right:3px}.retail-tile{display:flex;flex-wrap:wrap}.retail-tile__col{width:48%;padding-right:35px}.retail-tile__col:nth-child(1){width:52%}.retail-tile__col_contacts{padding-right:0}.retail-tile__row{display:flex;justify-content:center;margin-bottom:30px}.retail-tile__row:nth-last-child(1){margin-bottom:0}.retail-tile__item{margin-top:34px}.retail-tile__item:nth-child(1){margin-top:20px}.retail-tile__title{color:#363A41;font-size:16px;font-weight:600;line-height:24px}.retail-tile__descript{color:#7A7A7A;font-size:16px;line-height:24px;margin-top:10px}.retail-tile__link{color:#0068FF;font-size:16px;font-weight:600;line-height:24px;transition:.25s ease}.retail-tile__link:hover{color:#005add}.retail-popup{position:absolute;width:90%;height:90%;background:#fff;left:0;right:0;top:0;bottom:0;margin:auto;transform:translate3d(0,-1000%,0) scale(.1);transition:.25s ease}.retail-popup__close{position:absolute;top:-30px;right:-30px;width:30px;height:30px;cursor:pointer}.retail-popup__close::after,.retail-popup__close::before{content:"";position:absolute;left:0;right:0;top:0;bottom:0;margin:auto;height:30px;width:2px;background:#fff}.retail-popup__close::before{transform:rotate(45deg)}.retail-popup__close::after{transform:rotate(-45deg)}.retail-popup.open{transform:translate3d(0,0,0) scale(1)}.retail-popup-wrap{position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(0,0,0,.6);z-index:1000;display:none}.retail-column{display:flex;max-width:1389px;height:100%}.retail-column__aside{width:253px;background:#EAEBEC;min-height:300px}.retail-column__content{flex:1 0 auto;padding:0 58px;min-height:300px}.retail-menu{padding:8px 20px 8px 15px}.retail-menu__btn{display:inline-flex;align-items:center;justify-content:center;vertical-align:top;width:100%;height:60px;background:rgba(122,122,122,.1)!important;font-weight:700;font-size:16px;color:#363A41!important;text-decoration:none!important;padding:0 30px;margin-top:20px;border-radius:5px;text-align:center;transition:.25s ease}.retail-menu__btn span{display:block}.retail-menu__btn:hover{background:rgba(122,122,122,.15)!important}.retail-menu__btn:nth-child(1){margin-top:0}.retail-menu__btn_active{color:#fff!important;background:#0068FF!important}.retail-menu__btn_active:hover{background:#005add!important}.retail-menu__btn_active.retail-menu__btn_error{background:#da4932!important}.retail-menu__btn_error{color:#fff!important;background:#ff553b!important}.retail-menu__btn_error:hover{background:#da4932!important}.retail-menu__btn_big{font-size:18px}.retail-menu__btn_hidden{display:none}.retail-full-height{height:100%}.retail .btn{display:inline-block;vertical-align:top;background:rgba(122,122,122,.1);border-radius:58px;height:60px;line-height:60px;padding:0 30px;font-size:18px;font-weight:600;text-align:center;color:#0068FF;text-decoration:none;cursor:pointer;appearance:none;border:none;box-shadow:none;transition:.25s ease}.retail .btn:hover{background:rgba(122,122,122,.15)}.retail .btn:active{background:rgba(122,122,122,.25)}.retail .btn_max{min-width:356px}.retail .btn_invert{background:#0068FF;color:#fff}.retail .btn_invert:hover{background:#005add}.retail .btn_invert:active{background:#0045aa}.retail .btn_whatsapp{background:#33D16B;color:#fff;padding:0 62px}.retail .btn_whatsapp:hover{background:#22CA5D}.retail .btn_submit{min-width:218px}.retail .toggle-box{display:none}.retail-table{width:100%;border:none;border-radius:20px}.retail-table thead th{background:rgba(122,122,122,.15);font-size:16px}.retail-table tbody tr td{border-bottom:1px solid #ccc}.retail-table td,.retail-table th{color:#333;font-size:14px;line-height:60px;padding:4px 4px 4px 6px;max-width:300px;vertical-align:middle}.retail-table-no-wrap{white-space:nowrap}.retail-table-center{text-align:center}.retail-table-sort__btn,.retail-table-sort__switch{cursor:pointer}.retail-table-sort__btn:hover,.retail-table-sort__switch:hover{color:#005add}.retail-table-sort__btn{float:left;clear:both;line-height:15px;font-size:20px;padding-left:10px;padding-right:10px;opacity:0;transition:opacity .2s ease-out}.retail-table-sort__btn-wrap{position:absolute}.retail-table-sort__asc{padding-top:15px;padding-bottom:0}.retail-table-sort__desc{padding-top:0;padding-bottom:15px}.retail-table-sort thead td:hover .retail-table-sort__btn,.retail-table-sort thead th:hover .retail-table-sort__btn{opacity:1}.retail-collapsible__input{display:none}label.retail-collapsible__title{cursor:pointer;font-weight:400;text-align:center;padding:0;position:relative;line-height:1;width:100%}label.retail-collapsible__title:before{content:'\25B6';opacity:0;transition:opacity .2s ease-out}label.retail-collapsible__title:hover:before{opacity:1}.retail-collapsible__content{text-align:left;font-size:12px;line-height:1.5;background:#fff;border:1px solid rgba(122,122,122,.15);position:absolute;top:20px;left:0;padding:18px;margin:0;border-radius:20px;overflow:hidden;max-height:0;transition-duration:.2s;transition-timing-function:ease-out;transition-property:max-height,visibility;visibility:hidden}.retail-collapsible__input:checked+.retail-collapsible__title .retail-collapsible__content{max-height:100vh;visibility:visible}.retail-error-msg,.retail-error-msg:after,.retail-error-msg:before{color:#dd2e44} \ No newline at end of file +@font-face{font-family:'OpenSans';src:url('../fonts/OpenSans/opensans-regular.eot');src:url('../fonts/OpenSans/opensans-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/OpenSans/opensans-regular.woff2') format('woff2'),url('../fonts/OpenSans/opensans-regular.woff') format('woff'),url('../fonts/OpenSans/opensans-regular.ttf') format('truetype'),url('../fonts/OpenSans/opensans-regular.svg#open_sansregular') format('svg');font-weight:normal;font-style:normal}@font-face{font-family:'OpenSans';src:url('../fonts/OpenSansBold/opensans-bold.eot');src:url('../fonts/OpenSansBold/opensans-bold.eot?#iefix') format('embedded-opentype'),url('../fonts/OpenSansBold/opensans-bold.woff2') format('woff2'),url('../fonts/OpenSansBold/opensans-bold.woff') format('woff'),url('../fonts/OpenSansBold/opensans-bold.ttf') format('truetype'),url('../fonts/OpenSansBold/opensans-bold.svg#open_sansbold') format('svg');font-weight:600;font-style:normal}body,html{margin:0;padding:0;height:100%}.hidden{visibility:hidden}.retail-wrap{font-family:OpenSans,Arial,sans-serif;padding:0 15px;height:100%}.retail-wrap *,.retail-wrap *::before,.retail-wrap *::after{box-sizing:border-box}.retail-container{margin:0 auto;width:100%;max-width:950px}.retail-title{margin:60px 0 0;font-weight:400;text-align:center;font-size:28px;line-height:38px}.retail-title_content{text-align:left;margin-top:40px}.retail-txt{color:#7A7A7A;font-size:18px;line-height:26px}.retail-descript{margin-top:45px;text-align:center}.retail-tab__enabled{display:block}.retail-tab__disabled{display:none !important}.retail-video{margin:30px auto 0;text-align:center;position:relative}.retail-video-trigger{position:absolute;top:0;bottom:0;right:0;left:0;width:100%;height:100%;cursor:pointer}.retail-video iframe{pointer-events:none}.retail-video__btn{position:absolute;left:0;right:0;top:0;bottom:0;margin:auto;width:100px;height:100px;cursor:pointer;opacity:.4;transition:.25s ease}.retail-video__btn svg{width:100%}.retail-video__btn:hover{opacity:.6}.retail-btns{margin:56px auto 0;display:flex;justify-content:space-between;max-width:815px;transition:.05s ease}.retail-btns__separate{padding:0 20px;display:flex;align-items:center;color:#7A7A7A;font-size:16px}.retail-btns_hide{opacity:0}.retail-form{margin-top:60px}.retail-form__title{font-size:16px;font-weight:600;line-height:24px;margin-bottom:22px}.retail-form__title_link{color:#0068FF;transition:.25s ease;float:right}.retail-form__title_link:hover{color:#005add}.retail-form__label{width:100% !important;text-align:left !important;margin:15px 12px;font-size:15px}.retail-form__row{margin-top:15px}.retail-form__row_submit{margin-top:23px}.retail-form__message-warning{padding:13px 18px;margin:1px 13px;border-radius:8px;border:1px solid #fcf3b5;font-size:1rem;box-shadow:0 0 6px 0 #fdd0d0}.retail-form__checkbox{display:flex;flex-direction:row;align-items:center;padding:4px 12px}.retail-form__checkbox input[type=checkbox]{width:24px;height:24px}.retail-form__checkbox label{width:auto;margin-left:8px;font-size:16px}.retail-form__area{display:inline-block !important;vertical-align:top;width:430px !important;height:60px !important;border:1px solid rgba(122,122,122,0.15) !important;box-shadow:none !important;border-radius:58px !important;padding:0 28px !important;line-height:normal;color:#7A7A7A !important;font-size:16px !important;appearance:none}.retail-form__area:focus{color:#363A41}.retail-form__area:focus::-webkit-input-placeholder{color:#363A41}.retail-form__area:focus::-moz-placeholder{color:#363A41}.retail-form__area:focus:-moz-placeholder{color:#363A41}.retail-form__area:focus:-ms-input-placeholder{color:#363A41}.retail-form__area_txt{padding:20px 28px !important;line-height:24px !important;height:487px !important;border-radius:20px !important;resize:none !important;font-family:OpenSans,Arial,sans-serif !important}.retail-form input:focus,.retail-form textarea:focus{outline:none !important}.retail-form_main{margin-top:34px;max-width:900px;width:100%}.retail-form_main .retail-form__area{width:100% !important}.retail-tabs{margin-top:60px}.retail-tabs__btn{display:inline-block;vertical-align:top;padding:19px 30px;font-size:16px;font-weight:600;line-height:22px;color:#7A7A7A;text-align:center;min-width:152px;text-decoration:none !important;position:relative;transition:.25s ease}.retail-tabs__btn:hover{color:#363A41}.retail-tabs__btn::after{content:"";height:3px;width:100%;position:absolute;bottom:-1px;left:0;right:0;opacity:0;visibility:hidden;background:#0068FF;transition:.25s ease}.retail-tabs__btn_active{color:#363A41}.retail-tabs__btn_active::after{opacity:1;visibility:visible}.retail-tabs__head{display:flex;justify-content:space-between;border-bottom:1px solid #DFDFDF}.retail-tabs__body{padding-top:18px}.retail-tabs__body p{margin-top:23px;margin-bottom:0;color:#7A7A7A;font-size:16px;line-height:24px}.retail-tabs__item{display:none}.retail-list{margin:0;padding:0;list-style:none}.retail-list__item{padding-left:2px;position:relative;color:#7A7A7A;font-size:16px;line-height:24px}.retail-list__item::before{content:"-";display:inline-block;vertical-align:top;color:#7A7A7A;font-size:16px;line-height:24px;margin-right:3px}.retail-tile{display:flex;flex-wrap:wrap}.retail-tile__col{width:48%;padding-right:35px}.retail-tile__col:nth-child(1){width:52%}.retail-tile__col_contacts{padding-right:0}.retail-tile__row{display:flex;justify-content:center;margin-bottom:30px}.retail-tile__row:nth-last-child(1){margin-bottom:0}.retail-tile__item{margin-top:34px}.retail-tile__item:nth-child(1){margin-top:20px}.retail-tile__title{color:#363A41;font-size:16px;font-weight:600;line-height:24px}.retail-tile__descript{color:#7A7A7A;font-size:16px;line-height:24px;margin-top:10px}.retail-tile__link{color:#0068FF;font-size:16px;font-weight:600;line-height:24px;transition:.25s ease}.retail-tile__link:hover{color:#005add}.retail-popup{position:absolute;width:90%;height:90%;background:white;left:0;right:0;top:0;bottom:0;margin:auto;transform:translate3d(0, -1000%, 0) scale(.1);transition:.25s ease}.retail-popup__close{position:absolute;top:-30px;right:-30px;width:30px;height:30px;cursor:pointer}.retail-popup__close::before,.retail-popup__close::after{content:"";position:absolute;left:0;right:0;top:0;bottom:0;margin:auto;height:30px;width:2px;background:white}.retail-popup__close::before{transform:rotate(45deg)}.retail-popup__close::after{transform:rotate(-45deg)}.retail-popup.open{transform:translate3d(0, 0, 0) scale(1)}.retail-popup-wrap{position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(0,0,0,0.6);z-index:1000;display:none}.retail-column{display:flex;max-width:1389px;height:100%}.retail-column__aside{width:253px;background:#EAEBEC;min-height:300px}.retail-column__content{flex:1 0 auto;padding:0 58px;min-height:300px}.retail-menu{padding:8px 20px 8px 15px}.retail-menu__btn{display:inline-flex;align-items:center;justify-content:center;vertical-align:top;width:100%;height:60px;background:rgba(122,122,122,0.1) !important;font-weight:bold;font-size:16px;color:#363A41 !important;text-decoration:none !important;padding:0 30px;margin-top:20px;border-radius:5px;text-align:center;transition:.25s ease}.retail-menu__btn span{display:block}.retail-menu__btn:hover{background:rgba(122,122,122,0.15) !important}.retail-menu__btn:nth-child(1){margin-top:0}.retail-menu__btn_active{color:white !important;background:#0068FF !important}.retail-menu__btn_active:hover{background:#005add !important}.retail-menu__btn_active.retail-menu__btn_error{background:#da4932 !important}.retail-menu__btn_error{color:white !important;background:#ff553b !important}.retail-menu__btn_error:hover{background:#da4932 !important}.retail-menu__btn_big{font-size:18px}.retail-menu__btn_hidden{display:none}.retail-full-height{height:100%}.retail .btn{display:inline-block;vertical-align:top;background:rgba(122,122,122,0.1);border-radius:58px;height:60px;line-height:60px;padding:0 30px;font-size:18px;font-weight:600;text-align:center;color:#0068FF;text-decoration:none;cursor:pointer;appearance:none;border:none;box-shadow:none;transition:.25s ease}.retail .btn:hover{background:rgba(122,122,122,0.15)}.retail .btn:active{background:rgba(122,122,122,0.25)}.retail .btn_max{min-width:356px}.retail .btn_invert{background:#0068FF;color:white}.retail .btn_invert:hover{background:#005add}.retail .btn_invert:active{background:#0045aa}.retail .btn_whatsapp{background:#33D16B;color:white;padding:0 62px}.retail .btn_whatsapp:hover{background:#22CA5D}.retail .btn_submit{min-width:218px}.retail .btn_warning{min-width:218px;background:#fcc94f}.retail .btn_warning:hover{background:#edbe4c}.retail .toggle-box{display:none}.retail-table{width:100%;border:none;border-radius:20px}.retail-table thead th{background:rgba(122,122,122,0.15);font-size:16px}.retail-table tbody tr td{border-bottom:1px solid #ccc}.retail-table td,.retail-table th{color:#333;font-size:14px;line-height:60px;padding:4px 4px 4px 6px;max-width:300px;vertical-align:middle}.retail-table__row-bold{font-weight:bold}.retail-table-no-wrap{white-space:nowrap}.retail-table-center{text-align:center}.retail-table-sort__btn,.retail-table-sort__switch{cursor:pointer}.retail-table-sort__btn:hover,.retail-table-sort__switch:hover{color:#005add}.retail-table-sort__btn{float:left;clear:both;line-height:15px;font-size:20px;padding-left:10px;padding-right:10px;opacity:0;transition:opacity .2s ease-out}.retail-table-sort__btn-wrap{position:absolute}.retail-table-sort__asc{padding-top:15px;padding-bottom:0}.retail-table-sort__desc{padding-top:0;padding-bottom:15px}.retail-table-sort thead th:hover .retail-table-sort__btn,.retail-table-sort thead td:hover .retail-table-sort__btn{opacity:1}.retail-collapsible__input{display:none}label.retail-collapsible__title{cursor:pointer;font-weight:normal;text-align:center;padding:0;position:relative;line-height:1;width:100%}label.retail-collapsible__title:before{content:'\25B6';opacity:0;transition:opacity .2s ease-out}label.retail-collapsible__title:hover:before{opacity:1}.retail-collapsible__content{text-align:left;font-size:12px;line-height:1.5;background:#fff;border:1px solid rgba(122,122,122,0.15);position:absolute;z-index:5;top:20px;left:0;padding:18px;margin:0;border-radius:20px;overflow:hidden;max-height:0;transition-duration:.2s;transition-timing-function:ease-out;transition-property:max-height,visibility;visibility:hidden}.retail-collapsible__input:checked+.retail-collapsible__title .retail-collapsible__content{max-height:100vh;visibility:visible}.retail-error-msg,.retail-error-msg:after,.retail-error-msg:before{color:#dd2e44}.retail-alert{position:relative;height:60px;padding:0 50px;line-height:30px}.retail-alert-text{font-size:1.5em}.retail-alert-note{color:#7A7A7A;font-size:1.2em}.retail-alert:before{display:block;position:absolute;left:0;top:0;padding:10px 5px;font:normal normal normal 40px/1 FontAwesome}.retail-alert-success:before{content:"\F058";color:#33D16B}.retail-alert-warning:before{content:"\F06A";color:#fcc94f}.retail-alert-danger:before{content:"\F071";color:#ff553b}.retail-alert-info:before{content:"\F059";color:#0068FF} \ No newline at end of file diff --git a/retailcrm/views/js/retailcrm-export.js b/retailcrm/views/js/retailcrm-export.js index 96afeee..2be10c8 100644 --- a/retailcrm/views/js/retailcrm-export.js +++ b/retailcrm/views/js/retailcrm-export.js @@ -134,7 +134,7 @@ $(function () { RetailcrmExportForm.prototype.confirmLeave = function (event) { event.preventDefault(); - e.returnValue = 'Export process has been started'; + event.returnValue = 'Export process has been started'; } RetailcrmExportForm.prototype.exportDone = function () { diff --git a/retailcrm/views/js/retailcrm-export.min.js b/retailcrm/views/js/retailcrm-export.min.js index 392af74..5cf69d0 100644 --- a/retailcrm/views/js/retailcrm-export.min.js +++ b/retailcrm/views/js/retailcrm-export.min.js @@ -34,4 +34,5 @@ * Don't forget to prefix your containers with your own identifier * to avoid any conflicts with others containers. */ -$(function(){function t(){if(this.form=$("input[name=RETAILCRM_EXPORT_ORDERS_COUNT]").closest("form").get(0),void 0===this.form)return!1;this.isDone=!1,this.ordersCount=parseInt($(this.form).find('input[name="RETAILCRM_EXPORT_ORDERS_COUNT"]').val()),this.customersCount=parseInt($(this.form).find('input[name="RETAILCRM_EXPORT_CUSTOMERS_COUNT"]').val()),this.ordersStepSize=parseInt($(this.form).find('input[name="RETAILCRM_EXPORT_ORDERS_STEP_SIZE"]').val()),this.customersStepSize=parseInt($(this.form).find('input[name="RETAILCRM_EXPORT_CUSTOMERS_STEP_SIZE"]').val()),this.ordersStep=0,this.customersStep=0,this.submitButton=$(this.form).find('button[id="export-orders-submit"]').get(0),this.progressBar=$(this.form).find('div[id="export-orders-progress"]').get(0),this.submitAction=this.submitAction.bind(this),this.exportAction=this.exportAction.bind(this),this.exportDone=this.exportDone.bind(this),this.initializeProgressBar=this.initializeProgressBar.bind(this),this.updateProgressBar=this.updateProgressBar.bind(this),$(this.submitButton).click(this.submitAction)}t.prototype.submitAction=function(t){t.preventDefault(),this.initializeProgressBar(),this.exportAction()},t.prototype.exportAction=function(){let t={submitretailcrm:1,ajax:1};this.ordersStep*this.ordersStepSize",{class:"retail-progress__loader",text:"0%"})),window.addEventListener("beforeunload",this.confirmLeave)},t.prototype.updateProgressBar=function(){let t=this.ordersStep*this.ordersStepSize;t>this.ordersCount&&(t=this.ordersCount);let s=this.customersStep*this.customersStepSize;s>this.customersCount&&(s=this.customersCount);var e=t+s,i=this.ordersCount+this.customersCount,r=Math.round(100*e/i);$(this.progressBar).find(".retail-progress__loader").text(r+"%"),$(this.progressBar).find(".retail-progress__loader").css("width",r+"%"),$(this.progressBar).find(".retail-progress__loader").attr("title",e+"/"+i)},t.prototype.confirmLeave=function(t){t.preventDefault(),e.returnValue="Export process has been started"},t.prototype.exportDone=function(){window.removeEventListener("beforeunload",this.confirmLeave),alert("Export is done")},window.RetailcrmExportForm=t}); \ No newline at end of file +$(function(){function t(){if(this.form=$("input[name=RETAILCRM_EXPORT_ORDERS_COUNT]").closest("form").get(0),void 0===this.form)return!1;this.isDone=!1,this.ordersCount=parseInt($(this.form).find('input[name="RETAILCRM_EXPORT_ORDERS_COUNT"]').val()),this.customersCount=parseInt($(this.form).find('input[name="RETAILCRM_EXPORT_CUSTOMERS_COUNT"]').val()),this.ordersStepSize=parseInt($(this.form).find('input[name="RETAILCRM_EXPORT_ORDERS_STEP_SIZE"]').val()),this.customersStepSize=parseInt($(this.form).find('input[name="RETAILCRM_EXPORT_CUSTOMERS_STEP_SIZE"]').val()),this.ordersStep=0,this.customersStep=0,this.submitButton=$(this.form).find('button[id="export-orders-submit"]').get(0),this.progressBar=$(this.form).find('div[id="export-orders-progress"]').get(0),this.submitAction=this.submitAction.bind(this),this.exportAction=this.exportAction.bind(this),this.exportDone=this.exportDone.bind(this),this.initializeProgressBar=this.initializeProgressBar.bind(this),this.updateProgressBar=this.updateProgressBar.bind(this),$(this.submitButton).click(this.submitAction)}t.prototype.submitAction=function(t){t.preventDefault(),this.initializeProgressBar(),this.exportAction()},t.prototype.exportAction=function(){let t={submitretailcrm:1,ajax:1};this.ordersStep*this.ordersStepSize",{class:"retail-progress__loader",text:"0%"})),window.addEventListener("beforeunload",this.confirmLeave)},t.prototype.updateProgressBar=function(){let t=this.ordersStep*this.ordersStepSize;t>this.ordersCount&&(t=this.ordersCount);let s=this.customersStep*this.customersStepSize;s>this.customersCount&&(s=this.customersCount);var e=t+s,i=this.ordersCount+this.customersCount,r=Math.round(100*e/i);$(this.progressBar).find(".retail-progress__loader").text(r+"%"),$(this.progressBar).find(".retail-progress__loader").css("width",r+"%"),$(this.progressBar).find(".retail-progress__loader").attr("title",e+"/"+i)},t.prototype.confirmLeave=function(t){t.preventDefault(),t.returnValue="Export process has been started"},t.prototype.exportDone=function(){window.removeEventListener("beforeunload",this.confirmLeave),alert("Export is done")},window.RetailcrmExportForm=t}); +//# sourceMappingURL=retailcrm-export.min.js.map \ No newline at end of file diff --git a/retailcrm/views/js/retailcrm-icml.js b/retailcrm/views/js/retailcrm-icml.js new file mode 100644 index 0000000..62a5500 --- /dev/null +++ b/retailcrm/views/js/retailcrm-icml.js @@ -0,0 +1,95 @@ +/** + * MIT License + * + * Copyright (c) 2020 DIGITAL RETAIL TECHNOLOGIES SL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade PrestaShop to newer + * versions in the future. If you wish to customize PrestaShop for your + * needs please refer to http://www.prestashop.com for more information. + * + * @author DIGITAL RETAIL TECHNOLOGIES SL + * @copyright 2020 DIGITAL RETAIL TECHNOLOGIES SL + * @license https://opensource.org/licenses/MIT The MIT License + * + * Don't forget to prefix your containers with your own identifier + * to avoid any conflicts with others containers. + */ +$(function () { + function RetailcrmIcmlForm(tabController) { + this.submitButton = $('button[id="generate-icml-submit"]').get(0); + this.updateButton = $('button[id="update-icml-submit"]').get(0); + this.form = $(this.submitButton).closest('form').get(0); + this.icmlField = $(this.form).find('input[name="RETAILCRM_RUN_JOB"]').get(0); + + if (typeof this.form === 'undefined') { + return false; + } + + this.submitAction = this.submitAction.bind(this); + this.updateAction = this.updateAction.bind(this); + this.setLoading = this.setLoading.bind(this); + this.tabController = tabController; + + $(this.submitButton).click(this.submitAction); + $(this.updateButton).click(this.updateAction); + } + + RetailcrmIcmlForm.prototype.submitAction = function (event) { + event.preventDefault(); + + this.setLoading(true); + this.tabController.storeTabInAction(this.form); + + $(this.icmlField).val('RetailcrmIcmlEvent'); + $(this.form).submit(); + }; + + RetailcrmIcmlForm.prototype.updateAction = function (event) { + event.preventDefault(); + + this.setLoading(true); + this.tabController.storeTabInAction(this.form); + + $(this.icmlField).val('RetailcrmIcmlUpdateUrlEvent'); + $(this.form).submit(); + }; + + RetailcrmIcmlForm.prototype.setLoading = function (loading) { + var loaderId = 'retailcrm-loading-fade', + indicator = $('#' + loaderId); + + if (indicator.length === 0) { + $('body').append(` +
+
+
+ `.trim()); + + indicator = $('#' + loaderId); + } + + indicator.css('visibility', (loading ? 'visible' : 'hidden')); + }; + + window.RetailcrmIcmlForm = RetailcrmIcmlForm; +}); diff --git a/retailcrm/views/js/retailcrm-icml.min.js b/retailcrm/views/js/retailcrm-icml.min.js new file mode 100644 index 0000000..2fd5129 --- /dev/null +++ b/retailcrm/views/js/retailcrm-icml.min.js @@ -0,0 +1,42 @@ +/** + * MIT License + * + * Copyright (c) 2020 DIGITAL RETAIL TECHNOLOGIES SL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade PrestaShop to newer + * versions in the future. If you wish to customize PrestaShop for your + * needs please refer to http://www.prestashop.com for more information. + * + * @author DIGITAL RETAIL TECHNOLOGIES SL + * @copyright 2020 DIGITAL RETAIL TECHNOLOGIES SL + * @license https://opensource.org/licenses/MIT The MIT License + * + * Don't forget to prefix your containers with your own identifier + * to avoid any conflicts with others containers. + */ +$(function(){function t(t){if(this.submitButton=$('button[id="generate-icml-submit"]').get(0),this.updateButton=$('button[id="update-icml-submit"]').get(0),this.form=$(this.submitButton).closest("form").get(0),this.icmlField=$(this.form).find('input[name="RETAILCRM_RUN_JOB"]').get(0),void 0===this.form)return!1;this.submitAction=this.submitAction.bind(this),this.updateAction=this.updateAction.bind(this),this.setLoading=this.setLoading.bind(this),this.tabController=t,$(this.submitButton).click(this.submitAction),$(this.updateButton).click(this.updateAction)}t.prototype.submitAction=function(t){t.preventDefault(),this.setLoading(!0),this.tabController.storeTabInAction(this.form),$(this.icmlField).val("RetailcrmIcmlEvent"),$(this.form).submit()},t.prototype.updateAction=function(t){t.preventDefault(),this.setLoading(!0),this.tabController.storeTabInAction(this.form),$(this.icmlField).val("RetailcrmIcmlUpdateUrlEvent"),$(this.form).submit()},t.prototype.setLoading=function(t){var i="retailcrm-loading-fade",o=$("#"+i);0===o.length&&($("body").append(` +
+
+
+ `.trim()),o=$("#"+i)),o.css("visibility",t?"visible":"hidden")},window.RetailcrmIcmlForm=t}); +//# sourceMappingURL=retailcrm-icml.min.js.map \ No newline at end of file diff --git a/retailcrm/views/js/retailcrm.js b/retailcrm/views/js/retailcrm.js index fd2d02a..f62a05f 100644 --- a/retailcrm/views/js/retailcrm.js +++ b/retailcrm/views/js/retailcrm.js @@ -42,8 +42,7 @@ $(function(){ this.tableSort.init(); this.player.init(); this.tabs.init(); - this.uploadForm.init(this.settingsTabs.init()); - this.exportForm.init() + this.eventForm.init(this.settingsTabs.init()); this.popup.init(); this.toggleBox(); this.trimConsultant(); @@ -220,6 +219,7 @@ $(function(){ 'rcrm_tab_payment_types': selectsUpdate, 'rcrm_tab_consultant': mainSubmitHide, 'rcrm_tab_advanced': mainSubmitHide, + 'rcrm_tab_catalog': mainSubmitHide, 'rcrm_tab_orders_upload': mainSubmitHide }); tabs.initializeTabs(); @@ -227,23 +227,23 @@ $(function(){ return tabs; } }, - uploadForm: { + eventForm: { init: function (tabController) { if (!(typeof RetailcrmUploadForm === 'undefined')) { new RetailcrmUploadForm(tabController); } - } - }, - exportForm: { - init: function () { + if (!(typeof RetailcrmIcmlForm === 'undefined')) { + new RetailcrmIcmlForm(tabController); + } if (!(typeof RetailcrmExportForm === 'undefined')) { new RetailcrmExportForm(); } - } + }, }, tabs: { init: function () { $('.retail-tabs__btn').on('click', this.swithTab); + this.advancedTab(); }, swithTab: function (e) { e.preventDefault(); @@ -256,6 +256,16 @@ $(function(){ .fadeIn(150); }); $(this).addClass('retail-tabs__btn_active'); + }, + advancedTab: function () { + let tabElement = document.getElementsByClassName('retail-title_content')[0]; + if (tabElement !== undefined) { + tabElement.addEventListener('click', function (evt) { + if (evt.detail === 3) { + $('.retail-menu__btn[data-tab-trigger="rcrm_tab_advanced"]').click(); + } + }); + } } }, popup: { diff --git a/retailcrm/views/js/retailcrm.min.js b/retailcrm/views/js/retailcrm.min.js index 492aaff..dbd2866 100644 --- a/retailcrm/views/js/retailcrm.min.js +++ b/retailcrm/views/js/retailcrm.min.js @@ -34,4 +34,5 @@ * Don't forget to prefix your containers with your own identifier * to avoid any conflicts with others containers. */ -$(function(){var a={init:function(){this.selects.init(),this.tableSort.init(),this.player.init(),this.tabs.init(),this.uploadForm.init(this.settingsTabs.init()),this.exportForm.init(),this.popup.init(),this.toggleBox(),this.trimConsultant(),this.showSettings()},selects:{init:function(){var t=this;try{$(".jq-select").SumoSelect(),$("li.opt").each((t,e)=>{if(0===$(e).find("label").html().length){let t=$(e).closest("ul").closest("div").parent().find("select");$(e).find("label").html(t.attr("placeholder")),$(e).addClass("disabled")}}),t.update(),$(document).on("change",".jq-select",function(){t.update()})}catch(t){console.warn("Cannot initialize select: "+t.message)}},update:function(){var n={};let t=$(".retail-tab__enabled").find("select:not(#RETAILCRM_API_DELIVERY_DEFAULT, #RETAILCRM_API_PAYMENT_DEFAULT)");t.each((t,e)=>{var i=$(e).val();i&&i.length&&(n[t]=$('option[value="'+$(e).val()+'"]',$(e)).index())});let s=Object.values(n);t.each((i,a)=>{$("option",a).each((t,e)=>{-1===$.inArray(t,s)||void 0!==n[i]&&n[i]==t?a.sumo.enableItem(t):a.sumo.disableItem(t)})})}},tableSort:{init:function(){var n=this;$(".retail-table-sort").each((t,a)=>{$(a).find(".retail-table-sort__switch").each((t,e)=>{const i=$(e).closest("th,td").index();$(e).click(t=>{t.preventDefault(),n.sort(a,i)})}),$(a).find(".retail-table-sort__asc").each((t,e)=>{const i=$(e).closest("th,td").index();$(e).click(t=>{t.preventDefault(),n.sort(a,i,"asc")})}),$(a).find(".retail-table-sort__desc").each((t,e)=>{const i=$(e).closest("th,td").index();$(e).click(t=>{t.preventDefault(),n.sort(a,i,"desc")})}),$(a).find(".retail-table-sort__initial").click()})},sort:function(t,e,i=void 0){let a,n,s,o,r,l,c,d=0;for(n=!0,c=i||"asc";n;){for(n=!1,a=t.rows,s=1;sr.innerHTML.toLowerCase()){l=!0;break}}else if("desc"===c&&o.innerHTML.toLowerCase(){if(0===$(e).find("label").html().length){let t=$(e).closest("ul").closest("div").parent().find("select");$(e).find("label").html(t.attr("placeholder")),$(e).addClass("disabled")}}),t.update(),$(document).on("change",".jq-select",function(){t.update()})}catch(t){console.warn("Cannot initialize select: "+t.message)}},update:function(){var n={};let t=$(".retail-tab__enabled").find("select:not(#RETAILCRM_API_DELIVERY_DEFAULT, #RETAILCRM_API_PAYMENT_DEFAULT)");t.each((t,e)=>{var a=$(e).val();a&&a.length&&(n[t]=$('option[value="'+$(e).val()+'"]',$(e)).index())});let s=Object.values(n);t.each((a,i)=>{$("option",i).each((t,e)=>{-1===$.inArray(t,s)||void 0!==n[a]&&n[a]==t?i.sumo.enableItem(t):i.sumo.disableItem(t)})})}},tableSort:{init:function(){var n=this;$(".retail-table-sort").each((t,i)=>{$(i).find(".retail-table-sort__switch").each((t,e)=>{const a=$(e).closest("th,td").index();$(e).click(t=>{t.preventDefault(),n.sort(i,a)})}),$(i).find(".retail-table-sort__asc").each((t,e)=>{const a=$(e).closest("th,td").index();$(e).click(t=>{t.preventDefault(),n.sort(i,a,"asc")})}),$(i).find(".retail-table-sort__desc").each((t,e)=>{const a=$(e).closest("th,td").index();$(e).click(t=>{t.preventDefault(),n.sort(i,a,"desc")})}),$(i).find(".retail-table-sort__initial").click()})},sort:function(t,e,a=void 0){let i,n,s,r,o,l,c,d=0;for(n=!0,c=a||"asc";n;){for(n=!1,i=t.rows,s=1;so.innerHTML.toLowerCase()){l=!0;break}}else if("desc"===c&&r.innerHTML.toLowerCase() -Simla.com + +{assign var="systemName" value="Simla.com"} +{capture name="catalogTitleName"}{l s='Icml catalog' mod='retailcrm'}{/capture} +{assign var="catalogTitleName" value=$smarty.capture.catalogTitleName} + +{$systemName|escape:'htmlall':'UTF-8'} +
+
+ {$catalogTitleName|escape:'htmlall':'UTF-8'} + {if $catalogInfoMultistore|count == 1} + {assign var='catalogInfo' value=$catalogInfoMultistore[$catalogInfoMultistore|@key] } + {l s='Manage site settings' mod='retailcrm'} + {/if} +
+ {foreach from=$catalogInfoMultistore key=catalogShopId item=catalogInfo} + + {if $catalogInfo and $catalogInfo.lastGenerated} + {if $catalogInfo.isOutdated } +
+
+ {$catalogTitleName|escape:'htmlall':'UTF-8'} {l s='is outdated' mod='retailcrm'} +
+ {elseif !$catalogInfo.isUrlActual} + {assign var="showUpdateButton" value=true} +
+
+ {l s='URL for Icml catalog file in Prestashop and in %s do not match' mod='retailcrm' sprintf=[$systemName]} +
+ {else} +
+
+ {$catalogTitleName|escape:'htmlall':'UTF-8'} {l s='connected' mod='retailcrm'} +
+ {/if} +
+ {$catalogInfo.lastGenerated|date_format:"%Y-%m-%d %H:%M:%S"|escape:'htmlall':'UTF-8'} +
+
+
+
+ + {if $catalogInfo.lastGeneratedDiff.days > 7} + {l s='More than 7 days' mod='retailcrm'} + {else} + {if $catalogInfo.lastGeneratedDiff.days > 0} + {$catalogInfo.lastGeneratedDiff.days|escape:'htmlall':'UTF-8'} {l s='d' mod='retailcrm'}. + {/if} + {if $catalogInfo.lastGeneratedDiff.hours > 0} + {$catalogInfo.lastGeneratedDiff.hours|escape:'htmlall':'UTF-8'} {l s='h' mod='retailcrm'}. + {/if} + {$catalogInfo.lastGeneratedDiff.minutes|escape:'htmlall':'UTF-8'} {l s='min' mod='retailcrm'}. + {/if} + + {l s='passed since last run' mod='retailcrm'} +
+
+ + {$catalogInfo.productsCount|default:'---'|escape:'htmlall':'UTF-8'} + + {l s='Products' mod='retailcrm'} + + {$catalogInfo.offersCount|default:'---'|escape:'htmlall':'UTF-8'} + + {l s='Offers' mod='retailcrm'} +
+
+ {else} +
+
+ {$catalogTitleName|escape:'htmlall':'UTF-8'} {l s='was not generated yet' mod='retailcrm'} +
+
+ {l s='Press the below button to generate the %s' mod='retailcrm' sprintf=[$catalogTitleName]} +
+
+ {/if} + {/foreach} + +
+ + +
+
{l s='Delivery' mod='retailcrm'} @@ -302,7 +399,7 @@ {foreach from=$lastRunDetails key=key item=item} - + {if isset($jobsNames[$key]) } {l s=$jobsNames[$key] mod='retailcrm'} @@ -415,5 +512,6 @@ +