-
-
+
+
+
-
+
-
-
-
+
+
+
-
+
-
+
$value): ?>
-
-
-
\ No newline at end of file
+
diff --git a/catalog/model/intarocrm/order.php b/catalog/model/intarocrm/order.php
deleted file mode 100644
index 8779f66..0000000
--- a/catalog/model/intarocrm/order.php
+++ /dev/null
@@ -1,19 +0,0 @@
-load->model('setting/setting');
- $settings = $this->model_setting_setting->getSetting('intarocrm');
- $settings['domain'] = parse_url(HTTP_SERVER, PHP_URL_HOST);
-
- if(isset($settings['intarocrm_url']) && $settings['intarocrm_url'] != '' && isset($settings['intarocrm_apikey']) && $settings['intarocrm_apikey'] != '') {
- include_once DIR_SYSTEM . 'library/intarocrm/apihelper.php';
- $order['order_id'] = $order_id;
- $crm = new ApiHelper($settings);
- $crm->processOrder($order);
- }
-
- }
-}
-?>
\ No newline at end of file
diff --git a/catalog/model/retailcrm/order.php b/catalog/model/retailcrm/order.php
new file mode 100644
index 0000000..e021e30
--- /dev/null
+++ b/catalog/model/retailcrm/order.php
@@ -0,0 +1,97 @@
+load->model('setting/setting');
+ $settings = $this->model_setting_setting->getSetting('retailcrm');
+
+ if(!empty($settings['retailcrm_url']) && !empty($settings['retailcrm_apikey'])) {
+ require_once DIR_SYSTEM . 'library/retailcrm/bootstrap.php';
+
+ $this->retailcrm = new RetailcrmProxy(
+ $settings['retailcrm_url'],
+ $settings['retailcrm_apikey'],
+ DIR_SYSTEM . 'logs/retailcrm.log'
+ );
+
+ $order = array();
+
+ $payment_code = $order_data['payment_code'];
+ $delivery_code = $order_data['shipping_code'];
+
+ $customers = $this->retailcrm->customersList(
+ array(
+ 'name' => $order_data['telephone'],
+ 'email' => $order_data['email']
+ ),
+ 1,
+ 100
+ );
+
+ foreach($customers['customers'] as $customer) {
+ $order['customer']['id'] = $customer['id'];
+ }
+
+ unset($customers);
+
+ $order['externalId'] = $order_id;
+ $order['firstName'] = $order_data['firstname'];
+ $order['lastName'] = $order_data['lastname'];
+ $order['email'] = $order_data['email'];
+ $order['phone'] = $order_data['telephone'];
+ $order['customerComment'] = $order_data['comment'];
+
+ $deliveryCost = 0;
+ $orderTotals = isset($order_data['totals']) ? $order_data['totals'] : $order_data['order_total'] ;
+
+ foreach ($orderTotals as $totals) {
+ if ($totals['code'] == 'shipping') {
+ $deliveryCost = $totals['value'];
+ }
+ }
+
+ $order['createdAt'] = date('Y-m-d H:i:s');
+ $order['paymentType'] = $settings['retailcrm_payment'][$payment_code];
+
+ $country = (isset($order_data['shipping_country'])) ? $order_data['shipping_country'] : '' ;
+
+ $order['delivery'] = array(
+ 'code' => $settings['retailcrm_delivery'][$delivery_code],
+ 'cost' => $deliveryCost,
+ 'address' => array(
+ 'index' => $order_data['shipping_postcode'],
+ 'city' => $order_data['shipping_city'],
+ 'country' => $order_data['shipping_country_id'],
+ 'region' => $order_data['shipping_zone_id'],
+ 'text' => implode(', ', array(
+ $order_data['shipping_postcode'],
+ $country,
+ $order_data['shipping_city'],
+ $order_data['shipping_address_1'],
+ $order_data['shipping_address_2']
+ ))
+ )
+ );
+
+ $orderProducts = isset($order_data['products']) ? $order_data['products'] : $order_data['order_product'];
+
+ foreach ($orderProducts as $product) {
+ $order['items'][] = array(
+ 'productId' => $product['product_id'],
+ 'productName' => $product['name'],
+ 'initialPrice' => $product['price'],
+ 'quantity' => $product['quantity'],
+ );
+ }
+
+ if (isset($order_data['order_status_id'])) {
+ $order['status'] = $settings['retailcrm_status'][$order_data['order_status_id']];
+ }
+
+ $this->retailcrm->ordersCreate($order);
+ }
+ }
+}
+
diff --git a/cli/cli_export.php b/cli/cli_export.php
deleted file mode 100644
index f07aa2e..0000000
--- a/cli/cli_export.php
+++ /dev/null
@@ -1,3 +0,0 @@
- Intstall module. Before running exchange you must configure module.
-
-### Export
-
-Setup cron job for periodically catalog export
-
-```
-* */12 * * * /usr/bin/php /path/to/opencart/cli/cli_export.php >> /path/to/opencart/system/logs/cronjob_export.log 2>&1
-```
-
-Into your CRM settings set path to exported file
-
-```
-/download/intarocrm.xml
-```
-
-### Exchange setup
-
-
-#### Export new order from shop to CRM
-
-```
-$this->load->model('intarocrm/order');
-$this->model_intarocrm_order->send($data, $order_id);
-```
-
-Add this lines into:
-* /catalog/model/checkout/order.php script, into addOrder method before return statement
-
-```
-if (!isset($data['fromApi'])) {
- $this->load->model('setting/setting');
- $status = $this->model_setting_setting->getSetting('intarocrm');
- $data['order_status'] = $status['intarocrm_status'][$data['order_status_id']];
-
- $this->load->model('intarocrm/order');
- $this->model_intarocrm_order->send($data, $order_id);
-}
-```
-
-Add this lines into:
-* /admin/model/sale/order.php script, into addOrder & editOrder methods at the end of these methods
-
-#### Export new order from CRM to shop
-
-Setup cron job for exchange between CRM & your shop
-
-```
-*/5 * * * * /usr/bin/php /path/to/opencart/cli/cli_history.php >> /path/to/opencart/system/logs/cronjob_history.log 2>&1
-```
diff --git a/doc/TODO.md b/doc/TODO.md
deleted file mode 100644
index 32dce71..0000000
--- a/doc/TODO.md
+++ /dev/null
@@ -1,6 +0,0 @@
-TODO
-====
-
-* Export old customers & orders
-* New customers export
-* Make sources PSR-2 compatible
\ No newline at end of file
diff --git a/cli/cli_dispatch.php b/system/cron/dispatch.php
similarity index 94%
rename from cli/cli_dispatch.php
rename to system/cron/dispatch.php
index 8baa5e4..1c756ed 100644
--- a/cli/cli_dispatch.php
+++ b/system/cron/dispatch.php
@@ -1,12 +1,5 @@
write("ERROR: cli $cli_action call attempted by non-cli.");
- http_response_code(400);
- exit;
-}
-
// Ensure $cli_action is set
if (!isset($cli_action)) {
echo 'ERROR: $cli_action must be set in calling script.';
@@ -19,7 +12,7 @@ if (!isset($cli_action)) {
define('VERSION', '1.5.6');
// Configuration (note we're using the admin config)
-require_once(__DIR__ . '/../admin/config.php');
+require_once(realpath(dirname(__FILE__)) . '/../../admin/config.php');
// Configuration check
if (!defined('DIR_APPLICATION')) {
@@ -138,4 +131,3 @@ $controller->dispatch($action, new Action('error/not_found'));
// Output
$response->output();
-?>
\ No newline at end of file
diff --git a/system/cron/export.php b/system/cron/export.php
new file mode 100644
index 0000000..85d7d82
--- /dev/null
+++ b/system/cron/export.php
@@ -0,0 +1,3 @@
+dir = __DIR__ . '/../../logs/';
- $this->fileDate = $this->dir . 'intarocrm_history.log';
- $this->settings = $settings;
- $this->domain = $settings['domain'];
-
- $this->log = new Monolog\Logger('intarocrm');
- $this->log->pushHandler(
- new Monolog\Handler\StreamHandler($this->dir . 'intarocrm_module.log', Monolog\Logger::INFO)
- );
-
- $this->intaroApi = new IntaroCrm\RestApi(
- $settings['intarocrm_url'],
- $settings['intarocrm_apikey']
- );
- }
-
- public function processOrder($data) {
-
- $order = array();
- $customer = array();
- $customers = array();
-
- $payment_code = $data['payment_code'];
- $delivery_code = $data['shipping_code'];
- $settings = $this->settings;
-
- try {
- $customers = $this->intaroApi->customers($data['telephone'], $data['email'], $data['lastname'], 200, 0);
- } catch (IntaroCrm\Exception\ApiException $e) {
- $this->log->addError('['.$this->domain.'] RestApi::customers:' . $e->getMessage());
- $this->log->addError('['.$this->domain.'] RestApi::customers:' . json_encode($data));
- } catch (IntaroCrm\Exception\CurlException $e) {
- $this->log->addError('['.$this->domain.'] RestApi::customers::Curl:' . $e->getMessage());
- }
-
-
- if(count($customers) > 0 && isset($customers[0]['externalId'])) {
- $order['customerId'] = $customers[0]['externalId'];
- } else {
- $order['customerId'] = ($data['customer_id'] != '') ? $data['customer_id'] : (int) substr((microtime(true) * 10000) . mt_rand(1, 1000), 10, -1);
- $customer['externalId'] = $order['customerId'];
- $customer['firstName'] = $data['firstname'];
- $customer['lastName'] = $data['lastname'];
- $customer['email'] = $data['email'];
- $customer['phones'] = array(array('number' => $data['telephone']));
-
- $customer['address']['country'] = $data['payment_country_id'];
- $customer['address']['region'] = $data['payment_zone_id'];
-
- $customer['address']['text'] = implode(', ', array(
- $data['payment_postcode'],
- $data['payment_country'],
- $data['payment_city'],
- $data['payment_address_1'],
- $data['payment_address_2']
- ));
-
- try {
- $this->customer = $this->intaroApi->customerEdit($customer);
- } catch (IntaroCrm\Exception\ApiException $e) {
- $this->customer = $e->getMessage();
- $this->log->addError('['.$this->domain.'] RestApi::orderCreate:' . $e->getMessage());
- $this->log->addError('['.$this->domain.'] RestApi::orderCreate:' . json_encode($order));
- } catch (IntaroCrm\Exception\CurlException $e) {
- $this->customer = $e->getMessage();
- $this->log->addError('['.$this->domain.'] RestApi::orderCreate::Curl:' . $e->getMessage());
- }
- }
-
- unset($customer);
- unset($customers);
-
- $order['externalId'] = $data['order_id'];
- $order['firstName'] = $data['firstname'];
- $order['lastName'] = $data['lastname'];
- $order['email'] = $data['email'];
- $order['phone'] = $data['telephone'];
- $order['customerComment'] = $data['comment'];
-
- $deliveryCost = 0;
- $orderTotals = isset($data['totals']) ? $data['totals'] : $data['order_total'] ;
-
- foreach ($orderTotals as $totals) {
- if ($totals['code'] == 'shipping') {
- $deliveryCost = $totals['value'];
- }
- }
-
- $order['createdAt'] = date('Y-m-d H:i:s');
- $order['paymentType'] = $settings['intarocrm_payment'][$payment_code];
-
- $country = (isset($data['shipping_country'])) ? $data['shipping_country'] : '' ;
-
- $order['delivery'] = array(
- 'code' => $settings['intarocrm_delivery'][$delivery_code],
- 'cost' => $deliveryCost,
- 'address' => array(
- 'index' => $data['shipping_postcode'],
- 'city' => $data['shipping_city'],
- 'country' => $data['shipping_country_id'],
- 'region' => $data['shipping_zone_id'],
- 'text' => implode(', ', array(
- $data['shipping_postcode'],
- $country,
- $data['shipping_city'],
- $data['shipping_address_1'],
- $data['shipping_address_2']
- ))
- )
- );
-
- $orderProducts = isset($data['products']) ? $data['products'] : $data['order_product'];
-
- foreach ($orderProducts as $product) {
- $order['items'][] = array(
- 'productId' => $product['product_id'],
- 'productName' => $product['name'],
- 'initialPrice' => $product['price'],
- 'quantity' => $product['quantity'],
- );
- }
-
- if (isset($data['order_status_id'])) {
- $order['status'] = $data['order_status'];
- }
-
- try {
- $this->intaroApi->orderEdit($order);
- } catch (IntaroCrm\Exception\ApiException $e) {
- $this->log->addError('['.$this->domain.'] RestApi::orderCreate:' . $e->getMessage());
- $this->log->addError('['.$this->domain.'] RestApi::orderCreate:' . json_encode($order));
- } catch (IntaroCrm\Exception\CurlException $e) {
- $this->log->addError('['.$this->domain.'] RestApi::orderCreate::Curl:' . $e->getMessage());
- }
- }
-
- public function orderHistory() {
-
- $orders = array();
-
- try {
- $orders = $this->intaroApi->orderHistory($this->getDate());
- $this->saveDate($this->intaroApi->getGeneratedAt()->format('Y-m-d H:i:s'));
- } catch (IntaroCrm\Exception\ApiException $e) {
- $this->log->addError('['.$this->domain.'] RestApi::orderHistory:' . $e->getMessage());
- $this->log->addError('['.$this->domain.'] RestApi::orderHistory:' . json_encode($orders));
-
- return false;
- } catch (IntaroCrm\Exception\CurlException $e) {
- $this->log->addError('['.$this->domain.'] RestApi::orderHistory::Curl:' . $e->getMessage());
-
- return false;
- }
-
- return $orders;
- }
-
- public function orderFixExternalIds($data)
- {
- try {
- return $this->intaroApi->orderFixExternalIds($data);
- } catch (IntaroCrm\Exception\ApiException $e) {
- $this->log->addError('['.$this->domain.'] RestApi::orderFixExternalIds:' . $e->getMessage());
- $this->log->addError('['.$this->domain.'] RestApi::orderFixExternalIds:' . json_encode($data));
-
- return false;
- } catch (IntaroCrm\Exception\CurlException $e) {
- $this->log->addError('['.$this->domain.'] RestApi::orderFixExternalIds::Curl:' . $e->getMessage());
-
- return false;
- }
- }
-
- public function customerFixExternalIds($data)
- {
- try {
- return $this->intaroApi->customerFixExternalIds($data);
- } catch (IntaroCrm\Exception\ApiException $e) {
- $this->log->addError('['.$this->domain.'] RestApi::customerFixExternalIds:' . $e->getMessage());
- $this->log->addError('['.$this->domain.'] RestApi::customerFixExternalIds:' . json_encode($data));
-
- return false;
- } catch (IntaroCrm\Exception\CurlException $e) {
- $this->log->addError('['.$this->domain.'] RestApi::customerFixExternalIds::Curl:' . $e->getMessage());
-
- return false;
- }
- }
-
- public function getOrder($order_id)
- {
- try {
- return $this->intaroApi->orderGet($order_id);
- } catch (IntaroCrm\Exception\ApiException $e) {
- $this->log->addError('['.$this->domain.'] RestApi::orderFixExternalIds:' . $e->getMessage());
- $this->log->addError('['.$this->domain.'] RestApi::orderFixExternalIds:' . json_encode($order));
-
- return false;
- } catch (IntaroCrm\Exception\CurlException $e) {
- $this->log->addError('['.$this->domain.'] RestApi::orderFixExternalIds::Curl:' . $e->getMessage());
-
- return false;
- }
-
- }
-
- private function saveDate($date) {
- file_put_contents($this->fileDate, $date, LOCK_EX);
- }
-
- private function getDate() {
- if (file_exists($this->fileDate)) {
- $result = file_get_contents($this->fileDate);
- } else {
- $result = date('Y-m-d H:i:s', strtotime('-2 days', strtotime(date('Y-m-d H:i:s'))));
- }
-
- return $result;
- }
-
-}
diff --git a/system/library/intarocrm/composer.json b/system/library/intarocrm/composer.json
deleted file mode 100644
index 18ae32f..0000000
--- a/system/library/intarocrm/composer.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "name": "retailcrm/opencart-module",
- "description": "Opencart integration for IntaroCRM",
- "type": "library",
- "keywords": ["api", "Intaro CRM", "rest"],
- "homepage": "http://www.retailcrm.ru/",
- "authors": [
- {
- "name": "Alex Lushpai",
- "email": "lushpai@intaro.ru",
- "role": "Developer"
- }
- ],
- "support": {
- "email": "support@intarocrm.ru"
- },
- "require": {
- "php": ">=5.3",
- "retailcrm/api-client-php": "1.3.*",
- "symfony/console": "2.6.*",
- "monolog/monolog": "1.12.*"
- },
- "autoload": {
- "psr-0": {
- "": "/"
- }
- }
-}
diff --git a/system/library/intarocrm/composer.phar b/system/library/intarocrm/composer.phar
deleted file mode 100755
index aa9c50d..0000000
Binary files a/system/library/intarocrm/composer.phar and /dev/null differ
diff --git a/system/library/retailcrm/CurlException.php b/system/library/retailcrm/CurlException.php
new file mode 100644
index 0000000..2ab00f5
--- /dev/null
+++ b/system/library/retailcrm/CurlException.php
@@ -0,0 +1,5 @@
+client = new RetailcrmHttpClient($url, array('apiKey' => $apiKey));
+ $this->siteCode = $site;
+ }
+
+ /**
+ * Create a order
+ *
+ * @param array $order
+ * @param string $site (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function ordersCreate(array $order, $site = null)
+ {
+ if (!sizeof($order)) {
+ throw new InvalidArgumentException('Parameter `order` must contains a data');
+ }
+
+ return $this->client->makeRequest("/orders/create", RetailcrmHttpClient::METHOD_POST, $this->fillSite($site, array(
+ 'order' => json_encode($order)
+ )));
+ }
+
+ /**
+ * Edit a order
+ *
+ * @param array $order
+ * @param string $by
+ * @param string $site (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function ordersEdit(array $order, $by = 'externalId', $site = null)
+ {
+ if (!sizeof($order)) {
+ throw new InvalidArgumentException('Parameter `order` must contains a data');
+ }
+
+ $this->checkIdParameter($by);
+
+ if (!isset($order[$by])) {
+ throw new InvalidArgumentException(sprintf('Order array must contain the "%s" parameter.', $by));
+ }
+
+ return $this->client->makeRequest(
+ "/orders/" . $order[$by] . "/edit",
+ RetailcrmHttpClient::METHOD_POST,
+ $this->fillSite($site, array(
+ 'order' => json_encode($order),
+ 'by' => $by,
+ ))
+ );
+ }
+
+ /**
+ * Upload array of the orders
+ *
+ * @param array $orders
+ * @param string $site (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function ordersUpload(array $orders, $site = null)
+ {
+ if (!sizeof($orders)) {
+ throw new InvalidArgumentException('Parameter `orders` must contains array of the orders');
+ }
+
+ return $this->client->makeRequest("/orders/upload", RetailcrmHttpClient::METHOD_POST, $this->fillSite($site, array(
+ 'orders' => json_encode($orders),
+ )));
+ }
+
+ /**
+ * Get order by id or externalId
+ *
+ * @param string $id
+ * @param string $by (default: 'externalId')
+ * @param string $site (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function ordersGet($id, $by = 'externalId', $site = null)
+ {
+ $this->checkIdParameter($by);
+
+ return $this->client->makeRequest("/orders/$id", RetailcrmHttpClient::METHOD_GET, $this->fillSite($site, array(
+ 'by' => $by
+ )));
+ }
+
+ /**
+ * Returns a orders history
+ *
+ * @param DateTime $startDate (default: null)
+ * @param DateTime $endDate (default: null)
+ * @param int $limit (default: 100)
+ * @param int $offset (default: 0)
+ * @param bool $skipMyChanges (default: true)
+ * @return RetailcrmApiResponse
+ */
+ public function ordersHistory(
+ DateTime $startDate = null,
+ DateTime $endDate = null,
+ $limit = 100,
+ $offset = 0,
+ $skipMyChanges = true
+ ) {
+ $parameters = array();
+
+ if ($startDate) {
+ $parameters['startDate'] = $startDate->format('Y-m-d H:i:s');
+ }
+ if ($endDate) {
+ $parameters['endDate'] = $endDate->format('Y-m-d H:i:s');
+ }
+ if ($limit) {
+ $parameters['limit'] = (int) $limit;
+ }
+ if ($offset) {
+ $parameters['offset'] = (int) $offset;
+ }
+ if ($skipMyChanges) {
+ $parameters['skipMyChanges'] = (bool) $skipMyChanges;
+ }
+
+ return $this->client->makeRequest('/orders/history', RetailcrmHttpClient::METHOD_GET, $parameters);
+ }
+
+ /**
+ * Returns filtered orders list
+ *
+ * @param array $filter (default: array())
+ * @param int $page (default: null)
+ * @param int $limit (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function ordersList(array $filter = array(), $page = null, $limit = null)
+ {
+ $parameters = array();
+
+ if (sizeof($filter)) {
+ $parameters['filter'] = $filter;
+ }
+ if (null !== $page) {
+ $parameters['page'] = (int) $page;
+ }
+ if (null !== $limit) {
+ $parameters['limit'] = (int) $limit;
+ }
+
+ return $this->client->makeRequest('/orders', RetailcrmHttpClient::METHOD_GET, $parameters);
+ }
+
+ /**
+ * Returns statuses of the orders
+ *
+ * @param array $ids (default: array())
+ * @param array $externalIds (default: array())
+ * @return RetailcrmApiResponse
+ */
+ public function ordersStatuses(array $ids = array(), array $externalIds = array())
+ {
+ $parameters = array();
+
+ if (sizeof($ids)) {
+ $parameters['ids'] = $ids;
+ }
+ if (sizeof($externalIds)) {
+ $parameters['externalIds'] = $externalIds;
+ }
+
+ return $this->client->makeRequest('/orders/statuses', RetailcrmHttpClient::METHOD_GET, $parameters);
+ }
+
+ /**
+ * Save order IDs' (id and externalId) association in the CRM
+ *
+ * @param array $ids
+ * @return RetailcrmApiResponse
+ */
+ public function ordersFixExternalIds(array $ids)
+ {
+ if (!sizeof($ids)) {
+ throw new InvalidArgumentException('Method parameter must contains at least one IDs pair');
+ }
+
+ return $this->client->makeRequest("/orders/fix-external-ids", RetailcrmHttpClient::METHOD_POST, array(
+ 'orders' => json_encode($ids),
+ ));
+ }
+
+ /**
+ * Get orders assembly history
+ *
+ * @param array $filter (default: array())
+ * @param int $page (default: null)
+ * @param int $limit (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function ordersPacksHistory(array $filter = array(), $page = null, $limit = null)
+ {
+ $parameters = array();
+
+ if (sizeof($filter)) {
+ $parameters['filter'] = $filter;
+ }
+ if (null !== $page) {
+ $parameters['page'] = (int) $page;
+ }
+ if (null !== $limit) {
+ $parameters['limit'] = (int) $limit;
+ }
+
+ return $this->client->makeRequest('/orders/packs/history', RetailcrmHttpClient::METHOD_GET, $parameters);
+ }
+
+ /**
+ * Create a customer
+ *
+ * @param array $customer
+ * @param string $site (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function customersCreate(array $customer, $site = null)
+ {
+ if (!sizeof($customer)) {
+ throw new InvalidArgumentException('Parameter `customer` must contains a data');
+ }
+
+ return $this->client->makeRequest("/customers/create", RetailcrmHttpClient::METHOD_POST, $this->fillSite($site, array(
+ 'customer' => json_encode($customer)
+ )));
+ }
+
+ /**
+ * Edit a customer
+ *
+ * @param array $customer
+ * @param string $by (default: 'externalId')
+ * @param string $site (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function customersEdit(array $customer, $by = 'externalId', $site = null)
+ {
+ if (!sizeof($customer)) {
+ throw new InvalidArgumentException('Parameter `customer` must contains a data');
+ }
+
+ $this->checkIdParameter($by);
+
+ if (!isset($customer[$by])) {
+ throw new InvalidArgumentException(sprintf('Customer array must contain the "%s" parameter.', $by));
+ }
+
+ return $this->client->makeRequest(
+ "/customers/" . $customer[$by] . "/edit",
+ RetailcrmHttpClient::METHOD_POST,
+ $this->fillSite(
+ $site,
+ array(
+ 'customer' => json_encode($customer),
+ 'by' => $by
+ )
+ )
+ );
+ }
+
+ /**
+ * Upload array of the customers
+ *
+ * @param array $customers
+ * @param string $site (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function customersUpload(array $customers, $site = null)
+ {
+ if (!sizeof($customers)) {
+ throw new InvalidArgumentException('Parameter `customers` must contains array of the customers');
+ }
+
+ return $this->client->makeRequest("/customers/upload", RetailcrmHttpClient::METHOD_POST, $this->fillSite($site, array(
+ 'customers' => json_encode($customers),
+ )));
+ }
+
+ /**
+ * Get customer by id or externalId
+ *
+ * @param string $id
+ * @param string $by (default: 'externalId')
+ * @param string $site (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function customersGet($id, $by = 'externalId', $site = null)
+ {
+ $this->checkIdParameter($by);
+
+ return $this->client->makeRequest("/customers/$id", RetailcrmHttpClient::METHOD_GET, $this->fillSite($site, array(
+ 'by' => $by
+ )));
+ }
+
+ /**
+ * Returns filtered customers list
+ *
+ * @param array $filter (default: array())
+ * @param int $page (default: null)
+ * @param int $limit (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function customersList(array $filter = array(), $page = null, $limit = null)
+ {
+ $parameters = array();
+
+ if (sizeof($filter)) {
+ $parameters['filter'] = $filter;
+ }
+ if (null !== $page) {
+ $parameters['page'] = (int) $page;
+ }
+ if (null !== $limit) {
+ $parameters['limit'] = (int) $limit;
+ }
+
+ return $this->client->makeRequest('/customers', RetailcrmHttpClient::METHOD_GET, $parameters);
+ }
+
+ /**
+ * Save customer IDs' (id and externalId) association in the CRM
+ *
+ * @param array $ids
+ * @return RetailcrmApiResponse
+ */
+ public function customersFixExternalIds(array $ids)
+ {
+ if (!sizeof($ids)) {
+ throw new InvalidArgumentException('Method parameter must contains at least one IDs pair');
+ }
+
+ return $this->client->makeRequest("/customers/fix-external-ids", RetailcrmHttpClient::METHOD_POST, array(
+ 'customers' => json_encode($ids),
+ ));
+ }
+
+ /**
+ * Get purchace prices & stock balance
+ *
+ * @param array $filter (default: array())
+ * @param int $page (default: null)
+ * @param int $limit (default: null)
+ * @param string $site (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function storeInventories(array $filter = array(), $page = null, $limit = null, $site = null)
+ {
+ $parameters = array();
+
+ if (sizeof($filter)) {
+ $parameters['filter'] = $filter;
+ }
+ if (null !== $page) {
+ $parameters['page'] = (int) $page;
+ }
+ if (null !== $limit) {
+ $parameters['limit'] = (int) $limit;
+ }
+
+ return $this->client->makeRequest('/store/inventories', RetailcrmHttpClient::METHOD_GET, $this->fillSite($site, $parameters));
+ }
+
+ /**
+ * Upload store inventories
+ *
+ * @param array $offers
+ * @param string $site (default: null)
+ * @return RetailcrmApiResponse
+ */
+ public function storeInventoriesUpload(array $offers, $site = null)
+ {
+ if (!sizeof($offers)) {
+ throw new InvalidArgumentException('Parameter `offers` must contains array of the customers');
+ }
+
+ return $this->client->makeRequest(
+ "/store/inventories/upload",
+ RetailcrmHttpClient::METHOD_POST,
+ $this->fillSite($site, array('offers' => json_encode($offers)))
+ );
+ }
+
+ /**
+ * Returns deliveryServices list
+ *
+ * @return RetailcrmApiResponse
+ */
+ public function deliveryServicesList()
+ {
+ return $this->client->makeRequest('/reference/delivery-services', RetailcrmHttpClient::METHOD_GET);
+ }
+
+ /**
+ * Returns deliveryTypes list
+ *
+ * @return RetailcrmApiResponse
+ */
+ public function deliveryTypesList()
+ {
+ return $this->client->makeRequest('/reference/delivery-types', RetailcrmHttpClient::METHOD_GET);
+ }
+
+ /**
+ * Returns orderMethods list
+ *
+ * @return RetailcrmApiResponse
+ */
+ public function orderMethodsList()
+ {
+ return $this->client->makeRequest('/reference/order-methods', RetailcrmHttpClient::METHOD_GET);
+ }
+
+ /**
+ * Returns orderTypes list
+ *
+ * @return RetailcrmApiResponse
+ */
+ public function orderTypesList()
+ {
+ return $this->client->makeRequest('/reference/order-types', RetailcrmHttpClient::METHOD_GET);
+ }
+
+ /**
+ * Returns paymentStatuses list
+ *
+ * @return RetailcrmApiResponse
+ */
+ public function paymentStatusesList()
+ {
+ return $this->client->makeRequest('/reference/payment-statuses', RetailcrmHttpClient::METHOD_GET);
+ }
+
+ /**
+ * Returns paymentTypes list
+ *
+ * @return RetailcrmApiResponse
+ */
+ public function paymentTypesList()
+ {
+ return $this->client->makeRequest('/reference/payment-types', RetailcrmHttpClient::METHOD_GET);
+ }
+
+ /**
+ * Returns productStatuses list
+ *
+ * @return RetailcrmApiResponse
+ */
+ public function productStatusesList()
+ {
+ return $this->client->makeRequest('/reference/product-statuses', RetailcrmHttpClient::METHOD_GET);
+ }
+
+ /**
+ * Returns statusGroups list
+ *
+ * @return RetailcrmApiResponse
+ */
+ public function statusGroupsList()
+ {
+ return $this->client->makeRequest('/reference/status-groups', RetailcrmHttpClient::METHOD_GET);
+ }
+
+ /**
+ * Returns statuses list
+ *
+ * @return RetailcrmApiResponse
+ */
+ public function statusesList()
+ {
+ return $this->client->makeRequest('/reference/statuses', RetailcrmHttpClient::METHOD_GET);
+ }
+
+ /**
+ * Returns sites list
+ *
+ * @return RetailcrmApiResponse
+ */
+ public function sitesList()
+ {
+ return $this->client->makeRequest('/reference/sites', RetailcrmHttpClient::METHOD_GET);
+ }
+
+ /**
+ * Returns stores list
+ *
+ * @return RetailcrmApiResponse
+ */
+ public function storesList()
+ {
+ return $this->client->makeRequest('/reference/stores', RetailcrmHttpClient::METHOD_GET);
+ }
+
+ /**
+ * Edit deliveryService
+ *
+ * @param array $data delivery service data
+ * @return RetailcrmApiResponse
+ */
+ public function deliveryServicesEdit(array $data)
+ {
+ if (!isset($data['code'])) {
+ throw new InvalidArgumentException('Data must contain "code" parameter.');
+ }
+
+ return $this->client->makeRequest(
+ '/reference/delivery-services/' . $data['code'] . '/edit',
+ RetailcrmHttpClient::METHOD_POST,
+ array(
+ 'deliveryService' => json_encode($data)
+ )
+ );
+ }
+
+ /**
+ * Edit deliveryType
+ *
+ * @param array $data delivery type data
+ * @return RetailcrmApiResponse
+ */
+ public function deliveryTypesEdit(array $data)
+ {
+ if (!isset($data['code'])) {
+ throw new InvalidArgumentException('Data must contain "code" parameter.');
+ }
+
+ return $this->client->makeRequest(
+ '/reference/delivery-types/' . $data['code'] . '/edit',
+ RetailcrmHttpClient::METHOD_POST,
+ array(
+ 'deliveryType' => json_encode($data)
+ )
+ );
+ }
+
+ /**
+ * Edit orderMethod
+ *
+ * @param array $data order method data
+ * @return RetailcrmApiResponse
+ */
+ public function orderMethodsEdit(array $data)
+ {
+ if (!isset($data['code'])) {
+ throw new InvalidArgumentException('Data must contain "code" parameter.');
+ }
+
+ return $this->client->makeRequest(
+ '/reference/order-methods/' . $data['code'] . '/edit',
+ RetailcrmHttpClient::METHOD_POST,
+ array(
+ 'orderMethod' => json_encode($data)
+ )
+ );
+ }
+
+ /**
+ * Edit orderType
+ *
+ * @param array $data order type data
+ * @return RetailcrmApiResponse
+ */
+ public function orderTypesEdit(array $data)
+ {
+ if (!isset($data['code'])) {
+ throw new InvalidArgumentException('Data must contain "code" parameter.');
+ }
+
+ return $this->client->makeRequest(
+ '/reference/order-types/' . $data['code'] . '/edit',
+ RetailcrmHttpClient::METHOD_POST,
+ array(
+ 'orderType' => json_encode($data)
+ )
+ );
+ }
+
+ /**
+ * Edit paymentStatus
+ *
+ * @param array $data payment status data
+ * @return RetailcrmApiResponse
+ */
+ public function paymentStatusesEdit(array $data)
+ {
+ if (!isset($data['code'])) {
+ throw new InvalidArgumentException('Data must contain "code" parameter.');
+ }
+
+ return $this->client->makeRequest(
+ '/reference/payment-statuses/' . $data['code'] . '/edit',
+ RetailcrmHttpClient::METHOD_POST,
+ array(
+ 'paymentStatus' => json_encode($data)
+ )
+ );
+ }
+
+ /**
+ * Edit paymentType
+ *
+ * @param array $data payment type data
+ * @return RetailcrmApiResponse
+ */
+ public function paymentTypesEdit(array $data)
+ {
+ if (!isset($data['code'])) {
+ throw new InvalidArgumentException('Data must contain "code" parameter.');
+ }
+
+ return $this->client->makeRequest(
+ '/reference/payment-types/' . $data['code'] . '/edit',
+ RetailcrmHttpClient::METHOD_POST,
+ array(
+ 'paymentType' => json_encode($data)
+ )
+ );
+ }
+
+ /**
+ * Edit productStatus
+ *
+ * @param array $data product status data
+ * @return RetailcrmApiResponse
+ */
+ public function productStatusesEdit(array $data)
+ {
+ if (!isset($data['code'])) {
+ throw new InvalidArgumentException('Data must contain "code" parameter.');
+ }
+
+ return $this->client->makeRequest(
+ '/reference/product-statuses/' . $data['code'] . '/edit',
+ RetailcrmHttpClient::METHOD_POST,
+ array(
+ 'productStatus' => json_encode($data)
+ )
+ );
+ }
+
+ /**
+ * Edit order status
+ *
+ * @param array $data status data
+ * @return RetailcrmApiResponse
+ */
+ public function statusesEdit(array $data)
+ {
+ if (!isset($data['code'])) {
+ throw new InvalidArgumentException('Data must contain "code" parameter.');
+ }
+
+ return $this->client->makeRequest(
+ '/reference/statuses/' . $data['code'] . '/edit',
+ RetailcrmHttpClient::METHOD_POST,
+ array(
+ 'status' => json_encode($data)
+ )
+ );
+ }
+
+ /**
+ * Edit site
+ *
+ * @param array $data site data
+ * @return RetailcrmApiResponse
+ */
+ public function sitesEdit(array $data)
+ {
+ if (!isset($data['code'])) {
+ throw new InvalidArgumentException('Data must contain "code" parameter.');
+ }
+
+ return $this->client->makeRequest(
+ '/reference/sites/' . $data['code'] . '/edit',
+ RetailcrmHttpClient::METHOD_POST,
+ array(
+ 'site' => json_encode($data)
+ )
+ );
+ }
+
+ /**
+ * Edit store
+ *
+ * @param array $data site data
+ * @return RetailcrmApiResponse
+ */
+ public function storesEdit(array $data)
+ {
+ if (!isset($data['code'])) {
+ throw new InvalidArgumentException('Data must contain "code" parameter.');
+ }
+
+ if (!isset($data['name'])) {
+ throw new InvalidArgumentException('Data must contain "name" parameter.');
+ }
+
+ return $this->client->makeRequest(
+ '/reference/stores/' . $data['code'] . '/edit',
+ RetailcrmHttpClient::METHOD_POST,
+ array(
+ 'store' => json_encode($data)
+ )
+ );
+ }
+
+ /**
+ * Update CRM basic statistic
+ *
+ * @return RetailcrmApiResponse
+ */
+ public function statisticUpdate()
+ {
+ return $this->client->makeRequest('/statistic/update', RetailcrmHttpClient::METHOD_GET);
+ }
+
+ /**
+ * Return current site
+ *
+ * @return string
+ */
+ public function getSite()
+ {
+ return $this->siteCode;
+ }
+
+ /**
+ * Set site
+ *
+ * @param string $site
+ * @return void
+ */
+ public function setSite($site)
+ {
+ $this->siteCode = $site;
+ }
+
+ /**
+ * Check ID parameter
+ *
+ * @param string $by
+ * @return bool
+ */
+ protected function checkIdParameter($by)
+ {
+ $allowedForBy = array('externalId', 'id');
+ if (!in_array($by, $allowedForBy)) {
+ throw new InvalidArgumentException(sprintf(
+ 'Value "%s" for parameter "by" is not valid. Allowed values are %s.',
+ $by,
+ implode(', ', $allowedForBy)
+ ));
+ }
+
+ return true;
+ }
+
+ /**
+ * Fill params by site value
+ *
+ * @param string $site
+ * @param array $params
+ * @return array
+ */
+ protected function fillSite($site, array $params)
+ {
+ if ($site) {
+ $params['site'] = $site;
+ } elseif ($this->siteCode) {
+ $params['site'] = $this->siteCode;
+ }
+
+ return $params;
+ }
+}
diff --git a/system/library/retailcrm/RetailcrmApiResponse.php b/system/library/retailcrm/RetailcrmApiResponse.php
new file mode 100644
index 0000000..bba91db
--- /dev/null
+++ b/system/library/retailcrm/RetailcrmApiResponse.php
@@ -0,0 +1,122 @@
+statusCode = (int) $statusCode;
+
+ if (!empty($responseBody)) {
+ $response = json_decode($responseBody, true);
+
+ if (!$response && JSON_ERROR_NONE !== ($error = json_last_error())) {
+ throw new InvalidJsonException(
+ "Invalid JSON in the API response body. Error code #$error",
+ $error
+ );
+ }
+
+ $this->response = $response;
+ }
+ }
+
+ /**
+ * Return HTTP response status code
+ *
+ * @return int
+ */
+ public function getStatusCode()
+ {
+ return $this->statusCode;
+ }
+
+ /**
+ * HTTP request was successful
+ *
+ * @return bool
+ */
+ public function isSuccessful()
+ {
+ return $this->statusCode < 400;
+ }
+
+ /**
+ * Allow to access for the property throw class method
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function __call($name, $arguments)
+ {
+ // convert getSomeProperty to someProperty
+ $propertyName = strtolower(substr($name, 3, 1)) . substr($name, 4);
+
+ if (!isset($this->response[$propertyName])) {
+ throw new InvalidArgumentException("Method \"$name\" not found");
+ }
+
+ return $this->response[$propertyName];
+ }
+
+ /**
+ * Allow to access for the property throw object property
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function __get($name)
+ {
+ if (!isset($this->response[$name])) {
+ throw new InvalidArgumentException("Property \"$name\" not found");
+ }
+
+ return $this->response[$name];
+ }
+
+ /**
+ * @param mixed $offset
+ * @param mixed $value
+ */
+ public function offsetSet($offset, $value)
+ {
+ throw new BadMethodCallException('This activity not allowed');
+ }
+
+ /**
+ * @param mixed $offset
+ */
+ public function offsetUnset($offset)
+ {
+ throw new BadMethodCallException('This call not allowed');
+ }
+
+ /**
+ * @param mixed $offset
+ * @return bool
+ */
+ public function offsetExists($offset)
+ {
+ return isset($this->response[$offset]);
+ }
+
+ /**
+ * @param mixed $offset
+ * @return mixed
+ */
+ public function offsetGet($offset)
+ {
+ if (!isset($this->response[$offset])) {
+ throw new InvalidArgumentException("Property \"$offset\" not found");
+ }
+
+ return $this->response[$offset];
+ }
+}
diff --git a/system/library/retailcrm/RetailcrmHttpClient.php b/system/library/retailcrm/RetailcrmHttpClient.php
new file mode 100644
index 0000000..6f74d16
--- /dev/null
+++ b/system/library/retailcrm/RetailcrmHttpClient.php
@@ -0,0 +1,113 @@
+url = $url;
+ $this->defaultParameters = $defaultParameters;
+ $this->retry = 0;
+ }
+
+ /**
+ * Make HTTP request
+ *
+ * @param string $path
+ * @param string $method (default: 'GET')
+ * @param array $parameters (default: array())
+ * @param int $timeout
+ * @param bool $verify
+ * @param bool $debug
+ * @return RetailcrmApiResponse
+ */
+ public function makeRequest(
+ $path,
+ $method,
+ array $parameters = array(),
+ $timeout = 30,
+ $verify = false,
+ $debug = false
+ ) {
+ $allowedMethods = array(self::METHOD_GET, self::METHOD_POST);
+ if (!in_array($method, $allowedMethods)) {
+ throw new InvalidArgumentException(sprintf(
+ 'Method "%s" is not valid. Allowed methods are %s',
+ $method,
+ implode(', ', $allowedMethods)
+ ));
+ }
+
+ $parameters = array_merge($this->defaultParameters, $parameters);
+
+ $url = $this->url . $path;
+
+ if (self::METHOD_GET === $method && sizeof($parameters)) {
+ $url .= '?' . http_build_query($parameters, '', '&');
+ }
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
+ curl_setopt($ch, CURLOPT_FAILONERROR, false);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify);
+
+ if (!$debug) {
+ curl_setopt($ch, CURLOPT_TIMEOUT, (int) $timeout);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (int) $timeout);
+ } else {
+ curl_setopt($ch, CURLOPT_TIMEOUT_MS, (int) $timeout + ($this->retry * 2000));
+ }
+
+ if (self::METHOD_POST === $method) {
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters);
+ }
+
+ $responseBody = curl_exec($ch);
+ $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ $errno = curl_errno($ch);
+ $error = curl_error($ch);
+
+ curl_close($ch);
+
+ if ($errno && in_array($errno, array(6, 7, 28, 34, 35)) && $this->retry < 3) {
+ $errno = null;
+ $error = null;
+ $this->retry += 1;
+ $this->makeRequest(
+ $path,
+ $method,
+ $parameters,
+ $timeout,
+ $verify,
+ $debug
+ );
+ }
+
+ if ($errno) {
+ throw new CurlException($error, $errno);
+ }
+
+ return new RetailcrmApiResponse($statusCode, $responseBody);
+ }
+
+ public function getRetry()
+ {
+ return $this->retry;
+ }
+}
diff --git a/system/library/retailcrm/RetailcrmProxy.php b/system/library/retailcrm/RetailcrmProxy.php
new file mode 100644
index 0000000..f99f740
--- /dev/null
+++ b/system/library/retailcrm/RetailcrmProxy.php
@@ -0,0 +1,43 @@
+api = new RetailcrmApiClient($url, $key);
+ $this->log = $log;
+ }
+
+ public function __call($method, $arguments)
+ {
+ try {
+ $response = call_user_func_array(array($this->api, $method), $arguments);
+
+ if (!$response->isSuccessful()) {
+ error_log("[$method] " . $response->getErrorMsg() . "\n", 3, $this->log);
+ if (isset($response['errors'])) {
+ $error = implode("\n", $response['errors']);
+ error_log($error . "\n", 3, $this->log);
+ }
+ $response = false;
+ }
+
+ return $response;
+ } catch (CurlException $e) {
+ error_log("[$method] " . $e->getMessage() . "\n", 3, $this->log);
+ return false;
+ } catch (InvalidJsonException $e) {
+ error_log("[$method] " . $e->getMessage() . "\n", 3, $this->log);
+ return false;
+ }
+ }
+
+}
diff --git a/system/library/retailcrm/bootstrap.php b/system/library/retailcrm/bootstrap.php
new file mode 100644
index 0000000..7c0cc34
--- /dev/null
+++ b/system/library/retailcrm/bootstrap.php
@@ -0,0 +1,99 @@
+
+ * @author Alex Lushpai
+ */
+class RetailcrmAutoloader
+{
+ /**
+ * File extension as a string. Defaults to ".php".
+ */
+ protected static $fileExt = '.php';
+
+ /**
+ * The top level directory where recursion will begin.
+ *
+ */
+ protected static $pathTop;
+
+ /**
+ * Autoload function for registration with spl_autoload_register
+ *
+ * Looks recursively through project directory and loads class files based on
+ * filename match.
+ *
+ * @param string $className
+ */
+ public static function loader($className)
+ {
+ $directory = new RecursiveDirectoryIterator(self::$pathTop);
+ $fileIterator = new RecursiveIteratorIterator($directory);
+ $filename = $className . self::$fileExt;
+
+ foreach ($fileIterator as $file) {
+ if (strtolower($file->getFilename()) === strtolower($filename) && $file->isReadable()) {
+ include_once $file->getPathname();
+ }
+ }
+
+ }
+
+ /**
+ * Sets the $fileExt property
+ *
+ * @param string $fileExt The file extension used for class files. Default is "php".
+ */
+ public static function setFileExt($fileExt)
+ {
+ self::$fileExt = $fileExt;
+ }
+
+ /**
+ * Sets the $path property
+ *
+ * @param string $path The path representing the top level where recursion should
+ * begin. Defaults to the current directory.
+ */
+ public static function setPath($path)
+ {
+ self::$pathTop = $path;
+ }
+
+}
+
+RetailcrmAutoloader::setPath(realpath(dirname(__FILE__)));
+RetailcrmAutoloader::setFileExt('.php');
+spl_autoload_register('RetailcrmAutoloader::loader');
diff --git a/vqmod/xml/retailcrm_create_order.xml b/vqmod/xml/retailcrm_create_order.xml
new file mode 100644
index 0000000..eeb2704
--- /dev/null
+++ b/vqmod/xml/retailcrm_create_order.xml
@@ -0,0 +1,40 @@
+
+
+ Send order to RetailCRM when it created
+ 1.5.x
+ 2.3.x
+ retailcrm.ru
+
+
+
+
+ load->model('retailcrm/order');
+ $this->model_retailcrm_order->sendToCrm($data, $order_id);
+ ]]>
+
+
+
+
+
+ db->query("UPDATE `" . DB_PREFIX . "order` SET total = '" . (float)$total . "', affiliate_id = '" . (int)$affiliate_id . "', commission = '" . (float)$commission . "' WHERE order_id = '" . (int)$order_id . "'");]]>
+ load->model('setting/setting');
+ $status = $this->model_setting_setting->getSetting('retailcrm');
+
+ if (!empty($data['order_status_id'])) {
+ $data['order_status'] = $status['retailcrm_status'][$data['order_status_id']];
+ }
+
+ $this->load->model('retailcrm/order');
+ if (isset ($order_query)) {
+ $this->model_retailcrm_order->changeInCrm($data, $order_id);
+ } else {
+ $this->model_retailcrm_order->sendToCrm($data, $order_id);
+ }
+ }
+ ]]>
+
+
+