diff --git a/retailcrm/bootstrap.php b/retailcrm/bootstrap.php
old mode 100644
new mode 100755
diff --git a/retailcrm/config_ru.xml b/retailcrm/config_ru.xml
new file mode 100644
index 0000000..e87ab03
--- /dev/null
+++ b/retailcrm/config_ru.xml
@@ -0,0 +1,13 @@
+
+
+ retailcrm
+
+
+
+
+
+
+ 1
+ 1
+
+
\ No newline at end of file
diff --git a/retailcrm/index.php b/retailcrm/index.php
old mode 100644
new mode 100755
diff --git a/retailcrm/job/abandonedCarts.php b/retailcrm/job/abandonedCarts.php
new file mode 100644
index 0000000..3f84007
--- /dev/null
+++ b/retailcrm/job/abandonedCarts.php
@@ -0,0 +1,85 @@
+executeS(
+ 'SELECT c.id_cart, c.date_upd
+ FROM '._DB_PREFIX_.'cart AS c
+ WHERE id_customer != 0
+ AND TIME_TO_SEC(TIMEDIFF(now(), date_upd)) >= 86400
+ AND c.id_cart NOT IN(SELECT id_cart from '._DB_PREFIX_.'orders);'
+);
+
+$status = Configuration::get('RETAILCRM_API_SYNCHRONIZED_CART_STATUS');
+$paymentTypes = array_keys(json_decode(Configuration::get('RETAILCRM_API_PAYMENT'), true));
+
+if (empty($rows)
+ || empty($status)
+ || !$api
+ || (count($paymentTypes) < 1)
+) {
+ return;
+}
+
+foreach ($rows as $cartId) {
+ $cart = new Cart($cartId['id_cart']);
+ $cartExternalId = RetailCRM::getCartOrderExternalId($cart);
+
+ $response = $api->ordersGet($cartExternalId);
+
+ if ($response === false) {
+ $api->customersCreate(RetailCRM::buildCrmCustomer(new Customer($cart->id_customer)));
+ $order = RetailCRM::buildCrmOrderFromCart($cart, $cartExternalId, $paymentTypes[0], $status);
+
+ if (empty($order)) {
+ continue;
+ }
+
+ if ($api->ordersCreate($order) !== false) {
+ $cart->date_upd = date('Y-m-d H:i:s');
+ $cart->save();
+ }
+
+ continue;
+ }
+
+ if (isset($response['order']) && !empty($response['order'])) {
+ $order = RetailCRM::buildCrmOrderFromCart($cart, $response['order']['externalId'], $paymentTypes[0], $status);
+
+ if (empty($order)) {
+ continue;
+ }
+
+ if ($api->ordersEdit($order) !== false) {
+ $cart->date_upd = date('Y-m-d H:i:s');
+ $cart->save();
+ }
+ }
+}
diff --git a/retailcrm/job/export.php b/retailcrm/job/export.php
old mode 100644
new mode 100755
diff --git a/retailcrm/job/icml.php b/retailcrm/job/icml.php
old mode 100644
new mode 100755
diff --git a/retailcrm/job/index.php b/retailcrm/job/index.php
old mode 100644
new mode 100755
diff --git a/retailcrm/job/inventories.php b/retailcrm/job/inventories.php
old mode 100644
new mode 100755
diff --git a/retailcrm/job/jobs.php b/retailcrm/job/jobs.php
new file mode 100644
index 0000000..aeeedbc
--- /dev/null
+++ b/retailcrm/job/jobs.php
@@ -0,0 +1,18 @@
+ DateInterval::createFromDateString('10 seconds')
+ ),
+ true
+);
diff --git a/retailcrm/job/missing.php b/retailcrm/job/missing.php
old mode 100644
new mode 100755
diff --git a/retailcrm/job/sync.php b/retailcrm/job/sync.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/CurlException.php b/retailcrm/lib/CurlException.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/InvalidJsonException.php b/retailcrm/lib/InvalidJsonException.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/JobManager.php b/retailcrm/lib/JobManager.php
new file mode 100644
index 0000000..ea5db29
--- /dev/null
+++ b/retailcrm/lib/JobManager.php
@@ -0,0 +1,393 @@
+ $diff) {
+ try {
+ if (static::compareIntervals(date_diff($lastRun, $current), $diff, $current) == 1) {
+ JobManager::runJob($job, $runOnceInContext);
+ }
+ } catch (\Exception $exception) {
+ static::handleError($exception->getFile(), $exception->getMessage());
+ } catch (\Throwable $throwable) {
+ static::handleError($throwable->getFile(), $throwable->getMessage());
+ } catch (\Error $error) {
+ static::handleError($error->getFile(), $error->getMessage());
+ }
+ }
+
+ static::unlock();
+ }
+
+ /**
+ * Compare two date intervals
+ *
+ * @param $first
+ * @param $second
+ * @param null $now
+ *
+ * @return int
+ * @throws \Exception
+ */
+ private static function compareIntervals($first, $second, $now = null)
+ {
+ $dateFirst = is_null($now) ? new DateTime() : $now;
+ $dateSecond = clone $dateFirst;
+
+ $dateFirst->add($first);
+ $dateSecond->add($second);
+
+ if($dateFirst < $dateSecond) {
+ return -1;
+ } elseif($dateFirst == $dateSecond) {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ /**
+ * Runs job
+ *
+ * @param string $job
+ * @param bool $once
+ */
+ public static function runJob($job, $once = false)
+ {
+ $jobFile = implode(DIRECTORY_SEPARATOR, array(_PS_ROOT_DIR_, 'modules', 'retailcrm', 'job', $job . '.php'));
+
+ if (!file_exists($jobFile)) {
+ throw new \InvalidArgumentException('Cannot find job');
+ }
+
+ static::execPHP($jobFile, false, $once);
+ }
+
+ /**
+ * Runs PHP file
+ *
+ * @param $fileCommandLine
+ * @param bool $fork
+ * @param bool $once
+ */
+ private static function execPHP($fileCommandLine, $fork = true, $once = false)
+ {
+ if ($fork) {
+ static::execInBackground(sprintf('%s %s', static::getPhpBinary(), $fileCommandLine));
+ } else {
+ static::execHere($fileCommandLine, $once);
+ }
+ }
+
+ /**
+ * Serializes jobs to JSON
+ *
+ * @param $jobs
+ *
+ * @return string
+ */
+ public static function serializeJobs($jobs)
+ {
+ foreach ($jobs as $name => $interval) {
+ $jobs[$name] = serialize($interval);
+ }
+
+ return (string) base64_encode(json_encode($jobs));
+ }
+
+ /**
+ * Unserializes jobs
+ *
+ * @param $jobsJson
+ *
+ * @return array
+ */
+ public static function deserializeJobs($jobsJson)
+ {
+ $jobs = json_decode(base64_decode($jobsJson), true);
+
+ if (json_last_error() != JSON_ERROR_NONE) {
+ throw new \InvalidArgumentException(sprintf('Invalid JSON: %s', json_last_error_msg()));
+ }
+
+ if (!is_array($jobs) || count($jobs) == 0) {
+ throw new \InvalidArgumentException('Empty or invalid data');
+ }
+
+ foreach ($jobs as $name => $interval) {
+ if (!is_string($name) || !is_string($interval)) {
+ throw new \InvalidArgumentException('Invalid job in array');
+ }
+
+ $intervalObj = unserialize($interval);
+
+ if (!($intervalObj instanceof DateInterval)) {
+ throw new \InvalidArgumentException('Invalid job interval in array');
+ }
+
+ $jobs[$name] = $intervalObj;
+ }
+
+ return (array) $jobs;
+ }
+
+ /**
+ * Writes error to log and returns 500
+ *
+ * @param $file
+ * @param $msg
+ */
+ private static function handleError($file, $msg)
+ {
+ error_log(sprintf('%s: %s', $file, $msg), 3, _PS_ROOT_DIR_ . '/retailcrm.log');
+ http_response_code(500);
+ }
+
+ /**
+ * Run process in background without waiting
+ *
+ * @param $cmd
+ *
+ * @return void
+ */
+ private static function execInBackground($cmd) {
+ if (substr(php_uname(), 0, 7) == "Windows"){
+ pclose(popen("start /B ". $cmd, "r"));
+ } else {
+ $outputPos = strpos($cmd, '>');
+
+ if ($outputPos !== false) {
+ $cmd = substr($cmd, 0, $outputPos);
+ }
+
+ $command = $cmd . " > /dev/null &";
+
+ if (function_exists('exec')) {
+ exec($command);
+ } else if (function_exists('shell_exec')) {
+ shell_exec($command);
+ } else if (function_exists('passthru')) {
+ passthru($command);
+ }
+ }
+ }
+
+ /**
+ * Executes php script in this context, without hanging up request
+ *
+ * @param string $phpScript
+ * @param bool $once
+ */
+ private static function execHere($phpScript, $once = false)
+ {
+ ignore_user_abort( true);
+ set_time_limit(static::getTimeLimit());
+
+ if (version_compare(phpversion(), '7.0.16', '>=') &&
+ function_exists('fastcgi_finish_request')
+ ) {
+ if (!headers_sent()) {
+ header('Expires: Thu, 19 Nov 1981 08:52:00 GMT');
+ header('Cache-Control: no-store, no-cache, must-revalidate');
+ }
+
+ fastcgi_finish_request();
+ }
+
+ if ($once) {
+ require_once($phpScript);
+ } else {
+ require($phpScript);
+ }
+ }
+
+ /**
+ * Returns true if system support execution in background
+ *
+ * @return bool
+ */
+ private static function canExecInBackground()
+ {
+ if (substr(php_uname(), 0, 7) == "Windows"){
+ return function_exists('pclose') && function_exists('popen');
+ } else {
+ return function_exists('exec')
+ || function_exists('shell_exec')
+ || function_exists('passthru');
+ }
+ }
+
+ /**
+ * Returns path to current PHP binary
+ *
+ * @return string
+ */
+ private static function getPhpBinary()
+ {
+ if (defined('PHP_BINARY') && !empty(PHP_BINARY)) {
+ return PHP_BINARY;
+ }
+
+ if (defined('PHP_BINDIR') && !empty(PHP_BINDIR)) {
+ $version = phpversion();
+ $filePath = implode(DIRECTORY_SEPARATOR, array(PHP_BINDIR, 'php' . $version));
+
+ while (strlen($version) != 0 && !file_exists($filePath)) {
+ $dotPos = strrpos($version, '.');
+
+ if ($dotPos !== false) {
+ $version = substr($version, 0, strrpos($version, '.'));
+ } else {
+ $version = '';
+ }
+
+ $filePath = implode(DIRECTORY_SEPARATOR, array(PHP_BINDIR, 'php' . $version));
+ }
+
+ if (file_exists($filePath)) {
+ return $filePath;
+ }
+ }
+
+ return 'php';
+ }
+
+ /**
+ * Returns script execution time limit
+ *
+ * @return int
+ */
+ private static function getTimeLimit()
+ {
+ return 14400;
+ }
+
+ /**
+ * Returns true if lock is present and it's not expired
+ *
+ * @return bool
+ */
+ private static function isLocked()
+ {
+ $inProcess = (bool) Configuration::get(self::IN_PROGRESS_NAME);
+ $lastRan = date_create_from_format(self::DATE_FORMAT, (string) Configuration::get(self::LAST_RUN_NAME));
+ $lastRanSeconds = $lastRan instanceof DateTime ? $lastRan->format('U') : time();
+
+ if (($lastRanSeconds + self::getTimeLimit()) < time()) {
+ static::unlock();
+
+ return false;
+ }
+
+ return $inProcess;
+ }
+
+ /**
+ * Installs lock
+ *
+ * @return bool
+ */
+ private static function lock()
+ {
+ if (!static::isLocked()) {
+ Configuration::updateValue(self::IN_PROGRESS_NAME, true);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Removes lock
+ *
+ * @return bool
+ */
+ private static function unlock()
+ {
+ Configuration::updateValue(self::IN_PROGRESS_NAME, false);
+
+ return false;
+ }
+}
+
+if (PHP_SAPI == 'cli' && $argc == 3) {
+ try {
+ $jobs = JobManager::deserializeJobs($argv[1]);
+ $runOnce = (bool) $argv[2];
+ } catch (InvalidArgumentException $exception) {
+ printf('Error: %s%s', $exception->getMessage(), PHP_EOL);
+ exit(0);
+ }
+
+ JobManager::execJobs($jobs, $runOnce);
+}
\ No newline at end of file
diff --git a/retailcrm/lib/RetailcrmApiClientV4.php b/retailcrm/lib/RetailcrmApiClientV4.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/RetailcrmApiClientV5.php b/retailcrm/lib/RetailcrmApiClientV5.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/RetailcrmApiErrors.php b/retailcrm/lib/RetailcrmApiErrors.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/RetailcrmApiResponse.php b/retailcrm/lib/RetailcrmApiResponse.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/RetailcrmCatalog.php b/retailcrm/lib/RetailcrmCatalog.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/RetailcrmDaemonCollector.php b/retailcrm/lib/RetailcrmDaemonCollector.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/RetailcrmHistory.php b/retailcrm/lib/RetailcrmHistory.php
index 764388a..7aabe0c 100755
--- a/retailcrm/lib/RetailcrmHistory.php
+++ b/retailcrm/lib/RetailcrmHistory.php
@@ -173,6 +173,7 @@ class RetailcrmHistory
$sinceId = $end['id'];
$statuses = array_flip(array_filter(json_decode(Configuration::get('RETAILCRM_API_STATUS'), true)));
+ $cartStatus = (string)(Configuration::get('RETAILCRM_API_SYNCHRONIZED_CART_STATUS'));
$deliveries = array_flip(array_filter(json_decode(Configuration::get('RETAILCRM_API_DELIVERY'), true)));
$payments = array_flip(array_filter(json_decode(Configuration::get('RETAILCRM_API_PAYMENT'), true)));
$deliveryDefault = json_decode(Configuration::get('RETAILCRM_API_DELIVERY_DEFAULT'), true);
@@ -189,6 +190,10 @@ class RetailcrmHistory
if ($responce) {
$order = $responce['order'];
+
+ if ($order['status'] == $cartStatus) {
+ continue;
+ }
} else {
continue;
}
diff --git a/retailcrm/lib/RetailcrmHistoryHelper.php b/retailcrm/lib/RetailcrmHistoryHelper.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/RetailcrmHttpClient.php b/retailcrm/lib/RetailcrmHttpClient.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/RetailcrmIcml.php b/retailcrm/lib/RetailcrmIcml.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/RetailcrmInventories.php b/retailcrm/lib/RetailcrmInventories.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/RetailcrmProxy.php b/retailcrm/lib/RetailcrmProxy.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/RetailcrmReferences.php b/retailcrm/lib/RetailcrmReferences.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/RetailcrmService.php b/retailcrm/lib/RetailcrmService.php
old mode 100644
new mode 100755
diff --git a/retailcrm/lib/index.php b/retailcrm/lib/index.php
old mode 100644
new mode 100755
diff --git a/retailcrm/logo.gif b/retailcrm/logo.gif
old mode 100644
new mode 100755
diff --git a/retailcrm/logo.png b/retailcrm/logo.png
old mode 100644
new mode 100755
diff --git a/retailcrm/objects.xml b/retailcrm/objects.xml
old mode 100644
new mode 100755
diff --git a/retailcrm/public/css/retailcrm-upload.css b/retailcrm/public/css/retailcrm-upload.css
old mode 100644
new mode 100755
diff --git a/retailcrm/public/js/exec-jobs.js b/retailcrm/public/js/exec-jobs.js
new file mode 100644
index 0000000..cd2fc8d
--- /dev/null
+++ b/retailcrm/public/js/exec-jobs.js
@@ -0,0 +1,6 @@
+(function () {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', '/modules/retailcrm/job/jobs.php', true);
+ xhr.timeout = 0;
+ xhr.send(null);
+})();
\ No newline at end of file
diff --git a/retailcrm/public/js/retailcrm-upload.js b/retailcrm/public/js/retailcrm-upload.js
old mode 100644
new mode 100755
diff --git a/retailcrm/retailcrm.php b/retailcrm/retailcrm.php
index b5758d5..727ad6d 100755
--- a/retailcrm/retailcrm.php
+++ b/retailcrm/retailcrm.php
@@ -31,6 +31,7 @@ class RetailCRM extends Module
public $log;
public $confirmUninstall;
public $reference;
+ public $assetsBase;
private $use_new_hooks = true;
@@ -53,6 +54,12 @@ class RetailCRM extends Module
$this->psVersion = Tools::substr(_PS_VERSION_, 0, 3);
$this->log = _PS_ROOT_DIR_ . '/retailcrm.log';
$this->module_key = '149c765c6cddcf35e1f13ea6c71e9fa5';
+ $this->assetsBase =
+ Tools::getShopDomainSsl(true, true) .
+ __PS_BASE_URI__ .
+ 'modules/' .
+ $this->name .
+ '/public';
if ($this->psVersion == '1.6') {
$this->bootstrap = true;
@@ -84,6 +91,8 @@ class RetailCRM extends Module
public function hookHeader()
{
+ $this->context->controller->addJS($this->assetsBase . '/js/exec-jobs.js');
+
if (Configuration::get('RETAILCRM_DAEMON_COLLECTOR_ACTIVE')
&& Configuration::get('RETAILCRM_DAEMON_COLLECTOR_KEY')
) {
@@ -116,6 +125,8 @@ class RetailCRM extends Module
Configuration::deleteByName('RETAILCRM_LAST_SYNC') &&
Configuration::deleteByName('RETAILCRM_API_VERSION') &&
Configuration::deleteByName('RETAILCRM_LAST_CUSTOMERS_SYNC') &&
+ Configuration::deleteByName('RETAILCRM_API_SYNCHRONIZE_CARTS') &&
+ Configuration::deleteByName('RETAILCRM_API_SYNCHRONIZED_CART_STATUS') &&
Configuration::deleteByName('RETAILCRM_LAST_ORDERS_SYNC');
}
@@ -144,12 +155,17 @@ class RetailCRM extends Module
$collectorActive = (Tools::getValue('RETAILCRM_DAEMON_COLLECTOR_ACTIVE_1'));
$collectorKey = (string)(Tools::getValue('RETAILCRM_DAEMON_COLLECTOR_KEY'));
$clientId = Configuration::get('RETAILCRM_CLIENT_ID');
+ $synchronizeCartsActive = (Tools::getValue('RETAILCRM_API_SYNCHRONIZE_CARTS_1'));
+ $synchronizedCartStatus = (string)(Tools::getValue('RETAILCRM_API_SYNCHRONIZED_CART_STATUS'));
$settings = array(
'address' => $address,
'token' => $token,
'version' => $version,
- 'clientId' => $clientId
+ 'clientId' => $clientId,
+ 'status' => $status,
+ 'statusExport' => $statusExport,
+ 'synchronizeCartStatus' => $synchronizedCartStatus
);
$output .= $this->validateForm($settings, $output);
@@ -166,6 +182,8 @@ class RetailCRM extends Module
Configuration::updateValue('RETAILCRM_STATUS_EXPORT', $statusExport);
Configuration::updateValue('RETAILCRM_DAEMON_COLLECTOR_ACTIVE', $collectorActive);
Configuration::updateValue('RETAILCRM_DAEMON_COLLECTOR_KEY', $collectorKey);
+ Configuration::updateValue('RETAILCRM_API_SYNCHRONIZE_CARTS', $synchronizeCartsActive);
+ Configuration::updateValue('RETAILCRM_API_SYNCHRONIZED_CART_STATUS', $synchronizedCartStatus);
$output .= $this->displayConfirmation($this->l('Settings updated'));
}
@@ -189,14 +207,9 @@ class RetailCRM extends Module
"$address/admin/settings#t-main"
);
- $assetsBase =
- Tools::getShopDomainSsl(true, true) .
- __PS_BASE_URI__ .
- 'modules/' .
- $this->name .
- '/public';
- $this->context->controller->addCSS($assetsBase . '/css/retailcrm-upload.css');
- $this->context->controller->addJS($assetsBase . '/js/retailcrm-upload.js');
+ $this->context->controller->addCSS($this->assetsBase . '/css/retailcrm-upload.css');
+ $this->context->controller->addJS($this->assetsBase . '/js/retailcrm-upload.js');
+ $this->context->controller->addJS($this->assetsBase . '/js/exec-jobs.js');
$this->display(__FILE__, 'retailcrm.tpl');
return $output . $this->displaySettingsForm() . $this->displayUploadOrdersForm();
@@ -278,7 +291,45 @@ class RetailCRM extends Module
*/
public static function verifyDate($date, $format = "Y-m-d")
{
- return (bool)date_create_from_format($format, $date);
+ return $date !== "0000-00-00" && (bool)date_create_from_format($format, $date);
+ }
+
+ /**
+ * Build array with order data for retailCRM from PrestaShop cart data
+ *
+ * @param Cart $cart Cart with data
+ * @param string $externalId External ID for order
+ * @param string $paymentType Payment type (buildCrmOrder requires it)
+ * @param string $status Status for order
+ *
+ * @return array
+ */
+ public static function buildCrmOrderFromCart(Cart $cart = null, $externalId = '', $paymentType = '', $status = '')
+ {
+ if (empty($cart) || empty($paymentType) || empty($status)) {
+ return array();
+ }
+
+ $order = new Order();
+ $order->id_cart = $cart->id;
+ $order->id_customer = $cart->id_customer;
+ $order->total_discounts = 0;
+ $order->module = $paymentType;
+ $order->payment = $paymentType;
+ $orderData = static::buildCrmOrder(
+ $order,
+ new Customer($cart->id_customer),
+ $cart,
+ false,
+ true,
+ true
+ );
+ $orderData['externalId'] = $externalId;
+ $orderData['status'] = $status;
+
+ unset($orderData['payments']);
+
+ return $orderData;
}
/**
@@ -289,6 +340,7 @@ class RetailCRM extends Module
* @param Cart $orderCart Cart for provided order. Optional
* @param bool $isStatusExport Use status for export
* @param bool $preferCustomerAddress Use customer address even if delivery address is provided
+ * @param bool $dataFromCart Prefer data from cart
*
* @return array retailCRM order data
*/
@@ -297,7 +349,8 @@ class RetailCRM extends Module
Customer $customer = null,
Cart $orderCart = null,
$isStatusExport = false,
- $preferCustomerAddress = false
+ $preferCustomerAddress = false,
+ $dataFromCart = false
) {
$apiVersion = Configuration::get('RETAILCRM_API_VERSION');
$statusExport = Configuration::get('RETAILCRM_STATUS_EXPORT');
@@ -357,6 +410,10 @@ class RetailCRM extends Module
return $v->id_customer == $customer->id;
}
);
+
+ if (is_array($address) && count($address) == 1) {
+ $address = reset($address);
+ }
}
$address = static::addressParse($address);
@@ -388,16 +445,34 @@ class RetailCRM extends Module
$crmOrder['payments'] = array();
}
- if (array_key_exists($order->id_carrier, $delivery) && !empty($delivery[$order->id_carrier])) {
- $crmOrder['delivery']['code'] = $delivery[$order->id_carrier];
+ $idCarrier = $dataFromCart ? $cart->id_carrier : $order->id_carrier;
+
+ if (empty($idCarrier)) {
+ $idCarrier = $order->id_carrier;
+ $totalShipping = $order->total_shipping;
+ $totalShippingWithoutTax = $order->total_shipping_tax_excl;
+ } else {
+ $totalShipping = $dataFromCart ? $cart->getCarrierCost($idCarrier) : $order->total_shipping;
+
+ if (!empty($totalShipping) && $totalShipping != 0) {
+ $totalShippingWithoutTax = $dataFromCart
+ ? $totalShipping - $cart->getCarrierCost($idCarrier, false)
+ : $order->total_shipping_tax_excl;
+ } else {
+ $totalShippingWithoutTax = $order->total_shipping_tax_excl;
+ }
}
- if (isset($order->total_shipping) && ((int) $order->total_shipping) > 0) {
- $crmOrder['delivery']['cost'] = round($order->total_shipping, 2);
+ if (array_key_exists($idCarrier, $delivery) && !empty($delivery[$idCarrier])) {
+ $crmOrder['delivery']['code'] = $delivery[$idCarrier];
}
- if (isset($order->total_shipping_tax_excl) && $order->total_shipping_tax_excl > 0) {
- $crmOrder['delivery']['netCost'] = round($order->total_shipping_tax_excl, 2);
+ if (isset($totalShipping) && ((int) $totalShipping) > 0) {
+ $crmOrder['delivery']['cost'] = round($totalShipping, 2);
+ }
+
+ if (isset($totalShippingWithoutTax) && $totalShippingWithoutTax > 0) {
+ $crmOrder['delivery']['netCost'] = round($totalShippingWithoutTax, 2);
}
$comment = $order->getFirstMessage();
@@ -406,7 +481,30 @@ class RetailCRM extends Module
$crmOrder['customerComment'] = $comment;
}
- foreach ($order->getProducts() as $product) {
+ if ($dataFromCart) {
+ $productStore = $cart;
+ $converter = function ($product) {
+ $product['product_attribute_id'] = $product['id_product_attribute'];
+ $product['product_quantity'] = $product['cart_quantity'];
+ $product['product_id'] = $product['id_product'];
+ $product['id_order_detail'] = $product['id_product'];
+ $product['product_name'] = $product['name'];
+ $product['product_price'] = $product['price'];
+ $product['purchase_supplier_price'] = $product['price'];
+ $product['product_price_wt'] = $product['price_wt'];
+
+ return $product;
+ };
+ } else {
+ $productStore = $order;
+ $converter = function ($product) {
+ return $product;
+ };
+ }
+
+ foreach ($productStore->getProducts() as $productData) {
+ $product = $converter($productData);
+
if (isset($product['product_attribute_id']) && $product['product_attribute_id'] > 0) {
$productId = $product['product_id'] . '#' . $product['product_attribute_id'];
} else {
@@ -605,6 +703,43 @@ class RetailCRM extends Module
);
if ($this->api) {
+ /*
+ * Synchronize carts form
+ */
+ if ($this->use_new_hooks) {
+ $fields_form[]['form'] = array(
+ 'legend' => array(
+ 'title' => $this->l('Synchronization of buyer carts'),
+ ),
+ 'input' => array(
+ array(
+ 'type' => 'checkbox',
+ 'label' => $this->l('Create orders for abandoned carts of buyers'),
+ 'name' => 'RETAILCRM_API_SYNCHRONIZE_CARTS',
+ 'values' => array(
+ 'query' => array(
+ array(
+ 'id_option' => 1,
+ )
+ ),
+ 'id' => 'id_option',
+ 'name' => 'name'
+ )
+ ),
+ array(
+ 'type' => 'select',
+ 'name' => 'RETAILCRM_API_SYNCHRONIZED_CART_STATUS',
+ 'label' => $this->l('Order status for abandoned carts of buyers'),
+ 'options' => array(
+ 'query' => $this->reference->getStatuseDefaultExport(),
+ 'id' => 'id_option',
+ 'name' => 'name'
+ )
+ )
+ )
+ );
+ }
+
/*
* Delivery
*/
@@ -698,6 +833,8 @@ class RetailCRM extends Module
$helper->fields_value['RETAILCRM_API_VERSION'] = Configuration::get('RETAILCRM_API_VERSION');
$helper->fields_value['RETAILCRM_STATUS_EXPORT'] = Configuration::get('RETAILCRM_STATUS_EXPORT');
$helper->fields_value['RETAILCRM_DAEMON_COLLECTOR_ACTIVE_1'] = Configuration::get('RETAILCRM_DAEMON_COLLECTOR_ACTIVE');
+ $helper->fields_value['RETAILCRM_API_SYNCHRONIZE_CARTS_1'] = Configuration::get('RETAILCRM_API_SYNCHRONIZE_CARTS');
+ $helper->fields_value['RETAILCRM_API_SYNCHRONIZED_CART_STATUS'] = Configuration::get('RETAILCRM_API_SYNCHRONIZED_CART_STATUS');
$helper->fields_value['RETAILCRM_DAEMON_COLLECTOR_KEY'] = Configuration::get('RETAILCRM_DAEMON_COLLECTOR_KEY');
$deliverySettings = Configuration::get('RETAILCRM_API_DELIVERY');
@@ -751,6 +888,17 @@ class RetailCRM extends Module
}
}
+ if ($this->use_new_hooks) {
+ $synchronizedCartsStatusDefault = Configuration::get('RETAILCRM_API_SYNCHRONIZED_CART_STATUS');
+ if (isset($synchronizedCartsStatusDefault) && $synchronizedCartsStatusDefault != '') {
+ $synchronizedCartsStatus = json_decode($synchronizedCartsStatusDefault);
+ if ($synchronizedCartsStatus) {
+ $name = 'RETAILCRM_API_SYNCHRONIZED_CART_STATUS';
+ $helper->fields_value[$name] = $synchronizedCartsStatus;
+ }
+ }
+ }
+
return $helper->generateForm($fields_form);
}
@@ -1036,9 +1184,15 @@ class RetailCRM extends Module
if (isset($params['orderStatus'])) {
$cart = $params['cart'];
- $order = static::buildCrmOrder($params['order'], $params['customer'], $params['cart'], false);
+ $response = $this->api->ordersGet(self::getCartOrderExternalId($cart));
+ $order = static::buildCrmOrder($params['order'], $params['customer'], $cart, false);
- $this->api->ordersCreate($order);
+ if (!empty($response) && isset($response['order'])) {
+ $order['id'] = $response['order']['id'];
+ $this->api->ordersEdit($order, 'id');
+ } else {
+ $this->api->ordersCreate($order);
+ }
return true;
@@ -1159,6 +1313,15 @@ class RetailCRM extends Module
return false;
}
+ private function validateStatuses($statuses, $statusExport, $cartStatus)
+ {
+ if ($cartStatus == $statusExport || (stripos($statuses, $cartStatus) !== false)) {
+ return false;
+ }
+
+ return true;
+ }
+
private function validateForm($settings, $output)
{
if (!$this->validateCrmAddress($settings['address']) || !Validate::isGenericName($settings['address'])) {
@@ -1167,11 +1330,29 @@ class RetailCRM extends Module
$output .= $this->displayError($this->l('Invalid or empty crm api token'));
} elseif (!$this->validateApiVersion($settings)) {
$output .= $this->displayError($this->l('The selected version of the API is unavailable'));
+ } elseif (!$this->validateStatuses(
+ $settings['status'],
+ $settings['statusExport'],
+ $settings['synchronizeCartStatus'])
+ ) {
+ $output .= $this->displayError($this->l('Order status for abandoned carts should not be used in other settings'));
}
return $output;
}
+ /**
+ * Returns externalId for order
+ *
+ * @param Cart $cart
+ *
+ * @return string
+ */
+ public static function getCartOrderExternalId(Cart $cart)
+ {
+ return sprintf('pscart_%d', $cart->id);
+ }
+
/**
* Activate/deactivate module in marketplace retailCRM
*
diff --git a/retailcrm/translations/es.php b/retailcrm/translations/es.php
old mode 100644
new mode 100755
index 6db2eca..43e037f
--- a/retailcrm/translations/es.php
+++ b/retailcrm/translations/es.php
@@ -61,4 +61,8 @@ $_MODULE['<{retailcrm}prestashop>retailcrm_acfa058ec9e6e4745eddc0cae3f0f881'] =
$_MODULE['<{retailcrm}prestashop>retailcrm_91412465ea9169dfd901dd5e7c96dd99'] = 'Exportar';
$_MODULE['<{retailcrm}prestashop>retailcrm_6bd461d1fc51b3294c6513cecc24758d'] = 'Los pedidos han sido cargados con éxito';
$_MODULE['<{retailcrm}prestashop>retailcrm_3518f7b8d79f91da4c91772b4c46db94'] = 'No se han podido cargar algunos pedidos';
-$_MODULE['<{retailcrm}prestashop>retailcrm_9a7fc06b4b2359f1f26f75fbbe27a3e8'] = 'No todos los pedidos se han cargado con existo';
\ No newline at end of file
+$_MODULE['<{retailcrm}prestashop>retailcrm_9a7fc06b4b2359f1f26f75fbbe27a3e8'] = 'No todos los pedidos se han cargado con existo';
+$_MODULE['<{retailcrm}prestashop>retailcrm_917afe348e09163269225a89a825e634'] = 'Sincronización de carritos de compradores';
+$_MODULE['<{retailcrm}prestashop>retailcrm_d8e002d770b6f98af7b7ae9a0e5acfe9'] = 'Crear pedidos para carritos abandonados de compradores';
+$_MODULE['<{retailcrm}prestashop>retailcrm_35b5a9139a54caeb925556ceb2c38086'] = 'Estado del pedido para carritos abandonados de compradores';
+$_MODULE['<{retailcrm}prestashop>retailcrm_b9c4e8fe56eabcc4c7913ebb2f8eb388'] = 'Estado del pedido para carritos abandonados no debe ser utilizado en otros ajustes';
\ No newline at end of file
diff --git a/retailcrm/translations/index.php b/retailcrm/translations/index.php
old mode 100644
new mode 100755
diff --git a/retailcrm/translations/ru.php b/retailcrm/translations/ru.php
old mode 100644
new mode 100755
index 1f0def2..a2136b1
--- a/retailcrm/translations/ru.php
+++ b/retailcrm/translations/ru.php
@@ -61,4 +61,8 @@ $_MODULE['<{retailcrm}prestashop>retailcrm_acfa058ec9e6e4745eddc0cae3f0f881'] =
$_MODULE['<{retailcrm}prestashop>retailcrm_91412465ea9169dfd901dd5e7c96dd99'] = 'Выгрузить';
$_MODULE['<{retailcrm}prestashop>retailcrm_6bd461d1fc51b3294c6513cecc24758d'] = 'Все заказы успешно загружены';
$_MODULE['<{retailcrm}prestashop>retailcrm_3518f7b8d79f91da4c91772b4c46db94'] = 'Некоторые заказы не удалось загрузить';
-$_MODULE['<{retailcrm}prestashop>retailcrm_9a7fc06b4b2359f1f26f75fbbe27a3e8'] = 'Не все заказы загружены успешно';
\ No newline at end of file
+$_MODULE['<{retailcrm}prestashop>retailcrm_9a7fc06b4b2359f1f26f75fbbe27a3e8'] = 'Не все заказы загружены успешно';
+$_MODULE['<{retailcrm}prestashop>retailcrm_917afe348e09163269225a89a825e634'] = 'Синхронизация корзин покупателей';
+$_MODULE['<{retailcrm}prestashop>retailcrm_d8e002d770b6f98af7b7ae9a0e5acfe9'] = 'Создавать заказы для брошенных корзин покупателей';
+$_MODULE['<{retailcrm}prestashop>retailcrm_35b5a9139a54caeb925556ceb2c38086'] = 'Статус заказа для брошенных корзин покупателей';
+$_MODULE['<{retailcrm}prestashop>retailcrm_b9c4e8fe56eabcc4c7913ebb2f8eb388'] = 'Статус заказа для брошенных корзин не должен использоваться в других настройках';
\ No newline at end of file