vqmod, refactoring, bug fixes

This commit is contained in:
Alex Lushpai 2016-01-29 17:59:53 +03:00
parent 556edc9e00
commit 4522e0233d
16 changed files with 866 additions and 753 deletions

View File

@ -1,6 +1,13 @@
Changelog Changelog
========= =========
####v0.3.0
* Расширена библиотека клиента
* Добавлена возможность кастомизации моделей заказа через vqmod
* Устранены мелкие баги, проведен рефакторинг кода.
####v0.2.0 ####v0.2.0
Общие изменения Общие изменения

View File

@ -1,35 +1,42 @@
Opencart module Opencart module
=============== ===============
Модуль интеграции CMS Openacrt c [RetailCRM](http://retailcrm.ru) Модуль интеграции CMS Openacrt c [RetailCRM](http://retailcrm.ru)
### Модуль позволяет: #### Модуль позволяет:
* Экспортировать в CRM данные о заказах и клиентах и получать обратно изменения по этим данным * Экспортировать в CRM данные о заказах и клиентах и получать обратно изменения по этим данным
* Синхронизировать справочники (способы доставки и оплаты, статусы заказов и т.п.) * Синхронизировать справочники (способы доставки и оплаты, статусы заказов и т.п.)
* Выгружать каталог товаров в формате [ICML](http://retailcrm.ru/docs/Разработчики/ФорматICML) (IntaroCRM Markup Language) * Выгружать каталог товаров в формате [ICML](http://retailcrm.ru/docs/Разработчики/ФорматICML) (IntaroCRM Markup Language)
### Установка #### Установка
#### Скачайте модуль Установите модуль скопировав необходимые файлы в корень сайта
```
https://github.com/retailcrm/opencart-module/archive/master.zip
```
#### Установите модуль скопировав необходимые файлы в корень сайта
``` ```
unzip master.zip unzip master.zip
cp -r opencart-module/* /path/to/opecart/instance cp -r opencart-module/* /path/to/site/root
``` ```
#### Активируйте модуль #### Активируйте модуль
В основном меню Extension -> Modules -> Intstall module. В списке модулей нажмите "Установить"
#### Настройте параметры интеграции
На странице настроек модуля укажите URL Вашей CRM и ключ авторизации, после сохранения этих данных укажите соответствия справочников типов доставок, оплат и статусов заказа.
#### Выгрузка новых заказов в CRM (для версии opencart 1.5.x.x, для версии 2.0 и старше не требуется) #### Выгрузка новых заказов в CRM (для версии opencart 1.5.x.x, для версии 2.0 и старше не требуется)
##### VQmod
Скопируйте xml-файл модифицирующий работу моделей _admin/model/sale/order.php_ и _catalog/model/checkout/order.php_ в _/path/to/site/root/vqmod/xml_.
Для обновления кеша VQmod может потрбоваться удалить файлы _/path/to/site/root/vqmod/vqcache/vq2-admin_model_sale_order.php_ и _/path/to/site/root/vqmod/vqcache/vq2-catalog_model_checkout_order.php_
##### Ручная установка
В файле: В файле:
``` ```
@ -38,9 +45,9 @@ cp -r opencart-module/* /path/to/opecart/instance
Добавьте следующие строки в метод addOrder непосредственно перед языковой конструкцией return: Добавьте следующие строки в метод addOrder непосредственно перед языковой конструкцией return:
``` ```php
$this->load->model('retailcrm/order'); $this->load->model('retailcrm/order');
$this->model_retailcrm_order->send($data, $order_id); $this->model_retailcrm_order->sendToCrm($data, $order_id);
``` ```
В файле: В файле:
@ -49,12 +56,23 @@ $this->model_retailcrm_order->send($data, $order_id);
/admin/model/sale/order.php /admin/model/sale/order.php
``` ```
Добавьте следующие строки в методы addOrder и editOrder непосредственно перед языковой конструкцией return: Добавьте следующие строки в методы addOrder и editOrder в самом конце каждого метода:
``` ```php
if (!isset($data['fromApi'])) { if (!isset($data['fromApi'])) {
$this->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'); $this->load->model('retailcrm/order');
$this->model_retailcrm_order->send($data, $order_id); if (isset ($order_query)) {
$this->model_retailcrm_order->changeInCrm($data, $order_id);
} else {
$this->model_retailcrm_order->sendToCrm($data, $order_id);
}
} }
``` ```
@ -77,5 +95,5 @@ if (!isset($data['fromApi'])) {
В настройках CRM установите путь к файлу выгрузки В настройках CRM установите путь к файлу выгрузки
``` ```
/download/retailcrm.xml http://myopencartsite.ru/download/retailcrm.xml
``` ```

View File

@ -1,6 +1,6 @@
<?php <?php
require_once DIR_SYSTEM . 'library/retailcrm.php'; require_once DIR_SYSTEM . 'library/retailcrm/bootstrap.php';
class ControllerModuleRetailcrm extends Controller class ControllerModuleRetailcrm extends Controller
{ {
@ -11,19 +11,13 @@ class ControllerModuleRetailcrm extends Controller
public function install() public function install()
{ {
$this->load->model('setting/setting'); $this->load->model('setting/setting');
$this->model_setting_setting->editSetting( $this->model_setting_setting->editSetting('retailcrm', array('retailcrm_status' => 1));
'retailcrm',
array('retailcrm_status' => 1)
);
} }
public function uninstall() public function uninstall()
{ {
$this->load->model('setting/setting'); $this->load->model('setting/setting');
$this->model_setting_setting->editSetting( $this->model_setting_setting->editSetting('retailcrm', array('retailcrm_status' => 0));
'retailcrm',
array('retailcrm_status' => 0)
);
} }
public function index() public function index()
@ -36,22 +30,10 @@ class ControllerModuleRetailcrm extends Controller
$this->document->setTitle($this->language->get('heading_title')); $this->document->setTitle($this->language->get('heading_title'));
$this->document->addStyle('/admin/view/stylesheet/retailcrm.css'); $this->document->addStyle('/admin/view/stylesheet/retailcrm.css');
if ( if ($this->request->server['REQUEST_METHOD'] == 'POST' && $this->validate()) {
$this->request->server['REQUEST_METHOD'] == 'POST' $this->model_setting_setting->editSetting('retailcrm', $this->request->post);
&&
$this->validate()
) {
$this->model_setting_setting
->editSetting('retailcrm', $this->request->post);
$this->session->data['success'] = $this->language->get('text_success'); $this->session->data['success'] = $this->language->get('text_success');
$this->redirect($this->url->link('module/retailcrm', 'token=' . $this->session->data['token'], 'SSL'));
$this->redirect(
$this->url->link(
'extension/module',
'token=' . $this->session->data['token'], 'SSL'
)
);
} }
$text_strings = array( $text_strings = array(
@ -75,23 +57,18 @@ class ControllerModuleRetailcrm extends Controller
} }
$this->data['retailcrm_errors'] = array(); $this->data['retailcrm_errors'] = array();
$this->data['saved_settings'] = $this->model_setting_setting $this->data['saved_settings'] = $this->model_setting_setting->getSetting('retailcrm');
->getSetting('retailcrm');
if ( $url = $this->data['saved_settings']['retailcrm_url'];
!empty($this->data['saved_settings']['retailcrm_url']) $key = $this->data['saved_settings']['retailcrm_apikey'];
&&
!empty($this->data['saved_settings']['retailcrm_apikey'])
) {
$this->retailcrm = new ApiHelper($this->data['saved_settings']); if (!empty($url) && !empty($key)) {
$this->data['delivery'] = $this->model_retailcrm_references $this->retailcrm = new RetailcrmProxy($url, $key, DIR_SYSTEM . 'logs/retailcrm.log');
->getDeliveryTypes();
$this->data['statuses'] = $this->model_retailcrm_references $this->data['delivery'] = $this->model_retailcrm_references->getDeliveryTypes();
->getOrderStatuses(); $this->data['statuses'] = $this->model_retailcrm_references->getOrderStatuses();
$this->data['payments'] = $this->model_retailcrm_references $this->data['payments'] = $this->model_retailcrm_references->getPaymentTypes();
->getPaymentTypes();
} }
@ -176,7 +153,7 @@ class ControllerModuleRetailcrm extends Controller
public function history() public function history()
{ {
if (file_exists(DIR_APPLICATION . 'model/retailcrm/custom/history')) { if (file_exists(DIR_APPLICATION . 'model/retailcrm/custom/history.php')) {
$this->load->model('retailcrm/custom/history'); $this->load->model('retailcrm/custom/history');
$this->model_retailcrm_custom_history->request(); $this->model_retailcrm_custom_history->request();
} else { } else {
@ -187,7 +164,7 @@ class ControllerModuleRetailcrm extends Controller
public function icml() public function icml()
{ {
if (file_exists(DIR_APPLICATION . 'model/retailcrm/custom/icml')) { if (file_exists(DIR_APPLICATION . 'model/retailcrm/custom/icml.php')) {
$this->load->model('retailcrm/custom/icml'); $this->load->model('retailcrm/custom/icml');
$this->model_retailcrm_custom_icml->generateICML(); $this->model_retailcrm_custom_icml->generateICML();
} else { } else {

View File

@ -18,7 +18,12 @@ class ModelRetailcrmHistory extends Model
$settings['domain'] = parse_url(HTTP_SERVER, PHP_URL_HOST); $settings['domain'] = parse_url(HTTP_SERVER, PHP_URL_HOST);
if (!empty($settings['retailcrm_url']) && !empty($settings['retailcrm_apikey'])) { if (!empty($settings['retailcrm_url']) && !empty($settings['retailcrm_apikey'])) {
$crm = new ApiHelper($settings); $crm = new RetailcrmProxy(
$settings['retailcrm_url'],
$settings['retailcrm_apikey'],
DIR_SYSTEM . 'logs/retailcrm.log'
);
$orders = $crm->ordersHistory(); $orders = $crm->ordersHistory();
$ordersIdsFix = array(); $ordersIdsFix = array();
$customersIdsFix = array(); $customersIdsFix = array();
@ -288,19 +293,15 @@ class ModelRetailcrmHistory extends Model
} }
if (!empty($customersIdsFix)) { if (!empty($customersIdsFix)) {
$crm->customerFixExternalIds($customersIdsFix); $crm->customersFixExternalIds($customersIdsFix);
} }
if (!empty($ordersIdsFix)) { if (!empty($ordersIdsFix)) {
$crm->orderFixExternalIds($ordersIdsFix); $crm->ordersFixExternalIds($ordersIdsFix);
} }
} else { } else {
$this->log->addNotice( $this->log->addNotice('You need to configure retailcrm module first.');
'['.
$this->config->get('store_name').
'] RestApi::orderHistory: you need to configure retailcrm module first.'
);
} }
} }
} }

View File

@ -69,7 +69,7 @@ class ModelRetailcrmIcml extends Model
) )
); );
$e->setAttribute('id', $category['id']); $e->setAttribute('id', $category['category_id']);
if ($category['parent_id'] > 0) { if ($category['parent_id'] > 0) {
$e->setAttribute('parentId', $category['parent_id']); $e->setAttribute('parentId', $category['parent_id']);
@ -103,11 +103,11 @@ class ModelRetailcrmIcml extends Model
/** /**
* Offer activity * Offer activity
*/ */
$offer['status'] ? 'Y' : 'N'; $activity = $offer['status'] == 1 ? 'Y' : 'N';
$e->appendChild( $e->appendChild(
$this->dd->createElement('productActivity') $this->dd->createElement('productActivity')
)->appendChild( )->appendChild(
$this->dd->createTextNode($offer['status']) $this->dd->createTextNode($activity)
); );
/** /**

View File

@ -1,17 +1,173 @@
<?php <?php
class ModelRetailcrmOrder extends Model { class ModelRetailcrmOrder extends Model {
public function send($order, $order_id) public function sendToCrm($order_data, $order_id)
{ {
$this->load->model('setting/setting'); $this->load->model('setting/setting');
$settings = $this->model_setting_setting->getSetting('retailcrm'); $settings = $this->model_setting_setting->getSetting('retailcrm');
$order['order_status'] = $settings['retailcrm_status'][$order['order_status_id']];
if(!empty($settings['retailcrm_url']) && !empty($settings['retailcrm_apikey'])) { if(!empty($settings['retailcrm_url']) && !empty($settings['retailcrm_apikey'])) {
require_once DIR_SYSTEM . 'library/retailcrm.php'; require_once DIR_SYSTEM . 'library/retailcrm/bootstrap.php';
$order['order_id'] = $order_id;
$crm = new ApiHelper($settings); $this->retailcrm = new RetailcrmProxy(
$crm->processOrder($order); $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);
}
}
public function changeInCrm($order_data, $order_id)
{
$this->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'];
$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->ordersEdit($order);
} }
} }
} }

View File

@ -1,6 +1,6 @@
<?php <?php
require_once DIR_SYSTEM . 'library/retailcrm.php'; require_once DIR_SYSTEM . 'library/retailcrm/bootstrap.php';
class ModelRetailcrmReferences extends Model class ModelRetailcrmReferences extends Model
{ {
@ -88,42 +88,15 @@ class ModelRetailcrmReferences extends Model
$settings = $this->model_setting_setting->getSetting('retailcrm'); $settings = $this->model_setting_setting->getSetting('retailcrm');
if(!empty($settings['retailcrm_url']) && !empty($settings['retailcrm_apikey'])) { if(!empty($settings['retailcrm_url']) && !empty($settings['retailcrm_apikey'])) {
$this->retailcrm = new ApiHelper($settings); $this->retailcrm = new RetailcrmProxy(
$settings['retailcrm_url'],
$settings['retailcrm_apikey'],
DIR_SYSTEM . 'logs/retailcrm.log'
);
try { $response = $this->retailcrm->deliveryTypesList();
$response = $this->retailcrm->api->deliveryTypesList();
if ($response->isSuccessful() && $response->getStatusCode() == 200) {
return $response->deliveryTypes;
} else {
$this->log->write(
sprintf(
"RestApi::deliveryTypesList::Errors: [HTTP-status %s] %s",
$response->getStatusCode(),
$response->getErrorMsg()
)
);
if (isset($response['errors'])) { return ($response === false) ? array() : $response->deliveryTypes;
foreach ($response['errors'] as $error) {
$this->log->write(
sprintf(
"RestApi::deliveryTypesList::Errors: %s", $error
)
);
}
}
return array();
}
} catch (CurlException $e) {
$this->data['retailcrm_error'][] = $e->getMessage();
$this->log->write('RestApi::deliveryTypesList::Curl:' . $e->getMessage());
} catch (InvalidJsonException $e) {
$this->data['retailcrm_error'][] = $e->getMessage();
$this->log->write('RestApi::deliveryTypesList::JSON:' . $e->getMessage());
}
} else {
return array();
} }
} }
@ -133,42 +106,15 @@ class ModelRetailcrmReferences extends Model
$settings = $this->model_setting_setting->getSetting('retailcrm'); $settings = $this->model_setting_setting->getSetting('retailcrm');
if(!empty($settings['retailcrm_url']) && !empty($settings['retailcrm_apikey'])) { if(!empty($settings['retailcrm_url']) && !empty($settings['retailcrm_apikey'])) {
$this->retailcrm = new ApiHelper($settings); $this->retailcrm = new RetailcrmProxy(
$settings['retailcrm_url'],
$settings['retailcrm_apikey'],
DIR_SYSTEM . 'logs/retailcrm.log'
);
try { $response = $this->retailcrm->statusesList();
$response = $this->retailcrm->api->statusesList();
if ($response->isSuccessful() && $response->getStatusCode() == 200) {
return $response->statuses;
} else {
$this->log->write(
sprintf(
"RestApi::statusesList::Errors: [HTTP-status %s] %s",
$response->getStatusCode(),
$response->getErrorMsg()
)
);
if (isset($response['errors'])) { return ($response === false) ? array() : $response->statuses;
foreach ($response['errors'] as $error) {
$this->log->write(
sprintf(
"RestApi::statusesList::Errors: %s", $error
)
);
}
}
return array();
}
} catch (CurlException $e) {
$this->data['retailcrm_error'][] = $e->getMessage();
$this->log->write('RestApi::orderStatusesList::Curl:' . $e->getMessage());
} catch (InvalidJsonException $e) {
$this->data['retailcrm_error'][] = $e->getMessage();
$this->log->write('RestApi::orderStatusesList::JSON:' . $e->getMessage());
}
} else {
return array();
} }
} }
@ -178,42 +124,15 @@ class ModelRetailcrmReferences extends Model
$settings = $this->model_setting_setting->getSetting('retailcrm'); $settings = $this->model_setting_setting->getSetting('retailcrm');
if(!empty($settings['retailcrm_url']) && !empty($settings['retailcrm_apikey'])) { if(!empty($settings['retailcrm_url']) && !empty($settings['retailcrm_apikey'])) {
$this->retailcrm = new ApiHelper($settings); $this->retailcrm = new RetailcrmProxy(
$settings['retailcrm_url'],
$settings['retailcrm_apikey'],
DIR_SYSTEM . 'logs/retailcrm.log'
);
try { $response = $this->retailcrm->paymentTypesList();
$response = $this->retailcrm->api->paymentTypesList();
if ($response->isSuccessful() && $response->getStatusCode() == 200) {
return $response->paymentTypes;
} else {
$this->log->write(
sprintf(
"RestApi::paymentTypesList::Errors: [HTTP-status %s] %s",
$response->getStatusCode(),
$response->getErrorMsg()
)
);
if (isset($response['errors'])) { return ($response === false) ? array() : $response->paymentTypes;
foreach ($response['errors'] as $error) {
$this->log->write(
sprintf(
"RestApi::paymentTypesList::Errors: %s", $error
)
);
}
}
return array();
}
} catch (CurlException $e) {
$this->data['retailcrm_error'][] = $e->getMessage();
$this->log->write('RestApi::paymentTypesList::Curl:' . $e->getMessage());
} catch (InvalidJsonException $e) {
$this->data['retailcrm_error'][] = $e->getMessage();
$this->log->write('RestApi::paymentTypesList::JSON:' . $e->getMessage());
}
} else {
return array();
} }
} }
} }

View File

@ -1,21 +1,96 @@
<?php <?php
class ModelRetailcrmOrder extends Model { class ModelRetailcrmOrder extends Model {
public function send($order, $order_id) public function sendToCrm($order_data, $order_id)
{ {
$this->load->model('setting/setting'); $this->load->model('setting/setting');
$settings = $this->model_setting_setting->getSetting('retailcrm'); $settings = $this->model_setting_setting->getSetting('retailcrm');
$settings['domain'] = parse_url(HTTP_SERVER, PHP_URL_HOST);
if( if(!empty($settings['retailcrm_url']) && !empty($settings['retailcrm_apikey'])) {
!empty($settings['retailcrm_url']) require_once DIR_SYSTEM . 'library/retailcrm/bootstrap.php';
&&
!empty($settings['retailcrm_apikey']) $this->retailcrm = new RetailcrmProxy(
) { $settings['retailcrm_url'],
require_once DIR_SYSTEM . 'library/retailcrm/Retailcrm.php'; $settings['retailcrm_apikey'],
$order['order_id'] = $order_id; DIR_SYSTEM . 'logs/retailcrm.log'
$crm = new ApiHelper($settings); );
$crm->processOrder($order);
$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);
} }
} }
} }

View File

@ -0,0 +1,5 @@
<?php
class CurlException extends RuntimeException
{
}

View File

@ -0,0 +1,5 @@
<?php
class InvalidJsonException extends DomainException
{
}

View File

@ -0,0 +1,122 @@
<?php
/**
* Response from retailCRM API
*/
class RetailcrmApiResponse implements ArrayAccess
{
// HTTP response status code
protected $statusCode;
// response assoc array
protected $response;
public function __construct($statusCode, $responseBody = null)
{
$this->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];
}
}

View File

@ -0,0 +1,113 @@
<?php
/**
* HTTP client
*/
class RetailcrmHttpClient
{
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';
protected $url;
protected $defaultParameters;
protected $retry;
public function __construct($url, array $defaultParameters = array())
{
if (false === stripos($url, 'https://')) {
throw new InvalidArgumentException('API schema requires HTTPS protocol');
}
$this->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;
}
}

View File

@ -0,0 +1,43 @@
<?php
/**
* Class RequestProxy
* @package RetailCrm\Component
*/
class RetailcrmProxy
{
private $api;
private $log;
public function __construct($url, $key, $log)
{
$this->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;
}
}
}

View File

@ -0,0 +1,99 @@
<?php
/*
* The MIT License (MIT)
*
* Copyright (c) 2014 Rob Dunham
*
* 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.
*/
/**
* Simple Recursive Autoloader
*
* A simple autoloader that loads class files recursively starting in the directory
* where this class resides. Additional options can be provided to control the naming
* convention of the class files.
*
* @package Autoloader
* @license http://opensource.org/licenses/MIT MIT License
* @author Rob Dunham <contact@robunham.info>
* @author Alex Lushpai <lushpai@gmail.com>
*/
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');

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<modification>
<id>Send order to RetailCRM when it created</id>
<version>1.5.x</version>
<vqmver required="true">2.3.x</vqmver>
<author>retailcrm.ru</author>
<file path="catalog/model/checkout/" name="order.php">
<operation error="skip">
<search position="before" ><![CDATA[return $order_id]]></search>
<add><![CDATA[
$this->load->model('retailcrm/order');
$this->model_retailcrm_order->sendToCrm($data, $order_id);
]]></add>
</operation>
</file>
<file path="admin/model/sale/" name="order.php">
<operation error="skip">
<search position="after" ><![CDATA[$this->db->query("UPDATE `" . DB_PREFIX . "order` SET total = '" . (float)$total . "', affiliate_id = '" . (int)$affiliate_id . "', commission = '" . (float)$commission . "' WHERE order_id = '" . (int)$order_id . "'");]]></search>
<add><![CDATA[
if (!isset($data['fromApi'])) {
$this->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);
}
}
]]></add>
</operation>
</file>
</modification>