From fea35d72ae9eb8c8dfd190bf4baa5822dac34862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9?= Date: Mon, 4 Sep 2017 11:36:04 +0300 Subject: [PATCH] v.2.2.1 (#26) --- CHANGELOG.md | 14 + .../{ApiClient.php => ApiClient_v4.php} | 134 +- .../classes/general/ApiClient_v5.php | 2469 +++++++++++++++++ .../classes/general/RCrmActions.php | 232 +- .../general/collector/RetailCrmCollector.php | 32 + .../classes/general/config/objects.xml | 7 + .../classes/general/config/retailcrm.json | 30 +- .../classes/general/events/RetailCrmEvent.php | 54 +- .../general/history/FastOrderHistory.php | 31 + ...CrmHistory.php => RetailCrmHistory_v4.php} | 390 +-- .../general/history/RetailCrmHistory_v5.php | 1320 +++++++++ .../classes/general/icml/RetailCrmICML.php | 200 +- .../inventories/RetailCrmInventories.php | 163 ++ ...tailCrmOrder.php => RetailCrmOrder_v4.php} | 35 +- .../general/order/RetailCrmOrder_v5.php | 420 +++ .../general/prices/RetailCrmPrices.php | 137 + .../classes/general/ua/RetailCrmUa.php | 69 + .../classes/general/user/RetailCrmUser.php | 29 +- intaro.retailcrm/description.ru | 9 +- intaro.retailcrm/export/export_setup.php | 154 +- intaro.retailcrm/include.php | 23 +- intaro.retailcrm/install/index.php | 524 ++-- intaro.retailcrm/install/version.php | 4 +- .../general/history/RetailCrmHistory_v4.php | 3 + .../general/history/RetailCrmHistory_v5.php | 3 + .../classes/general/{ => icml}/ICMLLoader.php | 0 intaro.retailcrm/lang/ru/install/step1.php | 1 + intaro.retailcrm/lang/ru/install/step2.php | 2 +- intaro.retailcrm/lang/ru/install/step6.php | 4 +- intaro.retailcrm/lang/ru/options.php | 21 + intaro.retailcrm/options.php | 484 +++- 31 files changed, 6116 insertions(+), 882 deletions(-) rename intaro.retailcrm/classes/general/{ApiClient.php => ApiClient_v4.php} (92%) create mode 100644 intaro.retailcrm/classes/general/ApiClient_v5.php create mode 100644 intaro.retailcrm/classes/general/collector/RetailCrmCollector.php create mode 100644 intaro.retailcrm/classes/general/history/FastOrderHistory.php rename intaro.retailcrm/classes/general/history/{RetailCrmHistory.php => RetailCrmHistory_v4.php} (84%) create mode 100644 intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php create mode 100644 intaro.retailcrm/classes/general/inventories/RetailCrmInventories.php rename intaro.retailcrm/classes/general/order/{RetailCrmOrder.php => RetailCrmOrder_v4.php} (94%) create mode 100644 intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php create mode 100644 intaro.retailcrm/classes/general/prices/RetailCrmPrices.php create mode 100644 intaro.retailcrm/classes/general/ua/RetailCrmUa.php create mode 100644 intaro.retailcrm/lang/ru/classes/general/history/RetailCrmHistory_v4.php create mode 100644 intaro.retailcrm/lang/ru/classes/general/history/RetailCrmHistory_v5.php rename intaro.retailcrm/lang/ru/classes/general/{ => icml}/ICMLLoader.php (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac636398..51671515 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## 2017-08-21 v.2.2.1 +* Добавлена встроенная функция retailCrmApiResult +* Добавлен триггерный вариант истории изменений +* Исправлены ошибки +## 2017-08-21 v.2.2.0 +* API V5 +* Возможность выбора версии API +* Добавлена возможность выгрузки остатков в разрезе складов +* Добавлена возможность выгрузки типов цен +* Добавлена базовая интеграция Demon Collector +* Добавлена интеграция с Universal Analytics +* Доработана логика работы встроенных функций для модификации данных +* Исправлены ошибки + ## 2016-12-09 v.2.1.2 * Добавлены единицы измерения в экспорте каталога * Исправлены пути в include diff --git a/intaro.retailcrm/classes/general/ApiClient.php b/intaro.retailcrm/classes/general/ApiClient_v4.php similarity index 92% rename from intaro.retailcrm/classes/general/ApiClient.php rename to intaro.retailcrm/classes/general/ApiClient_v4.php index 1b51ee3e..401605d1 100644 --- a/intaro.retailcrm/classes/general/ApiClient.php +++ b/intaro.retailcrm/classes/general/ApiClient_v4.php @@ -97,6 +97,35 @@ class ApiClient ); } + /** + * Get user groups + * + * @param null $page + * @param null $limit + * + * @throws \RetailCrm\Exception\InvalidJsonException + * @throws \RetailCrm\Exception\CurlException + * + * @return ApiResponse + */ + public function usersGroups($page = null, $limit = null) + { + $parameters = array(); + + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/user-groups', + Client::METHOD_GET, + $parameters + ); + } + /** * Returns user data * @@ -804,7 +833,7 @@ class ApiClient return $this->client->makeRequest( sprintf('/store/setting/%s/edit', $configuration['code']), Client::METHOD_POST, - $configuration + array('configuration' => json_encode($configuration)) ); } @@ -834,6 +863,33 @@ class ApiClient $this->fillSite($site, array('offers' => json_encode($offers))) ); } + + /** + * Upload store prices + * + * @param array $prices prices data + * @param string $site default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function storePricesUpload(array $prices, $site = null) + { + if (!count($prices)) { + throw new \InvalidArgumentException( + 'Parameter `prices` must contains array of the prices' + ); + } + + return $this->client->makeRequest( + '/store/prices/upload', + Client::METHOD_POST, + $this->fillSite($site, array('prices' => json_encode($prices))) + ); + } /** * Get products @@ -945,7 +1001,7 @@ class ApiClient return $this->client->makeRequest( sprintf('/delivery/generic/%s/tracking', $code), Client::METHOD_POST, - $statusUpdate + array('statusUpdate' => json_encode($statusUpdate)) ); } @@ -1419,6 +1475,54 @@ class ApiClient ); } + /** + * Get prices types + * + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function pricesTypes() + { + return $this->client->makeRequest( + '/reference/price-types', + Client::METHOD_GET + ); + } + + /** + * Edit price type + * + * @param array $data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function pricesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "name" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/price-types/%s/edit', $data['code']), + Client::METHOD_POST, + array('priceType' => json_encode($data)) + ); + } + /** * Get telephony settings * @@ -1652,6 +1756,32 @@ class ApiClient ); } + /** + * Edit marketplace configuration + * + * @param array $configuration + * + * @throws \RetailCrm\Exception\InvalidJsonException + * @throws \RetailCrm\Exception\CurlException + * @throws \InvalidArgumentException + * + * @return ApiResponse + */ + public function marketplaceSettingsEdit(array $configuration) + { + if (!count($configuration) || empty($configuration['code'])) { + throw new \InvalidArgumentException( + 'Parameter `configuration` must contains a data & configuration `code` must be set' + ); + } + + return $this->client->makeRequest( + sprintf('/marketplace/external/setting/%s/edit', $configuration['code']), + Client::METHOD_POST, + array('configuration' => json_encode($configuration)) + ); + } + /** * Update CRM basic statistic * diff --git a/intaro.retailcrm/classes/general/ApiClient_v5.php b/intaro.retailcrm/classes/general/ApiClient_v5.php new file mode 100644 index 00000000..268e6244 --- /dev/null +++ b/intaro.retailcrm/classes/general/ApiClient_v5.php @@ -0,0 +1,2469 @@ + + * @license https://opensource.org/licenses/MIT MIT License + * @link http://www.retailcrm.ru/docs/Developers/ApiVersion5 + */ + +namespace RetailCrm; + +use RetailCrm\Http\Client; +use RetailCrm\Response\ApiResponse; + +/** + * PHP version 5.3 + * + * API client class + * + * @category RetailCrm + * @package RetailCrm + * @author RetailCrm + * @license https://opensource.org/licenses/MIT MIT License + * @link http://www.retailcrm.ru/docs/Developers/ApiVersion5 + */ +class ApiClient +{ + + const VERSION = 'v5'; + + protected $client; + + /** + * Site code + */ + protected $siteCode; + + /** + * Client creating + * + * @param string $url api url + * @param string $apiKey api key + * @param string $site site code + * + * @throws \InvalidArgumentException + * + * @return mixed + */ + public function __construct($url, $apiKey, $site = null) + { + if ('/' !== $url[strlen($url) - 1]) { + $url .= '/'; + } + + $url = $url . 'api/' . self::VERSION; + + $this->client = new Client($url, array('apiKey' => $apiKey)); + $this->siteCode = $site; + } + + /** + * Returns users list + * + * @param array $filter + * @param null $page + * @param null $limit + * + * @throws \RetailCrm\Exception\InvalidJsonException + * @throws \RetailCrm\Exception\CurlException + * @throws \InvalidArgumentException + * + * @return ApiResponse + */ + public function usersList(array $filter = array(), $page = null, $limit = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/users', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Get user groups + * + * @param null $page + * @param null $limit + * + * @throws \RetailCrm\Exception\InvalidJsonException + * @throws \RetailCrm\Exception\CurlException + * + * @return ApiResponse + */ + public function usersGroups($page = null, $limit = null) + { + $parameters = array(); + + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/user-groups', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Change user status + * + * @param integer $id user ID + * @param string $status user status + * + * @return ApiResponse + */ + public function usersStatus($id, $status) + { + $statuses = array("free", "busy", "dinner", "break"); + + if (empty($status) || !in_array($status, $statuses)) { + throw new \InvalidArgumentException( + 'Parameter `status` must be not empty & must be equal one of these values: free|busy|dinner|break' + ); + } + + /** @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + "/users/$id/status", + Client::METHOD_POST, + array('status' => $status) + ); + } + + /** + * Returns user data + * + * @param integer $id user ID + * + * @throws \RetailCrm\Exception\InvalidJsonException + * @throws \RetailCrm\Exception\CurlException + * @throws \InvalidArgumentException + * + * @return ApiResponse + */ + public function usersGet($id) + { + return $this->client->makeRequest("/users/$id", Client::METHOD_GET); + } + + /** + * Returns filtered orders list + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersList(array $filter = array(), $page = null, $limit = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/orders', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Create a order + * + * @param array $order order data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersCreate(array $order, $site = null) + { + if (!count($order)) { + throw new \InvalidArgumentException( + 'Parameter `order` must contains a data' + ); + } + + return $this->client->makeRequest( + '/orders/create', + Client::METHOD_POST, + $this->fillSite($site, array('order' => json_encode($order))) + ); + } + + /** + * Save order IDs' (id and externalId) association in the CRM + * + * @param array $ids order identificators + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersFixExternalIds(array $ids) + { + if (! count($ids)) { + throw new \InvalidArgumentException( + 'Method parameter must contains at least one IDs pair' + ); + } + + return $this->client->makeRequest( + '/orders/fix-external-ids', + Client::METHOD_POST, + array('orders' => json_encode($ids) + ) + ); + } + + /** + * Returns statuses of the orders + * + * @param array $ids (default: array()) + * @param array $externalIds (default: array()) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersStatuses(array $ids = array(), array $externalIds = array()) + { + $parameters = array(); + + if (count($ids)) { + $parameters['ids'] = $ids; + } + if (count($externalIds)) { + $parameters['externalIds'] = $externalIds; + } + + return $this->client->makeRequest( + '/orders/statuses', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Upload array of the orders + * + * @param array $orders array of orders + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersUpload(array $orders, $site = null) + { + if (!count($orders)) { + throw new \InvalidArgumentException( + 'Parameter `orders` must contains array of the orders' + ); + } + + return $this->client->makeRequest( + '/orders/upload', + Client::METHOD_POST, + $this->fillSite($site, array('orders' => json_encode($orders))) + ); + } + + /** + * Get order by id or externalId + * + * @param string $id order identificator + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersGet($id, $by = 'externalId', $site = null) + { + $this->checkIdParameter($by); + + return $this->client->makeRequest( + "/orders/$id", + Client::METHOD_GET, + $this->fillSite($site, array('by' => $by)) + ); + } + + /** + * Edit a order + * + * @param array $order order data + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersEdit(array $order, $by = 'externalId', $site = null) + { + if (!count($order)) { + throw new \InvalidArgumentException( + 'Parameter `order` must contains a data' + ); + } + + $this->checkIdParameter($by); + + if (!array_key_exists($by, $order)) { + throw new \InvalidArgumentException( + sprintf('Order array must contain the "%s" parameter.', $by) + ); + } + + return $this->client->makeRequest( + sprintf('/orders/%s/edit', $order[$by]), + Client::METHOD_POST, + $this->fillSite( + $site, + array('order' => json_encode($order), 'by' => $by) + ) + ); + } + + /** + * Get orders history + * @param array $filter + * @param null $page + * @param null $limit + * + * @return ApiResponse + */ + public function ordersHistory(array $filter = array(), $page = null, $limit = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/orders/history', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Returns filtered customers list + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function customersList(array $filter = array(), $page = null, $limit = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/customers', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Create a customer + * + * @param array $customer customer data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function customersCreate(array $customer, $site = null) + { + if (! count($customer)) { + throw new \InvalidArgumentException( + 'Parameter `customer` must contains a data' + ); + } + + return $this->client->makeRequest( + '/customers/create', + Client::METHOD_POST, + $this->fillSite($site, array('customer' => json_encode($customer))) + ); + } + + /** + * Save customer IDs' (id and externalId) association in the CRM + * + * @param array $ids ids mapping + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function customersFixExternalIds(array $ids) + { + if (! count($ids)) { + throw new \InvalidArgumentException( + 'Method parameter must contains at least one IDs pair' + ); + } + + return $this->client->makeRequest( + '/customers/fix-external-ids', + Client::METHOD_POST, + array('customers' => json_encode($ids)) + ); + } + + /** + * Upload array of the customers + * + * @param array $customers array of customers + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function customersUpload(array $customers, $site = null) + { + if (! count($customers)) { + throw new \InvalidArgumentException( + 'Parameter `customers` must contains array of the customers' + ); + } + + return $this->client->makeRequest( + '/customers/upload', + Client::METHOD_POST, + $this->fillSite($site, array('customers' => json_encode($customers))) + ); + } + + /** + * Get customer by id or externalId + * + * @param string $id customer identificator + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function customersGet($id, $by = 'externalId', $site = null) + { + $this->checkIdParameter($by); + + return $this->client->makeRequest( + "/customers/$id", + Client::METHOD_GET, + $this->fillSite($site, array('by' => $by)) + ); + } + + /** + * Edit a customer + * + * @param array $customer customer data + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function customersEdit(array $customer, $by = 'externalId', $site = null) + { + if (!count($customer)) { + throw new \InvalidArgumentException( + 'Parameter `customer` must contains a data' + ); + } + + $this->checkIdParameter($by); + + if (!array_key_exists($by, $customer)) { + throw new \InvalidArgumentException( + sprintf('Customer array must contain the "%s" parameter.', $by) + ); + } + + return $this->client->makeRequest( + sprintf('/customers/%s/edit', $customer[$by]), + Client::METHOD_POST, + $this->fillSite( + $site, + array('customer' => json_encode($customer), 'by' => $by) + ) + ); + } + + /** + * Get customers history + * @param array $filter + * @param null $page + * @param null $limit + * + * @return ApiResponse + */ + public function customersHistory(array $filter = array(), $page = null, $limit = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/customers/history', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Combine orders + * + * @param array $order + * @param array $resultOrder + * @param string $technique + * + * @return ApiResponse + */ + public function ordersCombine($order, $resultOrder, $technique = 'ours') + { + $techniques = array('ours', 'summ', 'theirs'); + + if (!count($order) || !count($resultOrder)) { + throw new \InvalidArgumentException( + 'Parameters `order` & `resultOrder` must contains a data' + ); + } + + if (!in_array($technique, $techniques)) { + throw new \InvalidArgumentException( + 'Parameter `technique` must be on of ours|summ|theirs' + ); + } + + return $this->client->makeRequest( + '/orders/combine', + Client::METHOD_POST, + array( + 'technique' => $technique, + 'order' => json_encode($order), + 'resultOrder' => json_encode($resultOrder) + ) + ); + } + + /** + * Create an order payment + * + * @param array $payment order data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersPaymentCreate(array $payment, $site = null) + { + if (!count($payment)) { + throw new \InvalidArgumentException( + 'Parameter `payment` must contains a data' + ); + } + + return $this->client->makeRequest( + '/orders/payments/create', + Client::METHOD_POST, + $this->fillSite( + $site, + array('payment' => json_encode($payment)) + ) + ); + } + + /** + * Edit an order payment + * + * @param array $payment order data + * @param string $by by key + * @param null $site site code + * + * @return ApiResponse + */ + public function ordersPaymentEdit(array $payment, $by = 'id', $site = null) + { + if (!count($payment)) { + throw new \InvalidArgumentException( + 'Parameter `payment` must contains a data' + ); + } + + $this->checkIdParameter($by); + + if (!array_key_exists($by, $payment)) { + throw new \InvalidArgumentException( + sprintf('Order array must contain the "%s" parameter.', $by) + ); + } + + return $this->client->makeRequest( + sprintf('/orders/payments/%s/edit', $payment[$by]), + Client::METHOD_POST, + $this->fillSite( + $site, + array('payment' => json_encode($payment), 'by' => $by) + ) + ); + } + + /** + * Delete an order payment + * + * @param integer $id id order payment + * + * @return ApiResponse + */ + public function ordersPaymentDelete($id) + { + if (empty($id)) { + throw new \InvalidArgumentException( + 'Note id must be set' + ); + } + + return $this->client->makeRequest( + "/orders/payments/$id/delete", + Client::METHOD_POST + ); + } + + /** + * Combine customers + * + * @param array $customers + * @param array $resultCustomer + * + * @return ApiResponse + */ + public function customersCombine(array $customers, $resultCustomer) + { + + if (!count($customers) || !count($resultCustomer)) { + throw new \InvalidArgumentException( + 'Parameters `customers` & `resultCustomer` must contains a data' + ); + } + + return $this->client->makeRequest( + '/customers/combine', + Client::METHOD_POST, + array( + 'customers' => json_encode($customers), + 'resultCustomer' => json_encode($resultCustomer) + ) + ); + } + + /** + * Returns filtered customers notes list + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function customersNotesList(array $filter = array(), $page = null, $limit = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/customers/notes', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Create customer note + * + * @param array $note (default: array()) + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function customersNotesCreate($note, $site = null) + { + if (empty($note['customer']['id']) && empty($note['customer']['externalId'])) { + throw new \InvalidArgumentException( + 'Customer identifier must be set' + ); + } + + return $this->client->makeRequest( + '/customers/notes/create', + Client::METHOD_POST, + $this->fillSite($site, array('note' => json_encode($note))) + ); + } + + /** + * Delete customer note + * + * @param integer $id + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function customersNotesDelete($id) + { + if (empty($id)) { + throw new \InvalidArgumentException( + 'Note id must be set' + ); + } + + return $this->client->makeRequest( + "/customers/notes/$id/delete", + Client::METHOD_POST + ); + } + + /** + * Get custom fields list + * + * @param array $filter + * @param null $limit + * @param null $page + * + * @return ApiResponse + */ + public function customFieldsList(array $filter = array(), $limit = null, $page = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/custom-fields', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Create custom field + * + * @param $entity + * @param $customField + * + * @return ApiResponse + */ + public function customFieldsCreate($entity, $customField) + { + if (!count($customField) || + empty($customField['code']) || + empty($customField['name']) || + empty($customField['type']) + ) { + throw new \InvalidArgumentException( + 'Parameter `customField` must contain a data & fields `code`, `name` & `type` must be set' + ); + } + + if (empty($entity) || !in_array($entity, ['customer', 'order'])) { + throw new \InvalidArgumentException( + 'Parameter `entity` must contain a data & value must be `order` or `customer`' + ); + } + + return $this->client->makeRequest( + "/custom-fields/$entity/create", + Client::METHOD_POST, + array('customField' => json_encode($customField)) + ); + } + + /** + * Edit custom field + * + * @param $entity + * @param $customField + * + * @return ApiResponse + */ + public function customFieldsEdit($entity, $customField) + { + if (!count($customField) || empty($customField['code'])) { + throw new \InvalidArgumentException( + 'Parameter `customField` must contain a data & fields `code` must be set' + ); + } + + if (empty($entity) || !in_array($entity, ['customer', 'order'])) { + throw new \InvalidArgumentException( + 'Parameter `entity` must contain a data & value must be `order` or `customer`' + ); + } + + return $this->client->makeRequest( + "/custom-fields/$entity/edit/{$customField['code']}", + Client::METHOD_POST, + array('customField' => json_encode($customField)) + ); + } + + /** + * Get custom field + * + * @param $entity + * @param $code + * + * @return ApiResponse + */ + public function customFieldsGet($entity, $code) + { + if (empty($code)) { + throw new \InvalidArgumentException( + 'Parameter `code` must be not empty' + ); + } + + if (empty($entity) || !in_array($entity, ['customer', 'order'])) { + throw new \InvalidArgumentException( + 'Parameter `entity` must contain a data & value must be `order` or `customer`' + ); + } + + return $this->client->makeRequest( + "/custom-fields/$entity/$code", + Client::METHOD_GET + ); + } + + /** + * Get custom dictionaries list + * + * @param array $filter + * @param null $limit + * @param null $page + * + * @return ApiResponse + */ + public function customDictionariesList(array $filter = array(), $limit = null, $page = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/custom-fields/dictionaries', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Create custom dictionary + * + * @param $customDictionary + * + * @return ApiResponse + */ + public function customDictionariesCreate($customDictionary) + { + if (!count($customDictionary) || + empty($customDictionary['code']) || + empty($customDictionary['elements']) + ) { + throw new \InvalidArgumentException( + 'Parameter `dictionary` must contain a data & fields `code` & `elemets` must be set' + ); + } + + return $this->client->makeRequest( + "/custom-fields/dictionaries/{$customDictionary['code']}/create", + Client::METHOD_POST, + array('customDictionary' => json_encode($customDictionary)) + ); + } + + /** + * Edit custom dictionary + * + * @param $customDictionary + * + * @return ApiResponse + */ + public function customDictionariesEdit($customDictionary) + { + if (!count($customDictionary) || + empty($customDictionary['code']) || + empty($customDictionary['elements']) + ) { + throw new \InvalidArgumentException( + 'Parameter `dictionary` must contain a data & fields `code` & `elemets` must be set' + ); + } + + return $this->client->makeRequest( + "/custom-fields/dictionaries/{$customDictionary['code']}/edit", + Client::METHOD_POST, + array('customDictionary' => json_encode($customDictionary)) + ); + } + + /** + * Get custom dictionary + * + * @param $code + * + * @return ApiResponse + */ + public function customDictionariesGet($code) + { + if (empty($code)) { + throw new \InvalidArgumentException( + 'Parameter `code` must be not empty' + ); + } + + return $this->client->makeRequest( + "/custom-fields/dictionaries/$code", + Client::METHOD_GET + ); + } + + /** + * Get tasks list + * + * @param array $filter + * @param null $limit + * @param null $page + * + * @return ApiResponse + */ + public function tasksList(array $filter = array(), $limit = null, $page = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/tasks', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Create task + * + * @param array $task + * @param null $site + * + * @return ApiResponse + * + */ + public function tasksCreate($task, $site = null) + { + if (!count($task)) { + throw new \InvalidArgumentException( + 'Parameter `task` must contain a data' + ); + } + + return $this->client->makeRequest( + "/tasks/create", + Client::METHOD_POST, + $this->fillSite( + $site, + array('task' => json_encode($task)) + ) + ); + } + + /** + * Edit task + * + * @param array $task + * @param null $site + * + * @return ApiResponse + * + */ + public function tasksEdit($task, $site = null) + { + if (!count($task)) { + throw new \InvalidArgumentException( + 'Parameter `task` must contain a data' + ); + } + + return $this->client->makeRequest( + "/tasks/{$task['id']}/edit", + Client::METHOD_POST, + $this->fillSite( + $site, + array('task' => json_encode($task)) + ) + ); + } + + /** + * Get custom dictionary + * + * @param $id + * + * @return ApiResponse + */ + public function tasksGet($id) + { + if (empty($id)) { + throw new \InvalidArgumentException( + 'Parameter `id` must be not empty' + ); + } + + return $this->client->makeRequest( + "/tasks/$id", + Client::METHOD_GET + ); + } + + /** + * Get orders assembly list + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersPacksList(array $filter = array(), $page = null, $limit = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/orders/packs', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Create orders assembly + * + * @param array $pack pack data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersPacksCreate(array $pack, $site = null) + { + if (!count($pack)) { + throw new \InvalidArgumentException( + 'Parameter `pack` must contains a data' + ); + } + + return $this->client->makeRequest( + '/orders/packs/create', + Client::METHOD_POST, + $this->fillSite($site, array('pack' => json_encode($pack))) + ); + } + + /** + * Get orders assembly history + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersPacksHistory(array $filter = array(), $page = null, $limit = null) + { + $parameters = array(); + + if (count($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', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Get orders assembly by id + * + * @param string $id pack identificator + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersPacksGet($id) + { + if (empty($id)) { + throw new \InvalidArgumentException('Parameter `id` must be set'); + } + + return $this->client->makeRequest( + "/orders/packs/$id", + Client::METHOD_GET + ); + } + + /** + * Delete orders assembly by id + * + * @param string $id pack identificator + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersPacksDelete($id) + { + if (empty($id)) { + throw new \InvalidArgumentException('Parameter `id` must be set'); + } + + return $this->client->makeRequest( + sprintf('/orders/packs/%s/delete', $id), + Client::METHOD_POST + ); + } + + /** + * Edit orders assembly + * + * @param array $pack pack data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersPacksEdit(array $pack, $site = null) + { + if (!count($pack) || empty($pack['id'])) { + throw new \InvalidArgumentException( + 'Parameter `pack` must contains a data & pack `id` must be set' + ); + } + + return $this->client->makeRequest( + sprintf('/orders/packs/%s/edit', $pack['id']), + Client::METHOD_POST, + $this->fillSite($site, array('pack' => json_encode($pack))) + ); + } + + /** + * Get purchace prices & stock balance + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function storeInventories(array $filter = array(), $page = null, $limit = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/store/inventories', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Get store settings + * + * @param string $code get settings code + * + * @return ApiResponse + * @throws \RetailCrm\Exception\InvalidJsonException + * @throws \RetailCrm\Exception\CurlException + * @throws \InvalidArgumentException + * + * @return ApiResponse + */ + public function storeSettingsGet($code) + { + if (empty($code)) { + throw new \InvalidArgumentException('Parameter `code` must be set'); + } + + return $this->client->makeRequest( + "/store/setting/$code", + Client::METHOD_GET + ); + } + + /** + * Upload store inventories + * + * @param array $offers offers data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function storeInventoriesUpload(array $offers, $site = null) + { + if (!count($offers)) { + throw new \InvalidArgumentException( + 'Parameter `offers` must contains array of the offers' + ); + } + + return $this->client->makeRequest( + '/store/inventories/upload', + Client::METHOD_POST, + $this->fillSite($site, array('offers' => json_encode($offers))) + ); + } + + /** + * Upload store prices + * + * @param array $prices prices data + * @param string $site default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function storePricesUpload(array $prices, $site = null) + { + if (!count($prices)) { + throw new \InvalidArgumentException( + 'Parameter `prices` must contains array of the prices' + ); + } + + return $this->client->makeRequest( + '/store/prices/upload', + Client::METHOD_POST, + $this->fillSite($site, array('prices' => json_encode($prices))) + ); + } + + /** + * Get products + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function storeProducts(array $filter = array(), $page = null, $limit = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/store/products', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Get delivery settings + * + * @param string $code + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function deliverySettingsGet($code) + { + if (empty($code)) { + throw new \InvalidArgumentException('Parameter `code` must be set'); + } + + return $this->client->makeRequest( + "/delivery/generic/setting/$code", + Client::METHOD_GET + ); + } + + /** + * Edit delivery configuration + * + * @param array $configuration + * + * @throws \RetailCrm\Exception\InvalidJsonException + * @throws \RetailCrm\Exception\CurlException + * @throws \InvalidArgumentException + * + * @return ApiResponse + */ + public function deliverySettingsEdit(array $configuration) + { + if (!count($configuration) || empty($configuration['code'])) { + throw new \InvalidArgumentException( + 'Parameter `configuration` must contains a data & configuration `code` must be set' + ); + } + + return $this->client->makeRequest( + sprintf('/delivery/generic/setting/%s/edit', $configuration['code']), + Client::METHOD_POST, + array('configuration' => json_encode($configuration)) + ); + } + + /** + * Delivery tracking update + * + * @param string $code + * @param array $statusUpdate + * + * @throws \RetailCrm\Exception\InvalidJsonException + * @throws \RetailCrm\Exception\CurlException + * @throws \InvalidArgumentException + * + * @return ApiResponse + */ + public function deliveryTracking($code, array $statusUpdate) + { + if (empty($code)) { + throw new \InvalidArgumentException('Parameter `code` must be set'); + } + + if (!count($statusUpdate)) { + throw new \InvalidArgumentException( + 'Parameter `statusUpdate` must contains a data' + ); + } + + return $this->client->makeRequest( + sprintf('/delivery/generic/%s/tracking', $code), + Client::METHOD_POST, + array('statusUpdate' => json_encode($statusUpdate)) + ); + } + + /** + * Returns available county list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function countriesList() + { + return $this->client->makeRequest( + '/reference/countries', + Client::METHOD_GET + ); + } + + /** + * Returns deliveryServices list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function deliveryServicesList() + { + return $this->client->makeRequest( + '/reference/delivery-services', + Client::METHOD_GET + ); + } + + /** + * Edit deliveryService + * + * @param array $data delivery service data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function deliveryServicesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/delivery-services/%s/edit', $data['code']), + Client::METHOD_POST, + array('deliveryService' => json_encode($data)) + ); + } + + /** + * Returns deliveryTypes list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function deliveryTypesList() + { + return $this->client->makeRequest( + '/reference/delivery-types', + Client::METHOD_GET + ); + } + + /** + * Edit deliveryType + * + * @param array $data delivery type data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function deliveryTypesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/delivery-types/%s/edit', $data['code']), + Client::METHOD_POST, + array('deliveryType' => json_encode($data)) + ); + } + + /** + * Returns orderMethods list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function orderMethodsList() + { + return $this->client->makeRequest( + '/reference/order-methods', + Client::METHOD_GET + ); + } + + /** + * Edit orderMethod + * + * @param array $data order method data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function orderMethodsEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/order-methods/%s/edit', $data['code']), + Client::METHOD_POST, + array('orderMethod' => json_encode($data)) + ); + } + + /** + * Returns orderTypes list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function orderTypesList() + { + return $this->client->makeRequest( + '/reference/order-types', + Client::METHOD_GET + ); + } + + /** + * Edit orderType + * + * @param array $data order type data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function orderTypesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/order-types/%s/edit', $data['code']), + Client::METHOD_POST, + array('orderType' => json_encode($data)) + ); + } + + /** + * Returns paymentStatuses list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function paymentStatusesList() + { + return $this->client->makeRequest( + '/reference/payment-statuses', + Client::METHOD_GET + ); + } + + /** + * Edit paymentStatus + * + * @param array $data payment status data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function paymentStatusesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/payment-statuses/%s/edit', $data['code']), + Client::METHOD_POST, + array('paymentStatus' => json_encode($data)) + ); + } + + /** + * Returns paymentTypes list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function paymentTypesList() + { + return $this->client->makeRequest( + '/reference/payment-types', + Client::METHOD_GET + ); + } + + /** + * Edit paymentType + * + * @param array $data payment type data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function paymentTypesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/payment-types/%s/edit', $data['code']), + Client::METHOD_POST, + array('paymentType' => json_encode($data)) + ); + } + + /** + * Returns productStatuses list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function productStatusesList() + { + return $this->client->makeRequest( + '/reference/product-statuses', + Client::METHOD_GET + ); + } + + /** + * Edit productStatus + * + * @param array $data product status data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function productStatusesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/product-statuses/%s/edit', $data['code']), + Client::METHOD_POST, + array('productStatus' => json_encode($data)) + ); + } + + /** + * Get products groups + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function storeProductsGroups(array $filter = array(), $page = null, $limit = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/store/product-groups', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Returns sites list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function sitesList() + { + return $this->client->makeRequest( + '/reference/sites', + Client::METHOD_GET + ); + } + + /** + * Edit site + * + * @param array $data site data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function sitesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/sites/%s/edit', $data['code']), + Client::METHOD_POST, + array('site' => json_encode($data)) + ); + } + + /** + * Returns statusGroups list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function statusGroupsList() + { + return $this->client->makeRequest( + '/reference/status-groups', + Client::METHOD_GET + ); + } + + /** + * Returns statuses list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function statusesList() + { + return $this->client->makeRequest( + '/reference/statuses', + Client::METHOD_GET + ); + } + + /** + * Edit order status + * + * @param array $data status data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function statusesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/statuses/%s/edit', $data['code']), + Client::METHOD_POST, + array('status' => json_encode($data)) + ); + } + + /** + * Returns stores list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function storesList() + { + return $this->client->makeRequest( + '/reference/stores', + Client::METHOD_GET + ); + } + + /** + * Edit store + * + * @param array $data site data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function storesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "name" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/stores/%s/edit', $data['code']), + Client::METHOD_POST, + array('store' => json_encode($data)) + ); + } + + /** + * Get prices types + * + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function pricesTypes() + { + return $this->client->makeRequest( + '/reference/price-types', + Client::METHOD_GET + ); + } + + /** + * Edit price type + * + * @param array $data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function pricesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "name" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/price-types/%s/edit', $data['code']), + Client::METHOD_POST, + array('priceType' => json_encode($data)) + ); + } + + /** + * Get telephony settings + * + * @param string $code + * + * @throws \RetailCrm\Exception\InvalidJsonException + * @throws \RetailCrm\Exception\CurlException + * @throws \InvalidArgumentException + * + * @return ApiResponse + */ + public function telephonySettingsGet($code) + { + if (empty($code)) { + throw new \InvalidArgumentException('Parameter `code` must be set'); + } + + return $this->client->makeRequest( + "/telephony/setting/$code", + Client::METHOD_GET + ); + } + + /** + * Edit telephony settings + * + * @param string $code symbolic code + * @param string $clientId client id + * @param boolean $active telephony activity + * @param mixed $name service name + * @param mixed $makeCallUrl service init url + * @param mixed $image service logo url(svg file) + * + * @param array $additionalCodes + * @param array $externalPhones + * @param bool $allowEdit + * @param bool $inputEventSupported + * @param bool $outputEventSupported + * @param bool $hangupEventSupported + * @param bool $changeUserStatusUrl + * + * @return ApiResponse + */ + public function telephonySettingsEdit( + $code, + $clientId, + $active = false, + $name = false, + $makeCallUrl = false, + $image = false, + $additionalCodes = array(), + $externalPhones = array(), + $allowEdit = false, + $inputEventSupported = false, + $outputEventSupported = false, + $hangupEventSupported = false, + $changeUserStatusUrl = false + ) + { + if (!isset($code)) { + throw new \InvalidArgumentException('Code must be set'); + } + + $parameters['code'] = $code; + + if (!isset($clientId)) { + throw new \InvalidArgumentException('client id must be set'); + } + + $parameters['clientId'] = $clientId; + + if (!isset($active)) { + $parameters['active'] = false; + } else { + $parameters['active'] = $active; + } + + if (!isset($name)) { + throw new \InvalidArgumentException('name must be set'); + } + + if (isset($name)) { + $parameters['name'] = $name; + } + + if (isset($makeCallUrl)) { + $parameters['makeCallUrl'] = $makeCallUrl; + } + + if (isset($image)) { + $parameters['image'] = $image; + } + + if (isset($additionalCodes)) { + $parameters['additionalCodes'] = $additionalCodes; + } + + if (isset($externalPhones)) { + $parameters['externalPhones'] = $externalPhones; + } + + if (isset($allowEdit)) { + $parameters['allowEdit'] = $allowEdit; + } + + if (isset($inputEventSupported)) { + $parameters['inputEventSupported'] = $inputEventSupported; + } + + if (isset($outputEventSupported)) { + $parameters['outputEventSupported'] = $outputEventSupported; + } + + if (isset($hangupEventSupported)) { + $parameters['hangupEventSupported'] = $hangupEventSupported; + } + + if (isset($changeUserStatusUrl)) { + $parameters['changeUserStatusUrl'] = $changeUserStatusUrl; + } + + return $this->client->makeRequest( + "/telephony/setting/$code/edit", + Client::METHOD_POST, + array('configuration' => json_encode($parameters)) + ); + } + + /** + * Call event + * + * @param string $phone phone number + * @param string $type call type + * @param array $codes + * @param string $hangupStatus + * @param string $externalPhone + * @param array $webAnalyticsData + * + * @return ApiResponse + * @internal param string $code additional phone code + * @internal param string $status call status + * + */ + public function telephonyCallEvent( + $phone, + $type, + $codes, + $hangupStatus, + $externalPhone = null, + $webAnalyticsData = array() + ) + { + if (!isset($phone)) { + throw new \InvalidArgumentException('Phone number must be set'); + } + + if (!isset($type)) { + throw new \InvalidArgumentException('Type must be set (in|out|hangup)'); + } + + if (empty($codes)) { + throw new \InvalidArgumentException('Codes array must be set'); + } + + $parameters['phone'] = $phone; + $parameters['type'] = $type; + $parameters['codes'] = $codes; + $parameters['hangupStatus'] = $hangupStatus; + $parameters['callExternalId'] = $externalPhone; + $parameters['webAnalyticsData'] = $webAnalyticsData; + + + return $this->client->makeRequest( + '/telephony/call/event', + Client::METHOD_POST, + array('event' => json_encode($parameters)) + ); + } + + /** + * Upload calls + * + * @param array $calls calls data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function telephonyCallsUpload(array $calls) + { + if (!count($calls)) { + throw new \InvalidArgumentException( + 'Parameter `calls` must contains array of the calls' + ); + } + + return $this->client->makeRequest( + '/telephony/calls/upload', + Client::METHOD_POST, + array('calls' => json_encode($calls)) + ); + } + + /** + * Get call manager + * + * @param string $phone phone number + * @param bool $details detailed information + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function telephonyCallManager($phone, $details) + { + if (!isset($phone)) { + throw new \InvalidArgumentException('Phone number must be set'); + } + + $parameters['phone'] = $phone; + $parameters['details'] = isset($details) ? $details : 0; + + return $this->client->makeRequest( + '/telephony/manager', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Get segments list + * + * @param array $filter + * @param null $limit + * @param null $page + * + * @return ApiResponse + */ + public function segmentsList(array $filter = array(), $limit = null, $page = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/segments', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Update CRM basic statistic + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function statisticUpdate() + { + return $this->client->makeRequest( + '/statistic/update', + Client::METHOD_GET + ); + } + + /** + * Return current site + * + * @return string + */ + public function getSite() + { + return $this->siteCode; + } + + /** + * Set site + * + * @param string $site site code + * + * @return void + */ + public function setSite($site) + { + $this->siteCode = $site; + } + + /** + * Check ID parameter + * + * @param string $by identify by + * + * @throws \InvalidArgumentException + * + * @return bool + */ + protected function checkIdParameter($by) + { + $allowedForBy = array( + 'externalId', + 'id' + ); + + if (!in_array($by, $allowedForBy, false)) { + throw new \InvalidArgumentException( + sprintf( + 'Value "%s" for "by" param is not valid. Allowed values are %s.', + $by, + implode(', ', $allowedForBy) + ) + ); + } + + return true; + } + + /** + * Fill params by site value + * + * @param string $site site code + * @param array $params input parameters + * + * @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/intaro.retailcrm/classes/general/RCrmActions.php b/intaro.retailcrm/classes/general/RCrmActions.php index 6ab6be1d..a4bd509e 100644 --- a/intaro.retailcrm/classes/general/RCrmActions.php +++ b/intaro.retailcrm/classes/general/RCrmActions.php @@ -4,6 +4,7 @@ class RCrmActions { public static $MODULE_ID = 'intaro.retailcrm'; public static $CRM_ORDER_FAILED_IDS = 'order_failed_ids'; + public static $CRM_API_VERSION = 'api_version'; const CANCEL_PROPERTY_CODE = 'INTAROCRM_IS_CANCELED'; @@ -41,8 +42,17 @@ class RCrmActions $bitrixDeliveryTypesList = array(); $arDeliveryServiceAll = \Bitrix\Sale\Delivery\Services\Manager::getActiveList(); $noOrderId = \Bitrix\Sale\Delivery\Services\EmptyDeliveryService::getEmptyDeliveryServiceId(); + $groups = array(); foreach ($arDeliveryServiceAll as $arDeliveryService) { - if (($arDeliveryService['PARENT_ID'] == '0' || $arDeliveryService['PARENT_ID'] == null) && $arDeliveryService['ID'] != $noOrderId) { + if ($arDeliveryService['CLASS_NAME'] == '\Bitrix\Sale\Delivery\Services\Group') { + $groups[] = $arDeliveryService['ID']; + } + } + foreach ($arDeliveryServiceAll as $arDeliveryService) { + if ((($arDeliveryService['PARENT_ID'] == '0' || $arDeliveryService['PARENT_ID'] == null) || + in_array($arDeliveryService['PARENT_ID'], $groups)) && + $arDeliveryService['ID'] != $noOrderId && + $arDeliveryService['CLASS_NAME'] != '\Bitrix\Sale\Delivery\Services\Group') { $bitrixDeliveryTypesList[] = $arDeliveryService; } } @@ -63,7 +73,7 @@ class RCrmActions return $bitrixPaymentTypesList; } - + public static function StatusesList() { $bitrixPaymentStatusesList = array(); @@ -79,8 +89,8 @@ class RCrmActions } return $bitrixPaymentStatusesList; - } - + } + public static function OrderPropsList() { $bitrixPropsList = array(); @@ -93,6 +103,57 @@ class RCrmActions return $bitrixPropsList; } + + public static function PricesExportList() + { + $priceId = COption::GetOptionString(self::$MODULE_ID, 'catalog_base_price', 0); + $catalogExportPrices = array(); + $dbPriceType = CCatalogGroup::GetList(array(), array('!ID' => $priceId), false, false, array('ID', 'NAME', 'NAME_LANG')); + while ($arPriceType = $dbPriceType->Fetch()) + { + $catalogExportPrices[$arPriceType['ID']] = $arPriceType; + } + + return $catalogExportPrices; + } + + public static function StoresExportList() + { + $catalogExportStores = array(); + $dbStores = CCatalogStore::GetList(array(), array("ACTIVE" => "Y"), false, false, array('ID', 'TITLE')); + while ($stores = $dbStores->Fetch()) { + $catalogExportStores[] = $stores; + } + + return $catalogExportStores; + } + + public static function IblocksExportList() + { + $catalogExportIblocks = array(); + $dbIblocks = CIBlock::GetList(array("IBLOCK_TYPE" => "ASC", "NAME" => "ASC"), array('CHECK_PERMISSIONS' => 'Y','MIN_PERMISSION' => 'W')); + while ($iblock = $dbIblocks->Fetch()) { + if ($arCatalog = CCatalog::GetByIDExt($iblock["ID"])) { + if($arCatalog['CATALOG_TYPE'] == "D" || $arCatalog['CATALOG_TYPE'] == "X" || $arCatalog['CATALOG_TYPE'] == "P") { + $catalogExportIblocks[$iblock['ID']] = array( + 'ID' => $iblock['ID'], + 'IBLOCK_TYPE_ID' => $iblock['IBLOCK_TYPE_ID'], + 'LID' => $iblock['LID'], + 'CODE' => $iblock['CODE'], + 'NAME' => $iblock['NAME'], + ); + + if ($arCatalog['CATALOG_TYPE'] == "X" || $arCatalog['CATALOG_TYPE'] == "P") { + $iblockOffer = CCatalogSKU::GetInfoByProductIBlock($iblock["ID"]); + $catalogExportIblocks[$iblock['ID']]['SKU'] = $iblockOffer; + } + } + } + } + + return $catalogExportIblocks; + } + /** * * w+ event in bitrix log @@ -124,7 +185,7 @@ class RCrmActions RetailCrmOrder::uploadOrders(50, true); } - return 'RCrmActions::uploadOrdersAgent();'; + return; } /** @@ -199,10 +260,14 @@ class RCrmActions public static function explodeFIO($fio) { - $fio = preg_replace('|[\s]+|s', ' ', trim($fio)); - $newFio = empty($fio) ? false : explode(" ", $fio, 3); - $result = array(); + $fio = preg_replace('|[\s]+|s', ' ', trim($fio)); + if (empty($fio)) { + return $result; + } else { + $newFio = explode(" ", $fio, 3); + } + switch (count($newFio)) { default: case 0: @@ -232,61 +297,114 @@ class RCrmActions public static function apiMethod($api, $methodApi, $method, $params, $site = null) { switch ($methodApi) { + case 'ordersPaymentDelete': + case 'ordersHistory': + case 'customerHistory': + case 'ordersFixExternalIds': + case 'customersFixExternalIds': + return self::proxy($api, $methodApi, $method, array($params)); + + case 'orderGet': + return self::proxy($api, 'ordersGet', $method, array($params, 'id', $site)); + case 'ordersGet': case 'ordersEdit': case 'customersGet': case 'customersEdit': - try { - $result = $api->$methodApi($params, 'externalId', $site); - if (isset($result['errorMsg'])) { - self::eventLog(__CLASS__.'::'.$method, 'RetailCrm\ApiClient::'.$methodApi, $result['errorMsg']); - - $log = new Logger(); - $log->write(array($methodApi, $result['errorMsg'], $result['errors'], $params), 'apiErrors'); - } - } catch (\RetailCrm\Exception\CurlException $e) { - self::eventLog( - __CLASS__.'::'.$method, 'RetailCrm\ApiClient::'.$methodApi.'::CurlException', - $e->getCode() . ': ' . $e->getMessage() - ); - - return false; - } catch (InvalidArgumentException $e) { - self::eventLog( - __CLASS__.'::'.$method, 'RetailCrm\ApiClient::'.$methodApi.'::InvalidArgumentException', - $e->getCode() . ': ' . $e->getMessage() - ); - - return false; - } - return $result; + case 'ordersPaymentEdit': + return self::proxy($api, $methodApi, $method, array($params, 'externalId', $site)); default: - try { - $result = $api->$methodApi($params, $site); - if (isset($result['errorMsg'])) { - if ($methodApi != 'customersUpload' && $methodApi != 'ordersUpload') { - self::eventLog(__CLASS__.'::'.$method, 'RetailCrm\ApiClient::'.$methodApi, $result['errorMsg']); - } - $log = new Logger(); - $log->write(array($methodApi, $result['errorMsg'], $result['errors'], $params), 'apiErrors'); - } - } catch (\RetailCrm\Exception\CurlException $e) { - self::eventLog( - __CLASS__.'::'.$method, 'RetailCrm\ApiClient::'.$methodApi.'::CurlException', - $e->getCode() . ': ' . $e->getMessage() - ); - - return false; - } catch (InvalidArgumentException $e) { - self::eventLog( - __CLASS__.'::'.$method, 'RetailCrm\ApiClient::'.$methodApi.'::InvalidArgumentException', - $e->getCode() . ': ' . $e->getMessage() - ); - - return false; - } - return $result; + return self::proxy($api, $methodApi, $method, array($params, $site)); } } + + private function proxy($api, $methodApi, $method, $params) { + $log = new Logger(); + $version = COption::GetOptionString(self::$MODULE_ID, self::$CRM_API_VERSION, 0); + try { + $result = call_user_func_array(array($api, $methodApi), $params); + + if ($result->getStatusCode() !== 200 && $result->getStatusCode() !== 201) { + if ($methodApi == 'ordersGet' || $methodApi == 'customersGet') { + $log->write(array( + 'api' => $version, + 'methodApi' => $methodApi, + 'errorMsg' => !empty($result['errorMsg']) ? $result['errorMsg'] : '', + 'errors' => !empty($result['errors']) ? $result['errors'] : '', + 'params' => $params + ), 'apiErrors'); + } elseif ($methodApi == 'customersUpload' || $methodApi == 'ordersUpload') { + $log->write(array( + 'api' => $version, + 'methodApi' => $methodApi, + 'errorMsg' => !empty($result['errorMsg']) ? $result['errorMsg'] : '', + 'errors' => !empty($result['errors']) ? $result['errors'] : '', + 'params' => $params + ), 'uploadApiErrors'); + } else { + self::eventLog(__CLASS__ . '::' . $method, 'RetailCrm\ApiClient::' . $methodApi, !empty($result['errorMsg']) ? $result['errorMsg'] : ''); + $log->write(array( + 'api' => $version, + 'methodApi' => $methodApi, + 'errorMsg' => !empty($result['errorMsg']) ? $result['errorMsg'] : '', + 'errors' => !empty($result['errors']) ? $result['errors'] : '', + 'params' => $params + ), 'apiErrors'); + } + + if (function_exists('retailCrmApiResult')) { + retailCrmApiResult($methodApi, false, $result->getStatusCode()); + } + + if ($result->getStatusCode() == 460) { + return true; + } + + return false; + } + } catch (\RetailCrm\Exception\CurlException $e) { + self::eventLog( + __CLASS__ . '::' . $method, 'RetailCrm\ApiClient::' . $methodApi . '::CurlException', + $e->getCode() . ': ' . $e->getMessage() + ); + $log->write(array( + 'api' => $version, + 'methodApi' => $methodApi, + 'errorMsg' => $e->getMessage(), + 'errors' => $e->getCode(), + 'params' => $params + ), 'apiErrors'); + + if (function_exists('retailCrmApiResult')) { + retailCrmApiResult($methodApi, false, 'CurlException'); + } + + return false; + } catch (InvalidArgumentException $e) { + self::eventLog( + __CLASS__ . '::' . $method, 'RetailCrm\ApiClient::' . $methodApi . '::InvalidArgumentException', + $e->getCode() . ': ' . $e->getMessage() + ); + $log->write(array( + 'api' => $version, + 'methodApi' => $methodApi, + 'errorMsg' => $e->getMessage(), + 'errors' => $e->getCode(), + 'params' => $params + ), 'apiErrors'); + + if (function_exists('retailCrmApiResult')) { + retailCrmApiResult($methodApi, false, 'ArgumentException'); + } + + return false; + } + + if (function_exists('retailCrmApiResult')) { + retailCrmApiResult($methodApi, true, $result->getStatusCode()); + } + + return $result; + } } diff --git a/intaro.retailcrm/classes/general/collector/RetailCrmCollector.php b/intaro.retailcrm/classes/general/collector/RetailCrmCollector.php new file mode 100644 index 00000000..dfe23319 --- /dev/null +++ b/intaro.retailcrm/classes/general/collector/RetailCrmCollector.php @@ -0,0 +1,32 @@ +IsAuthorized()) { + $params['customerId'] = $USER->GetID(); + } + + $str = ""; + $APPLICATION->AddHeadString($str, true); + } else { + return false; + } + } +} diff --git a/intaro.retailcrm/classes/general/config/objects.xml b/intaro.retailcrm/classes/general/config/objects.xml index 83346601..eacca5d8 100644 --- a/intaro.retailcrm/classes/general/config/objects.xml +++ b/intaro.retailcrm/classes/general/config/objects.xml @@ -71,6 +71,13 @@ discountPercent quantity status + discountTotal + + status + type + externalId + amount + comment code service diff --git a/intaro.retailcrm/classes/general/config/retailcrm.json b/intaro.retailcrm/classes/general/config/retailcrm.json index cace223f..acdad710 100644 --- a/intaro.retailcrm/classes/general/config/retailcrm.json +++ b/intaro.retailcrm/classes/general/config/retailcrm.json @@ -131,11 +131,11 @@ "type": "string" }, "managerId": { - "type": "int" + "type": "int" }, "browserId": { "type": "string" - } + } }, "orders": { "number": { @@ -149,6 +149,19 @@ "type": "datetime", "format": "Y-m-d H:i:s" }, + "discountManualAmount": { + "type": "double", + "default": 0, + "min": 0, + "decimals": 2 + }, + "discountManualPercent": { + "type": "double", + "default": 0, + "max": 100, + "min": 0, + "decimals": 2 + }, "discount": { "type": "double", "default": 0, @@ -287,6 +300,19 @@ "paymentStatus": { "type": "string" }, + "type": { + "type": "string" + }, + "amount": { + "type": "double", + "default": 0, + "min": 0, + "decimals": 2 + }, + "paidAt": { + "type": "datetime", + "format": "Y-m-d H:i:s" + }, "status": { "type": "string" }, diff --git a/intaro.retailcrm/classes/general/events/RetailCrmEvent.php b/intaro.retailcrm/classes/general/events/RetailCrmEvent.php index dd696497..a3e2b38d 100644 --- a/intaro.retailcrm/classes/general/events/RetailCrmEvent.php +++ b/intaro.retailcrm/classes/general/events/RetailCrmEvent.php @@ -2,6 +2,7 @@ /** * RCrmEvent */ +use \Bitrix\Main\Event; class RetailCrmEvent { protected static $MODULE_ID = 'intaro.retailcrm'; @@ -47,29 +48,7 @@ class RetailCrmEvent } return true; - } - - /** - * onBeforeOrderAdd - * - * @param mixed $arFields - User arFields - */ -// function onBeforeOrderAdd($arFields = array()) { -// $GLOBALS['RETAILCRM_ORDER_OLD_EVENT'] = false; -// return; -// } - - /** - * OnOrderSave - * - * @param mixed $ID - Order id - * @param mixed $arFields - Order arFields - */ -// function OnOrderSave($ID, $arFields, $arOrder, $isNew) -// { -// $GLOBALS['RETAILCRM_EVENT_OLD'] = true; -// return; -// } + } /** * onUpdateOrder @@ -84,7 +63,8 @@ class RetailCrmEvent return; } - $GLOBALS['RETAILCRM_ORDER_OLD_EVENT'] = true; + $GLOBALS['RETAILCRM_ORDER_OLD_EVENT'] = true; + return; } @@ -95,7 +75,8 @@ class RetailCrmEvent */ function orderDelete($event) { - $GLOBALS['RETAILCRM_ORDER_DELETE'] = true; + $GLOBALS['RETAILCRM_ORDER_DELETE'] = true; + return; } @@ -110,26 +91,30 @@ class RetailCrmEvent if ($GLOBALS['RETAILCRM_ORDER_OLD_EVENT'] !== false && $GLOBALS['RETAIL_CRM_HISTORY'] !== true && $GLOBALS['RETAILCRM_ORDER_DELETE'] !== true) { if (!CModule::IncludeModule('iblock')) { RCrmActions::eventLog('RetailCrmEvent::orderSave', 'iblock', 'module not found'); + return true; } if (!CModule::IncludeModule("sale")) { RCrmActions::eventLog('RetailCrmEvent::orderSave', 'sale', 'module not found'); + return true; } if (!CModule::IncludeModule("catalog")) { RCrmActions::eventLog('RetailCrmEvent::orderSave', 'catalog', 'module not found'); + return true; } - //проверка на существование getParameter("ENTITY") + //exists getParameter("ENTITY") if (method_exists($event, 'getId')) { $obOrder = $event; } elseif (method_exists($event, 'getParameter')) { $obOrder = $event->getParameter("ENTITY"); } else { RCrmActions::eventLog('RetailCrmEvent::orderSave', 'events', 'event error'); + return true; } @@ -165,13 +150,18 @@ class RetailCrmEvent 'optionsCustomFields' => $optionsCustomFields )); - //многосайтовость - $site = count($optionsSitesList) > 1 ? $optionsSitesList[$arOrder['LID']] : null; + //many sites? + if(!empty($optionsSitesList) && array_key_exists($arOrder['LID'], $optionsSitesList)) { + $site = $optionsSitesList[$arOrder['LID']]; + } else { + $site = null; + } - //проверка на новый заказ + //new order? $orderCrm = RCrmActions::apiMethod($api, 'ordersGet', __METHOD__, $arOrder['ID'], $site); if (isset($orderCrm['order'])) { $methodApi = 'ordersEdit'; + $arParams['crmOrder'] = $orderCrm['order']; } else { $methodApi = 'ordersCreate'; } @@ -183,6 +173,7 @@ class RetailCrmEvent $resultUser = RetailCrmUser::customerSend($arUser, $api, $optionsContragentType[$arOrder['PERSON_TYPE_ID']], true, $site); if (!$resultUser) { RCrmActions::eventLog('RetailCrmEvent::orderSave', 'RetailCrmUser::customerSend', 'error during creating customer'); + return true; } } @@ -191,12 +182,13 @@ class RetailCrmEvent $resultOrder = RetailCrmOrder::orderSend($arOrder, $api, $arParams, true, $site, $methodApi); if (!$resultOrder) { RCrmActions::eventLog('RetailCrmEvent::orderSave', 'RetailCrmOrder::orderSend', 'error during creating order'); + return true; } return true; } - - return; + + return true; } } \ No newline at end of file diff --git a/intaro.retailcrm/classes/general/history/FastOrderHistory.php b/intaro.retailcrm/classes/general/history/FastOrderHistory.php new file mode 100644 index 00000000..1149acf2 --- /dev/null +++ b/intaro.retailcrm/classes/general/history/FastOrderHistory.php @@ -0,0 +1,31 @@ +RestartBuffer(); +$moduleId = 'intaro.retailcrm'; +$historyTime = 'history_time'; +$idOrderCRM = (int)$_REQUEST['idOrderCRM']; + +if (CModule::IncludeModule($moduleId) && $idOrderCRM && $idOrderCRM > 0) { + $timeBd = COption::GetOptionString($moduleId, $historyTime, 0); + $nowDate = date('Y-m-d H:i:s'); + if (!empty($timeBd)) { + $timeBdObj = new \DateTime($timeBd); + $newTimeBdObj = $timeBdObj->modify('+5 min'); + $nowDateObj = new \DateTime($nowDate); + //If there is a record, but it is older than 5 minutes, overwrite + if ($newTimeBdObj < $nowDateObj) { + COption::SetOptionString($moduleId, $historyTime, $nowDate); + //call history + RCrmActions::orderAgent(); + + COption::RemoveOption($moduleId, $historyTime); + } + } else { + COption::SetOptionString($moduleId, $historyTime, $nowDate); + //call history + RCrmActions::orderAgent(); + + COption::RemoveOption($moduleId, $historyTime); + } +} \ No newline at end of file diff --git a/intaro.retailcrm/classes/general/history/RetailCrmHistory.php b/intaro.retailcrm/classes/general/history/RetailCrmHistory_v4.php similarity index 84% rename from intaro.retailcrm/classes/general/history/RetailCrmHistory.php rename to intaro.retailcrm/classes/general/history/RetailCrmHistory_v4.php index 64eef64e..240c5887 100644 --- a/intaro.retailcrm/classes/general/history/RetailCrmHistory.php +++ b/intaro.retailcrm/classes/general/history/RetailCrmHistory_v4.php @@ -29,14 +29,17 @@ class RetailCrmHistory { if (!CModule::IncludeModule("iblock")) { RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'iblock', 'module not found'); + return false; } if (!CModule::IncludeModule("sale")) { RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'sale', 'module not found'); + return false; } if (!CModule::IncludeModule("catalog")) { RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'catalog', 'module not found'); + return false; } @@ -47,34 +50,26 @@ class RetailCrmHistory $historyFilter = array(); $historyStart = COption::GetOptionString(self::$MODULE_ID, self::$CRM_CUSTOMER_HISTORY); + if ($historyStart && $historyStart > 0) { $historyFilter['sinceId'] = $historyStart; } - + while (true) { - try { - $customerHistory = $api->customersHistory($historyFilter); - } catch (\RetailCrm\Exception\CurlException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::customerHistory', 'RetailCrm\RestApi::customersHistory::CurlException', - $e->getCode() . ': ' . $e->getMessage() - ); - - return false; - } catch (InvalidArgumentException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::customerHistory', 'RetailCrm\RestApi::customersHistory::InvalidArgumentException', - $e->getCode() . ': ' . $e->getMessage() - ); - - return false; - } + $customerHistory = RCrmActions::apiMethod($api, 'ordersHistory', __METHOD__, $historyFilter); $customerH = isset($customerHistory['history']) ? $customerHistory['history'] : array(); $log = new Logger(); $log->write($customerH, 'customerHistory'); - if(count($customerH) == 0){ + + if (count($customerH) == 0) { + if ($customerHistory['history']['totalPageCount'] > $customerHistory['history']['currentPage']) { + $historyFilter['page'] = $customerHistory['history']['currentPage'] + 1; + + continue; + } + return true; } @@ -89,6 +84,10 @@ class RetailCrmHistory $newResCustomer = retailCrmBeforeCustomerSave($customer); if (is_array($newResCustomer) && !empty($newResCustomer)) { $customer = $newResCustomer; + } elseif ($newResCustomer === false) { + RCrmActions::eventLog('RetailCrmHistory::customerHistory', 'retailCrmBeforeCustomerSave()', 'UserCrmId = ' . $customer['id'] . '. Sending canceled after retailCrmBeforeCustomerSave'); + + continue; } } @@ -137,23 +136,10 @@ class RetailCrmHistory continue; } - try { - $api->customersFixExternalIds(array(array('id' => $customer['id'], 'externalId' => $registeredUserID))); - } catch (\RetailCrm\Exception\CurlException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::orderHistory', 'RetailCrm\RestApi::customerFixExternalIds::CurlException', - $e->getCode() . ': ' . $e->getMessage() - ); - - continue; - } catch (InvalidArgumentException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::orderHistory', 'RetailCrm\RestApi::customerFixExternalIds::InvalidArgumentException', - $e->getCode() . ': ' . $e->getMessage() - ); - - continue; + if(RCrmActions::apiMethod($api, 'customersFixExternalIds', __METHOD__, array(array('id' => $customer['id'], 'externalId' => $registeredUserID))) == false) { + continue; } + } $customer['externalId'] = $registeredUserID; @@ -171,9 +157,9 @@ class RetailCrmHistory $arUser["SECOND_NAME"] = $customer['patronymic'] ? RCrmActions::fromJSON($customer['patronymic']) : ''; } - if (array_key_exists('email', $customer)) { - $arUser["EMAIL"] = $customer['email'] ? RCrmActions::fromJSON($customer['email']) : ''; - } +// if (array_key_exists('email', $customer)) { +// $arUser["EMAIL"] = $customer['email'] ? RCrmActions::fromJSON($customer['email']) : ''; +// } if (isset($customer['phones'])) { $user = CUser::GetList(($by="ID"), ($order="desc"), array('ID' => $customer['externalId']), array('FIELDS' => array('PERSONAL_PHONE', 'PERSONAL_MOBILE')))->fetch(); @@ -222,14 +208,14 @@ class RetailCrmHistory $GLOBALS['RETAIL_CRM_HISTORY'] = false; - //запоминаем номер последнего изменения + //last id $end = array_pop($customerH); COption::SetOptionString(self::$MODULE_ID, self::$CRM_CUSTOMER_HISTORY, $end['id']); if ($customerHistory['pagination']['totalPageCount'] == 1) { return true; } - //новый фильтр для истории + //new filter $historyFilter['sinceId'] = $end['id']; } } @@ -242,14 +228,17 @@ class RetailCrmHistory } if (!CModule::IncludeModule("iblock")) { RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'iblock', 'module not found'); + return false; } if (!CModule::IncludeModule("sale")) { RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'sale', 'module not found'); + return false; } if (!CModule::IncludeModule("catalog")) { RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'catalog', 'module not found'); + return false; } @@ -278,29 +267,20 @@ class RetailCrmHistory } while (true) { - try { - $orderHistory = $api->ordersHistory($historyFilter); - } catch (\RetailCrm\Exception\CurlException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::orderHistory', 'RetailCrm\RestApi::ordersHistory::CurlException', - $e->getCode() . ': ' . $e->getMessage() - ); - - return false; - } catch (InvalidArgumentException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::orderHistory', 'RetailCrm\RestApi::ordersHistory::InvalidArgumentException', - $e->getCode() . ': ' . $e->getMessage() - ); - - return false; - } + $orderHistory = RCrmActions::apiMethod($api, 'ordersHistory', __METHOD__, $historyFilter); $orderH = isset($orderHistory['history']) ? $orderHistory['history'] : array(); $log = new Logger(); $log->write($orderH, 'orderHistory'); + if (count($orderH) == 0) { + if ($orderHistory['history']['totalPageCount'] > $orderHistory['history']['currentPage']) { + $historyFilter['page'] = $orderHistory['history']['currentPage'] + 1; + + continue; + } + return true; } @@ -308,12 +288,16 @@ class RetailCrmHistory $GLOBALS['RETAIL_CRM_HISTORY'] = true; - //обработка заказа + //orders with changes foreach ($orders as $order) { if (function_exists('retailCrmBeforeOrderSave')) { $newResOrder = retailCrmBeforeOrderSave($order); if (is_array($newResOrder) && !empty($newResOrder)) { $order = $newResOrder; + } elseif ($newResOrder === false) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'retailCrmBeforeOrderSave()', 'OrderCrmId = ' . $order['id'] . '. Sending canceled after retailCrmBeforeOrderSave'); + + continue; } } @@ -370,62 +354,40 @@ class RetailCrmHistory if ($order['customer']['phones'][1]) { $arFields['PERSONAL_MOBILE'] = $order['customer']['phones'][1]; } - + $registeredUserID = $newUser->Add($arFields); - + if ($registeredUserID === false) { RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'CUser::Register', 'Error register user'); + continue; } - try { - $api->customersFixExternalIds(array(array('id' => $order['customer']['id'], 'externalId' => $registeredUserID))); - } catch (\RetailCrm\Exception\CurlException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::orderHistory', 'RetailCrm\RestApi::customerFixExternalIds::CurlException', - $e->getCode() . ': ' . $e->getMessage() - ); - - continue; - } catch (InvalidArgumentException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::orderHistory', 'RetailCrm\RestApi::customerFixExternalIds::InvalidArgumentException', - $e->getCode() . ': ' . $e->getMessage() - ); - - continue; + if(RCrmActions::apiMethod($api, 'customersFixExternalIds', __METHOD__, array(array('id' => $order['customer']['id'], 'externalId' => $registeredUserID))) == false) { + continue; } } $order['customer']['externalId'] = $registeredUserID; } - if ($optionsSitesList) { + if (isset($optionsSitesList)) { $site = array_search($order['site'], $optionsSitesList); } else { $site = CSite::GetDefSite(); } + if (empty($site)) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::create', 'Site = ' . $order['site'] . ' not found in setting. Order crm id=' . $order['id']); + + continue; + } $newOrder = Bitrix\Sale\Order::create($site, $order['customer']['externalId']); - $newOrder = $newOrder->save(); + $newOrder->save(); $externalId = $newOrder->getId(); if (isset($externalId)) { - try { - $api->ordersFixExternalIds(array(array('id' => $order['id'], 'externalId' => $externalId))); - } catch (\RetailCrm\Exception\CurlException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::orderHistory', 'RetailCrm\RestApi::orderFixExternalIds::CurlException', - $e->getCode() . ': ' . $e->getMessage() - ); - - continue; - } catch (InvalidArgumentException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::orderHistory', 'RetailCrm\RestApi::orderFixExternalIds::InvalidArgumentException', - $e->getCode() . ': ' . $e->getMessage() - ); - + if(RCrmActions::apiMethod($api, 'ordersFixExternalIds', __METHOD__, array(array('id' => $order['id'], 'externalId' => $externalId))) == false){ continue; } } else { @@ -436,20 +398,43 @@ class RetailCrmHistory if (isset($order['externalId']) && $order['externalId']) { $itemUpdate = false; - $newOrder = Bitrix\Sale\Order::load($order['externalId']); + try { + $newOrder = Bitrix\Sale\Order::load($order['externalId']); + } catch (Bitrix\Main\ArgumentNullException $e) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::load', $e->getMessage() . ': ' . $order['externalId']); + continue; + } if (!$newOrder instanceof \Bitrix\Sale\Order) { RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::load', 'Error order load id=' . $order['externalId']); continue; } - + if ($optionsSitesList) { $site = array_search($order['site'], $optionsSitesList); } else { $site = CSite::GetDefSite(); } + if (empty($site)) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::edit', 'Site = ' . $order['site'] . ' not found in setting. Order id=' . $order['externalId']); + + continue; + } if ($optionsOrderNumbers == 'Y' && isset($order['number'])) { + $searchFilter = array( + 'filter' => array('ACCOUNT_NUMBER' => $order['number']), + 'select' => array('ID'), + ); + $searchOrder = reset(Bitrix\Sale\Order::loadByFilter($searchFilter)); + if (!empty($searchOrder)) { + if ($searchOrder->getId() != $order['externalId']) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'setField("ACCOUNT_NUMBER")', 'Error order load id=' . $order['externalId']) . '. Number ' . $order['number'] . ' already exists'; + + continue; + } + } + $newOrder->setField('ACCOUNT_NUMBER', $order['number']); } @@ -484,10 +469,11 @@ class RetailCrmHistory } } - if (array_key_exists('statusComment', $order)) { + if (array_key_exists('statusComment', $order)) { self::setProp($newOrder, RCrmActions::fromJSON($order['statusComment']), 'REASON_CANCELED'); - } + } + //props $propertyCollection = $newOrder->getPropertyCollection(); $propertyCollectionArr = $propertyCollection->getArray(); $nProps = array(); @@ -500,20 +486,13 @@ class RetailCrmHistory } $propertyCollectionArr['properties'] = $nProps; - if ($propsRemove) {//удаляем старые свойства + if ($propsRemove) {//delete props foreach ($propertyCollectionArr['properties'] as $orderProp) { $somePropValue = $propertyCollection->getItemByOrderPropertyId($orderProp['ID']); self::setProp($somePropValue); } + $orderCrm = RCrmActions::apiMethod($api, 'orderGet', __METHOD__, $order['id']); - try { - $orderCrm = $api->ordersGet($order['id'], 'id', $order['site']); - } catch (\RetailCrm\Exception\CurlException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::orderHistory', 'RetailCrm\RestApi::ordersGet0::CurlException', - $e->getCode() . ': ' . $e->getMessage() - ); - } $orderDump = $order; $order = $orderCrm['order']; } @@ -562,22 +541,28 @@ class RetailCrmHistory } } elseif (array_key_exists($key, $order['delivery']['address'])) { if ($propsKey[$orderProp]['TYPE'] == 'LOCATION') { + $order['delivery']['address'][$key] = trim($order['delivery']['address'][$key]); if(!empty($order['delivery']['address'][$key])){ $parameters = array(); $loc = explode('.', $order['delivery']['address'][$key]); if (count($loc) == 1) { - $parameters['filter']['NAME'] = RCrmActions::fromJSON(trim($loc[0])); + $parameters['filter']['PHRASE'] = RCrmActions::fromJSON(trim($loc[0])); } elseif (count($loc) == 2) { - $parameters['filter']['NAME'] = RCrmActions::fromJSON(trim($loc[1])); + $parameters['filter']['PHRASE'] = RCrmActions::fromJSON(trim($loc[1])); } else{ - RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'RetailCrmHistory::setProp', 'Error location ' . $order['delivery']['address'][$key] . ' not found add in order id=' . $order['externalId']); + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'RetailCrmHistory::setProp', 'Error location. ' . $order['delivery']['address'][$key] . ' not found add in order id=' . $order['externalId']); continue; } - $parameters['filter']['LANGUAGE_ID'] = 'ru'; - $location = \Bitrix\Sale\Location\LocationTable::getListFast($parameters)->fetch(); + $parameters['filter']['NAME.LANGUAGE_ID'] = 'ru'; + $location = \Bitrix\Sale\Location\Search\Finder::find($parameters, array('USE_INDEX' => false, 'USE_ORM' => false))->fetch(); + + $somePropValue = $propertyCollection->getItemByOrderPropertyId($propsKey[$orderProp]['ID']); + self::setProp($somePropValue, $location['CODE']); + } else { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'RetailCrmHistory::setProp', 'Error location. ' . $order['delivery']['address'][$key] . ' is empty in order id=' . $order['externalId']); + + continue; } - $somePropValue = $propertyCollection->getItemByOrderPropertyId($propsKey[$orderProp]['ID']); - self::setProp($somePropValue, $location['CODE']); } else { $somePropValue = $propertyCollection->getItemByOrderPropertyId($propsKey[$orderProp]['ID']); self::setProp($somePropValue, RCrmActions::fromJSON($order['delivery']['address'][$key])); @@ -585,6 +570,7 @@ class RetailCrmHistory } } } + //optionsLegalDetails if ($optionsLegalDetails[$personType]) { foreach ($optionsLegalDetails[$personType] as $key => $orderProp) { @@ -646,14 +632,7 @@ class RetailCrmHistory if (array_key_exists('discount', $product) || array_key_exists('discountPercent', $product)) { if (!isset($orderCrm)) { - try { - $orderCrm = $api->ordersGet($order['id'], 'id', $order['site']); - } catch (\RetailCrm\Exception\CurlException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::orderHistory', 'RetailCrm\RestApi::ordersGet1::CurlException', - $e->getCode() . ': ' . $e->getMessage() - ); - } + $orderCrm = RCrmActions::apiMethod($api, 'orderGet', __METHOD__, $order['id']); } if (isset($orderCrm['order']['items'])) { foreach ($orderCrm['order']['items'] as $itemCrm) { @@ -663,6 +642,7 @@ class RetailCrmHistory } } } + if (isset($itemCost) && $itemCost > 0) { $item->setField('CUSTOM_PRICE', 'Y'); $item->setField('PRICE', $itemCost); @@ -694,27 +674,22 @@ class RetailCrmHistory //payment if (array_key_exists('paymentType', $order)) { - self::paySystemUpdate($order, $optionsPayTypes); + self::paySystemUpdate($order, $optionsPayTypes, $newOrder->getField('ACCOUNT_NUMBER')); } //delivery if (array_key_exists('code', $order['delivery'])) { $itemUpdate = true; - //если пусто, удаляем, если нет, update или add + //delete empty if (!isset($orderCrm)) { - try { - $orderCrm = $api->ordersGet($order['id'], 'id', $order['site']); - } catch (\RetailCrm\Exception\CurlException $e) { - RCrmActions::eventLog( - 'RetailCrmHistory::orderHistory', 'RetailCrm\RestApi::ordersGet2::CurlException', - $e->getCode() . ': ' . $e->getMessage() - ); - } + $orderCrm = RCrmActions::apiMethod($api, 'orderGet', __METHOD__, $order['id']); + } + if ($orderCrm) { + self::shipmentUpdate($orderCrm['order'], $optionsDelivTypes, $newOrder->getField('ACCOUNT_NUMBER')); } - self::shipmentUpdate($orderCrm['order'], $optionsDelivTypes); } if (isset($orderCrm)) { - unset($orderCrm); + unset($orderCrm); } //delivery cost @@ -727,7 +702,7 @@ class RetailCrmHistory Bitrix\Sale\Internals\ShipmentTable::update($shipment['ID'], array('BASE_PRICE_DELIVERY' => $order['delivery']['cost'], 'PRICE_DELIVERY' => $order['delivery']['cost'], 'CUSTOM_PRICE_DELIVERY' => 'Y')); } - Bitrix\Sale\OrderTable::update($order['externalId'], array('PRICE_DELIVERY' => $order['delivery']['cost']));//не пишется в историю, надо добавить + Bitrix\Sale\OrderTable::update($order['externalId'], array('PRICE_DELIVERY' => $order['delivery']['cost'])); } Bitrix\Sale\OrderTable::update($order['externalId'], array('MARKED' => 'N', 'EMP_MARKED_ID' => '', 'REASON_MARKED' => '')); @@ -744,17 +719,16 @@ class RetailCrmHistory $GLOBALS['RETAIL_CRM_HISTORY'] = false; - //запоминаем номер последнего изменения + //end id $end = array_pop($orderH); COption::SetOptionString(self::$MODULE_ID, self::$CRM_ORDER_HISTORY, $end['id']); if ($orderHistory['pagination']['totalPageCount'] == 1) { return true; } - //новый фильтр для истории + //new filter $historyFilter['sinceId'] = $end['id']; - } - + } } public static function assemblyCustomer($customerHistory) @@ -892,18 +866,24 @@ class RetailCrmHistory return $orders; } - public static function shipmentUpdate($orderCrm, $optionsDelivTypes) + public static function shipmentUpdate($orderCrm, $optionsDelivTypes, $accountNumber = '') { + if (strlen($accountNumber) < 1) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'shipmentUpdate', 'ACCOUNT_NUMBER not found'); + + return false; + } + if (isset($orderCrm['delivery']['code'])) { $crmCode = $orderCrm['delivery']['code']; if (isset($orderCrm['delivery']['data']['deliveryType'])) { $crmService = $orderCrm['delivery']['data']['deliveryType']; } elseif (isset($orderCrm['delivery']['service'])) { - $crmService = $orderCrm['delivery']['service']; + $crmService = $orderCrm['delivery']['service']['code']; } - //подбираем код битриксового сервиса + //select bitrix service code $arDeliveryServiceAll = \Bitrix\Sale\Delivery\Services\Manager::getActiveList(); foreach ($arDeliveryServiceAll as $arDeliveryService) { $arDeliveryCode[$arDeliveryService['CODE']] = $arDeliveryService['ID']; @@ -912,16 +892,20 @@ class RetailCrmHistory $dCode = $arDeliveryService['CODE'] . ':' . $crmService; } } - //будем менять доставку на этот id + //We will change delivery to this id if ($crmService && $arDeliveryCode[$dCode]) { $nowDelivery = $arDeliveryCode[$dCode]; - } else { + } elseif (!empty($optionsDelivTypes[$crmCode])) { $nowDelivery = $optionsDelivTypes[$crmCode]; + } else { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'shipmentUpdate', 'Delivery ' . $crmCode . ' not found in options'); + + return false; } - //найти текущую доставку в заказе + //Find the current delivery in the order $cnt = Bitrix\Sale\Internals\ShipmentTable::getCount(array('ORDER_ID' => $orderCrm['externalId'])); - if ($cnt > 0) {//обновляем + if ($cnt > 0) {//update $obDeliverys = \Bitrix\Sale\Internals\ShipmentTable::getList(array('filter' => array('ORDER_ID' => $orderCrm['externalId']), 'order' => array('ID'))); while ($arDelivery = $obDeliverys->fetch()) { @@ -930,7 +914,29 @@ class RetailCrmHistory \Bitrix\Sale\Internals\ShipmentTable::update($arDelivery['ID'], array('DELIVERY_ID' => $nowDelivery, 'DELIVERY_NAME' => $arDeliveryID[$nowDelivery]['NAME'])); } } - } else {//создаем + if ($cnt = 1 && $arDelivery['DELIVERY_ID'] == 0) { + $shipment = Bitrix\Sale\Internals\ShipmentTable::add(array( + 'ORDER_ID' => $orderCrm['externalId'], + 'STATUS_ID' => 'DN', + 'PRICE_DELIVERY' => 0, + 'BASE_PRICE_DELIVERY' => 0, + 'CUSTOM_PRICE_DELIVERY' => 'N', + 'ALLOW_DELIVERY' => 'N', + 'DEDUCTED' => 'N', + 'RESERVED' => 'N', + 'DELIVERY_ID' => $nowDelivery, + 'DELIVERY_NAME' => $arDeliveryID[$nowDelivery]['NAME'], + 'CANCELED' => 'N', + 'MARKED' => 'N', + 'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(), + 'SYSTEM' => 'N', + 'ACCOUNT_NUMBER' => $accountNumber . '/2', + 'EXTERNAL_DELIVERY' => 'N', + 'UPDATED_1C' => 'N', + 'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime() + )); + } + } else {//create \Bitrix\Sale\OrderTable::update($orderCrm['externalId'], array('DELIVERY_ID' => $nowDelivery)); $shipmentSystem = \Bitrix\Sale\Internals\ShipmentTable::add(array( 'ORDER_ID' => $orderCrm['externalId'], @@ -944,7 +950,7 @@ class RetailCrmHistory 'CANCELED' => 'N', 'MARKED' => 'N', 'SYSTEM' => 'Y', - 'ACCOUNT_NUMBER' => $orderCrm['externalId'] . '/1', + 'ACCOUNT_NUMBER' => $accountNumber . '/1', 'EXTERNAL_DELIVERY' => 'N', 'UPDATED_1C' => 'N', 'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime() @@ -964,21 +970,21 @@ class RetailCrmHistory 'MARKED' => 'N', 'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(), 'SYSTEM' => 'N', - 'ACCOUNT_NUMBER' => $orderCrm['externalId'] . '/2', + 'ACCOUNT_NUMBER' => $accountNumber . '/2', 'EXTERNAL_DELIVERY' => 'N', 'UPDATED_1C' => 'N', 'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime() )); } } else { - //ищем у заказа на сайте доставки и удаляем/заменяем на без доставки + //search for the order on the delivery site and delete / replace with no delivery $noOrderId = \Bitrix\Sale\Delivery\Services\EmptyDeliveryService::getEmptyDeliveryServiceId(); \Bitrix\Sale\OrderTable::update($orderCrm['externalId'], array('DELIVERY_ID' => $noOrderId)); $obDeliverys = Bitrix\Sale\Internals\ShipmentTable::getList(array('filter' => array('ORDER_ID' => $orderCrm['externalId']), 'order' => array('ID'))); $create = true; while ($arDelivery = $obDeliverys->fetch()) { - \Bitrix\Sale\Internals\ShipmentTable::update($arDelivery['ID'], array('DELIVERY_ID' => $noOrderId, 'DELIVERY_NAME' => 'Без доставки')); + \Bitrix\Sale\Internals\ShipmentTable::update($arDelivery['ID'], array('DELIVERY_ID' => $noOrderId, 'DELIVERY_NAME' => GetMessage('NO_DELIVERY'))); $create = false; } if ($create) { @@ -989,12 +995,12 @@ class RetailCrmHistory 'ALLOW_DELIVERY' => 'N', 'DEDUCTED' => 'N', 'RESERVED' => 'N', - 'DELIVERY_ID' => $nowDelivery, - 'DELIVERY_NAME' => $nowDelivery[$nowDelivery]['NAME'], + 'DELIVERY_ID' => $noOrderId, + 'DELIVERY_NAME' => GetMessage('NO_DELIVERY'), 'CANCELED' => 'N', 'MARKED' => 'N', 'SYSTEM' => 'Y', - 'ACCOUNT_NUMBER' => $orderCrm['externalId'] . '/1', + 'ACCOUNT_NUMBER' => $accountNumber . '/1', 'EXTERNAL_DELIVERY' => 'N', 'UPDATED_1C' => 'N', 'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime() @@ -1008,13 +1014,13 @@ class RetailCrmHistory 'ALLOW_DELIVERY' => 'N', 'DEDUCTED' => 'N', 'RESERVED' => 'N', - 'DELIVERY_ID' => $nowDelivery, - 'DELIVERY_NAME' => $arDeliveryID[$nowDelivery]['NAME'], + 'DELIVERY_ID' => $noOrderId, + 'DELIVERY_NAME' => GetMessage('NO_DELIVERY'), 'CANCELED' => 'N', 'MARKED' => 'N', 'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(), 'SYSTEM' => 'N', - 'ACCOUNT_NUMBER' => $orderCrm['externalId'] . '/2', + 'ACCOUNT_NUMBER' => $accountNumber . '/2', 'EXTERNAL_DELIVERY' => 'N', 'UPDATED_1C' => 'N', 'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime() @@ -1031,6 +1037,7 @@ class RetailCrmHistory 'filter' => array('ORDER_ID' => $orderId), 'select' => array('ID', 'QUANTITY') )); + $basketItems = array(); while ($basketItem = $orderBasket->fetch()) { $basketItems[] = $basketItem; @@ -1041,6 +1048,7 @@ class RetailCrmHistory 'filter' => array('ORDER_ID' => $orderId), 'select' => array('ID') )); + $shipmentItems = array(); while ($arShipment = $obShipments->fetch()) { $dlvBaslet = \Bitrix\Sale\Internals\ShipmentItemTable::getList(array( @@ -1058,13 +1066,13 @@ class RetailCrmHistory $found = false; foreach ($arShipmentItems as $elShipmentItem) { if (!in_array($elShipmentItem['BASKET_ID'], $bItems)) { - //удаляем элемент + //delete the element \Bitrix\Sale\Internals\ShipmentItemTable::delete($elShipmentItem['ID']); } if ($elShipmentItem['BASKET_ID'] == $basketItem['ID']) { - //нашли + //found $found = true; - //проверяем кол-во, если нужно, обновляем + //update quantity if ($elShipmentItem['QUANTITY'] != $basketItem['QUANTITY']) { \Bitrix\Sale\Internals\ShipmentItemTable::update($elShipmentItem['ID'], array('QUANTITY' => $basketItem['QUANTITY'])); } @@ -1072,7 +1080,7 @@ class RetailCrmHistory } } if (!$found) { - //добавляем + //create \Bitrix\Sale\Internals\ShipmentItemTable::add(array( 'ORDER_DELIVERY_ID' => $key, 'BASKET_ID' => $basketItem['ID'], @@ -1085,8 +1093,14 @@ class RetailCrmHistory } } - public static function paySystemUpdate($order, $optionsPayment) + public static function paySystemUpdate($order, $optionsPayment, $accountNumber = '') { + if (strlen($accountNumber) < 1) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'paySystemUpdate', 'ACCOUNT_NUMBER not found'); + + return false; + } + if (isset($order['paymentType'])) { if ($optionsPayment[$order['paymentType']]) { $paymentList = RCrmActions::PaymentList(); @@ -1103,7 +1117,7 @@ class RetailCrmHistory 'filter' => array('ORDER_ID' => $order['externalId']), 'order' => array('ID') ))->fetch(); - if ($payment) {//если уже существует, update + if ($payment) {//update payment \Bitrix\Sale\Internals\PaymentTable::update($payment['ID'], array('PAY_SYSTEM_ID' => $optionsPayment[$order['paymentType']], 'PAY_SYSTEM_NAME' => $arPaymentsName[$optionsPayment[$order['paymentType']]], 'SUM' => $order['summ'])); } else { \Bitrix\Sale\Internals\PaymentTable::add(array( @@ -1114,17 +1128,16 @@ class RetailCrmHistory 'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(), 'PAY_SYSTEM_NAME' => $arPaymentsName[$optionsPayment[$order['paymentType']]], 'IS_RETURN' => 'N', - 'ACCOUNT_NUMBER' => $order['externalId'] . '/1', + 'ACCOUNT_NUMBER' => $accountNumber . '/1', 'PRICE_COD' => '0.00', 'EXTERNAL_PAYMENT' => 'N', 'UPDATED_1C' => 'N' )); } - //запись в историю - } else {//ошибка, нет такой активной платежной системы + } else { RCrmActions::eventLog('RetailCrmHistory::paySystemUpdate', 'RCrmActions::PaymentList()', 'Error paySystem not found in order id=' . $order['externalId']); } - } else {//ошибка, возможно платежная система не сопоставлена + } else { RCrmActions::eventLog('RetailCrmHistory::paySystemUpdate', 'RCrmActions::PaymentList()', 'Error paySystem not found in option in order id=' . $order['externalId']);; } } else { @@ -1137,7 +1150,6 @@ class RetailCrmHistory if ($payment['ID']) { \Bitrix\Sale\Internals\PaymentTable::delete($payment['ID']); } - //запись в историю } } @@ -1153,12 +1165,14 @@ class RetailCrmHistory public static function removeEmpty($inputArray) { $outputArray = array(); + if (!empty($inputArray)) { foreach ($inputArray as $key => $element) { if (!empty($element) || $element === 0 || $element === '0') { if (is_array($element)) { $element = self::removeEmpty($element); } + $outputArray[$key] = $element; } } @@ -1169,7 +1183,7 @@ class RetailCrmHistory public static function setProp($obj, $value = '', $prop) { - if (!isset($obj)) { + if (!isset($obj)) { return false; } if ($prop) { @@ -1185,21 +1199,22 @@ class RetailCrmHistory public static function getExistsItem($basket, $moduleId, $productId) { - foreach ($basket as $basketItem) { - $itemExists = ($basketItem->getField('PRODUCT_ID') == $productId && $basketItem->getField('MODULE') == $moduleId); + foreach ($basket as $basketItem) { + $itemExists = ($basketItem->getField('PRODUCT_ID') == $productId && $basketItem->getField('MODULE') == $moduleId); - if ($itemExists) { + if ($itemExists) { return $basketItem; - } - } + } + } - return false; - } + return false; + } public static function getInfoElement($offerId) { $elementInfo = CIBlockElement::GetByID($offerId)->fetch(); $url = CAllIBlock::ReplaceDetailUrl($elementInfo['DETAIL_PAGE_URL'], $elementInfo, false, 'E'); + $info = array( 'NAME' => $elementInfo['NAME'], 'URL' => $url, @@ -1213,24 +1228,27 @@ class RetailUser extends CUser { public function GetID() { - $rsUser = CUser::GetList(($by='ID'), ($order='DESC'), array('LOGIN' => 'retailcrm%')); + $rsUser = CUser::GetList(($by = 'ID'), ($order = 'DESC'), array('LOGIN' => 'retailcrm%')); if ($arUser = $rsUser->Fetch()) { return $arUser['ID']; } else { $retailUser = new CUser; + $userPassword = uniqid(); + $arFields = array( - "NAME" => 'retailcrm', - "LAST_NAME" => 'retailcrm', - "EMAIL" => 'retailcrm@retailcrm.com', - "LOGIN" => 'retailcrm', - "LID" => "ru", - "ACTIVE" => "Y", - "GROUP_ID" => array(2), - "PASSWORD" => $userPassword, - "CONFIRM_PASSWORD" => $userPassword - ); + "NAME" => 'retailcrm', + "LAST_NAME" => 'retailcrm', + "EMAIL" => 'retailcrm@retailcrm.com', + "LOGIN" => 'retailcrm', + "LID" => "ru", + "ACTIVE" => "Y", + "GROUP_ID" => array(2), + "PASSWORD" => $userPassword, + "CONFIRM_PASSWORD" => $userPassword + ); $id = $retailUser->Add($arFields); + if (!$id) { return null; } else { diff --git a/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php b/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php new file mode 100644 index 00000000..b4916b9f --- /dev/null +++ b/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php @@ -0,0 +1,1320 @@ + 0) { + $historyFilter['sinceId'] = $historyStart; + } + + while (true) { + $customerHistory = RCrmActions::apiMethod($api, 'ordersHistory', __METHOD__, $historyFilter); + + $customerH = isset($customerHistory['history']) ? $customerHistory['history'] : array(); + + $log = new Logger(); + $log->write($customerH, 'customerHistory'); + + if (count($customerH) == 0) { + if ($customerHistory['history']['totalPageCount'] > $customerHistory['history']['currentPage']) { + $historyFilter['page'] = $customerHistory['history']['currentPage'] + 1; + + continue; + } + + return true; + } + + $customers = self::assemblyCustomer($customerH); + + $GLOBALS['RETAIL_CRM_HISTORY'] = true; + + $newUser = new CUser; + + foreach ($customers as $customer) { + if (function_exists('retailCrmBeforeCustomerSave')) { + $newResCustomer = retailCrmBeforeCustomerSave($customer); + if (is_array($newResCustomer) && !empty($newResCustomer)) { + $customer = $newResCustomer; + } elseif ($newResCustomer === false) { + RCrmActions::eventLog('RetailCrmHistory::customerHistory', 'retailCrmBeforeCustomerSave()', 'UserCrmId = ' . $customer['id'] . '. Sending canceled after retailCrmBeforeCustomerSave'); + + continue; + } + } + + if (isset($customer['deleted'])) { + continue; + } + + if (!isset($customer['externalId'])) { + if (!isset($customer['id'])) { + continue; + } + + $registerNewUser = true; + if (!isset($customer['email']) || $customer['email'] == '') { + $login = $customer['email'] = uniqid('user_' . time()) . '@crm.com'; + } else { + $dbUser = CUser::GetList(($by = 'ID'), ($sort = 'ASC'), array('=EMAIL' => $customer['email'])); + switch ($dbUser->SelectedRowsCount()) { + case 0: + $login = $customer['email']; + break; + case 1: + $arUser = $dbUser->Fetch(); + $registeredUserID = $arUser['ID']; + $registerNewUser = false; + break; + default: + $login = uniqid('user_' . time()) . '@crm.com'; + break; + } + } + + if ($registerNewUser === true) { + $userPassword = uniqid(); + + $arFields = array( + "EMAIL" => $customer['email'], + "LOGIN" => $login, + "ACTIVE" => "Y", + "PASSWORD" => $userPassword, + "CONFIRM_PASSWORD" => $userPassword + ); + $registeredUserID = $newUser->Add($arFields); + if ($registeredUserID === false) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'CUser::Register', 'Error register user'); + continue; + } + + if(RCrmActions::apiMethod($api, 'customersFixExternalIds', __METHOD__, array(array('id' => $customer['id'], 'externalId' => $registeredUserID))) == false) { + continue; + } + } + + $customer['externalId'] = $registeredUserID; + } + + if (isset($customer['externalId'])) { + $arUser = array(); + if (array_key_exists('firstName', $customer)) { + $arUser["NAME"] = $customer['firstName'] ? RCrmActions::fromJSON($customer['firstName']) : ''; + } + if (array_key_exists('lastName', $customer)) { + $arUser["LAST_NAME"] = $customer['lastName'] ? RCrmActions::fromJSON($customer['lastName']) : ''; + } + if (array_key_exists('patronymic', $customer)) { + $arUser["SECOND_NAME"] = $customer['patronymic'] ? RCrmActions::fromJSON($customer['patronymic']) : ''; + } + +// if (array_key_exists('email', $customer)) { +// $arUser["EMAIL"] = $customer['email'] ? RCrmActions::fromJSON($customer['email']) : ''; +// } + + if (isset($customer['phones'])) { + $user = CUser::GetList(($by = "ID"), ($order = "desc"), array('ID' => $customer['externalId']), array('FIELDS' => array('PERSONAL_PHONE', 'PERSONAL_MOBILE')))->fetch(); + foreach ($customer['phones'] as $phone) { + if (isset($phone['old_number']) && in_array($phone['old_number'], $user)) { + $key = array_search($phone['old_number'], $user); + if (isset($phone['number'])) { + $arUser[$key] = $phone['number']; + $user[$key] = $phone['number']; + } else { + $arUser[$key] = ''; + $user[$key] = ''; + } + } + if (isset($phone['number'])) { + if ((!isset($user['PERSONAL_PHONE']) || strlen($user['PERSONAL_PHONE']) == 0) && $user['PERSONAL_MOBILE'] != $phone['number']) { + $arUser['PERSONAL_PHONE'] = $phone['number']; + $user['PERSONAL_PHONE'] = $phone['number']; + continue; + } + if ((!isset($user['PERSONAL_MOBILE']) || strlen($user['PERSONAL_MOBILE']) == 0) && $user['PERSONAL_PHONE'] != $phone['number']) { + $arUser['PERSONAL_MOBILE'] = $phone['number']; + $user['PERSONAL_MOBILE'] = $phone['number']; + continue; + } + } + } + } + if (array_key_exists('index', $customer['address'])) { + $arUser["PERSONAL_ZIP"] = $customer['address']['index'] ? RCrmActions::fromJSON($customer['address']['index']) : ''; + } + if (array_key_exists('city', $customer['address'])) { + $arUser["PERSONAL_CITY"] = $customer['address']['city'] ? RCrmActions::fromJSON($customer['address']['city']) : ''; + } + + $u = $newUser->Update($customer['externalId'], $arUser); + if (!$u) { + RCrmActions::eventLog('RetailCrmHistory::customerHistory', 'Error update user', $newUser->LAST_ERROR); + } + + if (function_exists('retailCrmAfterCustomerSave')) { + retailCrmAfterCustomerSave($customer); + } + } + } + + $GLOBALS['RETAIL_CRM_HISTORY'] = false; + + //last id + $end = array_pop($customerH); + COption::SetOptionString(self::$MODULE_ID, self::$CRM_CUSTOMER_HISTORY, $end['id']); + + if ($customerHistory['pagination']['totalPageCount'] == 1) { + return true; + } + //new filter + $historyFilter['sinceId'] = $end['id']; + } + } + + public static function orderHistory() + { + global $USER; + if (is_object($USER) == false) { + $USER = new RetailUser; + } + if (!CModule::IncludeModule("iblock")) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'iblock', 'module not found'); + + return false; + } + if (!CModule::IncludeModule("sale")) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'sale', 'module not found'); + + return false; + } + if (!CModule::IncludeModule("catalog")) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'catalog', 'module not found'); + + return false; + } + + $api_host = COption::GetOptionString(self::$MODULE_ID, self::$CRM_API_HOST_OPTION, 0); + $api_key = COption::GetOptionString(self::$MODULE_ID, self::$CRM_API_KEY_OPTION, 0); + + $optionsOrderTypes = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_TYPES_ARR, 0)); + $optionsDelivTypes = array_flip(unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_DELIVERY_TYPES_ARR, 0))); + $optionsPayStatuses = array_flip(unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_PAYMENT_STATUSES, 0))); // --statuses + $optionsOrderProps = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_PROPS, 0)); + $optionsLegalDetails = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_LEGAL_DETAILS, 0)); + $optionsSitesList = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_SITES_LIST, 0)); + $optionsOrderNumbers = COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_NUMBERS, 0); + $optionsCanselOrder = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_CANSEL_ORDER, 0)); + + $api = new RetailCrm\ApiClient($api_host, $api_key); + + $historyFilter = array(); + $historyStart = COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_HISTORY); + if ($historyStart && $historyStart > 0) { + $historyFilter['sinceId'] = $historyStart; + } + + while (true) { + $orderHistory = RCrmActions::apiMethod($api, 'ordersHistory', __METHOD__, $historyFilter); + + $orderH = isset($orderHistory['history']) ? $orderHistory['history'] : array(); + + $log = new Logger(); + $log->write($orderH, 'orderHistory'); + + if (count($orderH) == 0) { + if ($orderHistory['history']['totalPageCount'] > $orderHistory['history']['currentPage']) { + $historyFilter['page'] = $orderHistory['history']['currentPage'] + 1; + + continue; + } + + return true; + } + + $orders = self::assemblyOrder($orderH); + + $GLOBALS['RETAIL_CRM_HISTORY'] = true; + + //orders with changes + foreach ($orders as $order) { + if (function_exists('retailCrmBeforeOrderSave')) { + $newResOrder = retailCrmBeforeOrderSave($order); + if (is_array($newResOrder) && !empty($newResOrder)) { + $order = $newResOrder; + } elseif ($newResOrder === false) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'retailCrmBeforeOrderSave()', 'OrderCrmId = ' . $order['id'] . '. Sending canceled after retailCrmBeforeOrderSave'); + + continue; + } + } + + $log->write($order, 'assemblyOrderHistory'); + + if (isset($order['deleted'])) { + if (isset($order['externalId'])) { + try { + $newOrder = Bitrix\Sale\Order::load($order['externalId']); + } catch (Bitrix\Main\ArgumentNullException $e) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::load', $e->getMessage() . ': ' . $order['externalId']); + continue; + } + + if (!$newOrder instanceof \Bitrix\Sale\Order) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::load', 'Error order load: ' . $order['externalId']); + continue; + } + + $newOrder->setField('CANCELED', 'Y'); + $newOrder->save(); + } + + continue; + } + + if (!isset($order['externalId'])) { + if (!isset($order['customer']['externalId'])) { + if (!isset($order['customer']['id'])) { + continue; + } + + $registerNewUser = true; + + if (!isset($order['customer']['email']) || $order['customer']['email'] == '') { + $login = $order['customer']['email'] = uniqid('user_' . time()) . '@crm.com'; + } else { + $dbUser = CUser::GetList(($by = 'ID'), ($sort = 'ASC'), array('=EMAIL' => $order['email'])); + switch ($dbUser->SelectedRowsCount()) { + case 0: + $login = $order['customer']['email']; + break; + case 1: + $arUser = $dbUser->Fetch(); + $registeredUserID = $arUser['ID']; + $registerNewUser = false; + break; + default: + $login = uniqid('user_' . time()) . '@crm.com'; + break; + } + } + + if ($registerNewUser === true) { + $userPassword = uniqid(); + + $newUser = new CUser; + $arFields = array( + "NAME" => RCrmActions::fromJSON($order['customer']['firstName']), + "LAST_NAME" => RCrmActions::fromJSON($order['customer']['lastName']), + "SECOND_NAME" => RCrmActions::fromJSON($order['customer']['patronymic']), + "EMAIL" => $order['customer']['email'], + "LOGIN" => $login, + "ACTIVE" => "Y", + "PASSWORD" => $userPassword, + "CONFIRM_PASSWORD" => $userPassword + ); + if ($order['customer']['phones'][0]) { + $arFields['PERSONAL_PHONE'] = $order['customer']['phones'][0]; + } + if ($order['customer']['phones'][1]) { + $arFields['PERSONAL_MOBILE'] = $order['customer']['phones'][1]; + } + + $registeredUserID = $newUser->Add($arFields); + + if ($registeredUserID === false) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'CUser::Register', 'Error register user'); + + continue; + } + + if(RCrmActions::apiMethod($api, 'customersFixExternalIds', __METHOD__, array(array('id' => $order['customer']['id'], 'externalId' => $registeredUserID))) == false) { + continue; + } + } + + $order['customer']['externalId'] = $registeredUserID; + } + + if ($optionsSitesList) { + $site = array_search($order['site'], $optionsSitesList); + } else { + $site = CSite::GetDefSite(); + } + if (empty($site)) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::create', 'Site = ' . $order['site'] . ' not found in setting. Order crm id=' . $order['id']); + + continue; + } + + $newOrder = Bitrix\Sale\Order::create($site, $order['customer']['externalId']); + $newOrder->save(); + $externalId = $newOrder->getId(); + + if (isset($externalId)) { + if(RCrmActions::apiMethod($api, 'ordersFixExternalIds', __METHOD__, array(array('id' => $order['id'], 'externalId' => $externalId))) == false){ + continue; + } + } else { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::create', 'Error order create'); + } + $order['externalId'] = $externalId; + } + + if (isset($order['externalId']) && $order['externalId']) { + $itemUpdate = false; + try { + $newOrder = Bitrix\Sale\Order::load($order['externalId']); + } catch (Bitrix\Main\ArgumentNullException $e) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::load', $e->getMessage() . ': ' . $order['externalId']); + + continue; + } + + if (!$newOrder instanceof \Bitrix\Sale\Order) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::load', 'Error order load id=' . $order['externalId']); + + continue; + } + + if ($optionsSitesList) { + $site = array_search($order['site'], $optionsSitesList); + } else { + $site = CSite::GetDefSite(); + } + if (empty($site)) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::edit', 'Site = ' . $order['site'] . ' not found in setting. Order id=' . $order['externalId']); + + continue; + } + + if ($optionsOrderNumbers == 'Y' && isset($order['number'])) { + $searchFilter = array( + 'filter' => array('ACCOUNT_NUMBER' => $order['number']), + 'select' => array('ID'), + ); + $searchOrder = reset(Bitrix\Sale\Order::loadByFilter($searchFilter)); + if (!empty($searchOrder)) { + if ($searchOrder->getId() != $order['externalId']) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'setField("ACCOUNT_NUMBER")', 'Error order load id=' . $order['externalId']) . '. Number ' . $order['number'] . ' already exists'; + + continue; + } + } + + $newOrder->setField('ACCOUNT_NUMBER', $order['number']); + } + + $personType = $newOrder->getField('PERSON_TYPE_ID'); + + $nType = array(); + $tList = RCrmActions::OrderTypesList(array(array('LID' => $site))); + foreach($tList as $type){ + if (isset($optionsOrderTypes[$type['ID']])) { + $nType[$optionsOrderTypes[$type['ID']]] = $type['ID']; + } + } + $optionsOrderTypes = $nType; + + if ($optionsOrderTypes[$order['orderType']]) { + if ($personType != $optionsOrderTypes[$order['orderType']] && $personType != 0) { + $propsRemove = true; + } + $personType = $optionsOrderTypes[$order['orderType']]; + $newOrder->setField('PERSON_TYPE_ID', $personType); + } elseif ($personType == 0) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'orderType not found', 'PERSON_TYPE_ID = 0'); + } + + //status + if ($optionsPayStatuses[$order['status']]) { + $newOrder->setField('STATUS_ID', $optionsPayStatuses[$order['status']]); + if (in_array($optionsPayStatuses[$order['status']], $optionsCanselOrder)) { + $newOrder->setFieldNoDemand('CANCELED', 'Y'); + } else { + $newOrder->setFieldNoDemand('CANCELED', 'N'); + } + } + + if (array_key_exists('statusComment', $order)) { + self::setProp($newOrder, RCrmActions::fromJSON($order['statusComment']), 'REASON_CANCELED'); + } + + //props + $propertyCollection = $newOrder->getPropertyCollection(); + $propertyCollectionArr = $propertyCollection->getArray(); + $nProps = array(); + foreach ($propertyCollectionArr['properties'] as $orderProp) { + if ($orderProp['ID'][0] == 'n') { + $orderProp['ID'] = substr($orderProp['ID'], 1); + $orderProp['ID'] = $propertyCollection->getItemById($orderProp['ID'])->getField('ORDER_PROPS_ID'); + } + $nProps[] = $orderProp; + } + $propertyCollectionArr['properties'] = $nProps; + + if ($propsRemove) {//delete props + foreach ($propertyCollectionArr['properties'] as $orderProp) { + $somePropValue = $propertyCollection->getItemByOrderPropertyId($orderProp['ID']); + self::setProp($somePropValue); + } + $orderCrm = RCrmActions::apiMethod($api, 'orderGet', __METHOD__, $order['id']); + + $orderDump = $order; + $order = $orderCrm['order']; + } + + $propsKey = array(); + foreach ($propertyCollectionArr['properties'] as $prop) { + $propsKey[$prop['CODE']]['ID'] = $prop['ID']; + $propsKey[$prop['CODE']]['TYPE'] = $prop['TYPE']; + } + //fio + if ($order['firstName'] || $order['lastName'] || $order['patronymic']) { + $fio = ''; + foreach ($propertyCollectionArr['properties'] as $prop) { + if (in_array($optionsOrderProps[$personType]['fio'], $prop)) { + $getFio = $newOrder->getPropertyCollection()->getItemByOrderPropertyId($prop['ID']); + if (method_exists($getFio, 'getValue')) { + $fio = $getFio->getValue(); + } + } + } + + $fio = RCrmActions::explodeFIO($fio); + $newFio = array(); + if ($fio) { + $newFio[] = isset($order['lastName']) ? RCrmActions::fromJSON($order['lastName']) : (isset($fio['lastName']) ? $fio['lastName'] : ''); + $newFio[] = isset($order['firstName']) ? RCrmActions::fromJSON($order['firstName']) : (isset($fio['firstName']) ? $fio['firstName'] : ''); + $newFio[] = isset($order['patronymic']) ? RCrmActions::fromJSON($order['patronymic']) : (isset($fio['patronymic']) ? $fio['patronymic'] : ''); + $order['fio'] = trim(implode(' ', $newFio)); + } else { + $newFio[] = isset($order['lastName']) ? RCrmActions::fromJSON($order['lastName']) : ''; + $newFio[] = isset($order['firstName']) ? RCrmActions::fromJSON($order['firstName']) : ''; + $newFio[] = isset($order['patronymic']) ? RCrmActions::fromJSON($order['patronymic']) : ''; + $order['fio'] = trim(implode(' ', $newFio)); + } + } + + //optionsOrderProps + if ($optionsOrderProps[$personType]) { + foreach ($optionsOrderProps[$personType] as $key => $orderProp) { + if (array_key_exists($key, $order)) { + $somePropValue = $propertyCollection->getItemByOrderPropertyId($propsKey[$orderProp]['ID']); + if ($key == 'fio') { + self::setProp($somePropValue, $order[$key]); + } else { + self::setProp($somePropValue, RCrmActions::fromJSON($order[$key])); + } + } elseif (array_key_exists($key, $order['delivery']['address'])) { + if ($propsKey[$orderProp]['TYPE'] == 'LOCATION') { + $order['delivery']['address'][$key] = trim($order['delivery']['address'][$key]); + if(!empty($order['delivery']['address'][$key])){ + $parameters = array(); + $loc = explode('.', $order['delivery']['address'][$key]); + if (count($loc) == 1) { + $parameters['filter']['PHRASE'] = RCrmActions::fromJSON(trim($loc[0])); + } elseif (count($loc) == 2) { + $parameters['filter']['PHRASE'] = RCrmActions::fromJSON(trim($loc[1])); + } else{ + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'RetailCrmHistory::setProp', 'Error location. ' . $order['delivery']['address'][$key] . ' not found add in order id=' . $order['externalId']); + continue; + } + $parameters['filter']['NAME.LANGUAGE_ID'] = 'ru'; + $location = \Bitrix\Sale\Location\Search\Finder::find($parameters, array('USE_INDEX' => false, 'USE_ORM' => false))->fetch(); + + $somePropValue = $propertyCollection->getItemByOrderPropertyId($propsKey[$orderProp]['ID']); + self::setProp($somePropValue, $location['CODE']); + } else { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'RetailCrmHistory::setProp', 'Error location. ' . $order['delivery']['address'][$key] . ' is empty in order id=' . $order['externalId']); + + continue; + } + } else { + $somePropValue = $propertyCollection->getItemByOrderPropertyId($propsKey[$orderProp]['ID']); + self::setProp($somePropValue, RCrmActions::fromJSON($order['delivery']['address'][$key])); + } + } + } + } + + //optionsLegalDetails + if ($optionsLegalDetails[$personType]) { + foreach ($optionsLegalDetails[$personType] as $key => $orderProp) { + if (array_key_exists($key, $order)) { + $somePropValue = $propertyCollection->getItemByOrderPropertyId($propsKey[$orderProp]['ID']); + self::setProp($somePropValue, $order[$key]); + } + } + } + if ($propsRemove) { + $order = $orderDump; + } + + //comments + if (array_key_exists('customerComment', $order)) { + self::setProp($newOrder, RCrmActions::fromJSON($order['customerComment']), 'USER_DESCRIPTION'); + } + if (array_key_exists('managerComment', $order)) { + self::setProp($newOrder, RCrmActions::fromJSON($order['managerComment']), 'COMMENTS'); + } + + //items + $basket = $newOrder->getBasket(); + if (isset($order['items'])) { + $itemUpdate = true; + foreach ($order['items'] as $product) { + $item = self::getExistsItem($basket, 'catalog', $product['offer']['externalId']); + if (!$item) { + if($product['delete']){ + continue; + } + $item = $basket->createItem('catalog', $product['offer']['externalId']); + if ($item instanceof \Bitrix\Sale\BasketItem) { + $elem = self::getInfoElement($product['offer']['externalId']); + $item->setFields(array( + 'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(), + 'LID' => $site, + 'BASE_PRICE' => $product['initialPrice'], + 'NAME' => $product['name'] ? RCrmActions::fromJSON($product['name']) : $elem['NAME'], + 'DETAIL_PAGE_URL' => $elem['URL'], + 'PRODUCT_PROVIDER_CLASS' => 'CCatalogProductProvider', + 'DIMENSIONS' => $elem['DIMENSIONS'], + 'WEIGHT' => $elem['WEIGHT'], + 'NOTES' => GetMessage('PRICE_TYPE') + )); + } else { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'createItem', 'Error item add'); + + continue; + } + } + if ($product['delete']) { + $item->delete(); + + continue; + } + + if ($product['quantity']) { + $item->setFieldNoDemand('QUANTITY', $product['quantity']); + } + + if (array_key_exists('discountTotal', $product)) { + $itemCost = $item->getField('BASE_PRICE'); + if (isset($itemCost) && $itemCost > 0) { + $item->setField('CUSTOM_PRICE', 'Y'); + $item->setField('PRICE', $itemCost - $product['discountTotal']); + $item->setField('DISCOUNT_PRICE', $product['discountTotal']); + $item->setField('DISCOUNT_NAME', ''); + $item->setField('DISCOUNT_VALUE', ''); + } + } + + $basket->save(); + } + } + + $orderSumm = 0; + foreach ($basket as $item) { + $orderSumm += $item->getFinalPrice(); + } + + if (array_key_exists('cost', $order['delivery'])) { + $deliverySumm = $order['delivery']['cost']; + } else { + $deliverySumm = $newOrder->getDeliveryPrice(); + } + + $orderSumm += $deliverySumm; + + $newOrder->setField('PRICE', $orderSumm); + $order['summ'] = $orderSumm; + $newOrder->save(); + + //payment + if (array_key_exists('payments', $order)) { + if (!isset($orderCrm)) { + $orderCrm = RCrmActions::apiMethod($api, 'orderGet', __METHOD__, $order['id']); + } + if ($orderCrm) { + $newOrder = self::paymentsUpdate($newOrder, $orderCrm['order'], $api); + } + } + + //delivery + if (array_key_exists('code', $order['delivery'])) { + $itemUpdate = true; + //delete empty + if (!isset($orderCrm)) { + $orderCrm = RCrmActions::apiMethod($api, 'orderGet', __METHOD__, $order['id']); + } + if ($orderCrm) { + self::shipmentUpdate($orderCrm['order'], $optionsDelivTypes, $newOrder->getField('ACCOUNT_NUMBER')); + } + } + if (isset($orderCrm)) { + unset($orderCrm); + } + + //delivery cost + if (array_key_exists('cost', $order['delivery'])) { + $shipment = Bitrix\Sale\Internals\ShipmentTable::getList(array( + 'filter' => array('ORDER_ID' => $order['externalId'], 'SYSTEM' => 'N'), + 'order' => array('ID') + ))->fetch(); + if ($shipment) { + Bitrix\Sale\Internals\ShipmentTable::update($shipment['ID'], array('BASE_PRICE_DELIVERY' => $order['delivery']['cost'], 'PRICE_DELIVERY' => $order['delivery']['cost'], 'CUSTOM_PRICE_DELIVERY' => 'Y')); + } + + Bitrix\Sale\OrderTable::update($order['externalId'], array('PRICE_DELIVERY' => $order['delivery']['cost'])); + } + + Bitrix\Sale\OrderTable::update($order['externalId'], array('MARKED' => 'N', 'EMP_MARKED_ID' => '', 'REASON_MARKED' => '')); + + if ($itemUpdate) { + self::updateShipmentItem($order['externalId']); + } + + if (function_exists('retailCrmAfterOrderSave')) { + retailCrmAfterOrderSave($order); + } + } + } + + $GLOBALS['RETAIL_CRM_HISTORY'] = false; + + //end id + $end = array_pop($orderH); + COption::SetOptionString(self::$MODULE_ID, self::$CRM_ORDER_HISTORY, $end['id']); + + if ($orderHistory['pagination']['totalPageCount'] == 1) { + return true; + } + //new filter + $historyFilter['sinceId'] = $end['id']; + } + } + + public static function assemblyCustomer($customerHistory) + { + $server = \Bitrix\Main\Context::getCurrent()->getServer()->getDocumentRoot(); + $fields = array(); + if (file_exists($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/objects.xml')) { + $objects = simplexml_load_file($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/objects.xml'); + foreach ($objects->fields->field as $object) { + $fields[(string)$object["group"]][(string)$object["id"]] = (string)$object; + } + } + $customers = array(); + foreach ($customerHistory as $change) { + $change['customer'] = self::removeEmpty($change['customer']); + if ($customers[$change['customer']['id']]) { + $customers[$change['customer']['id']] = array_merge($customers[$change['customer']['id']], $change['customer']); + } else { + $customers[$change['customer']['id']] = $change['customer']; + } + + if ($change['customer']['contragent']['contragentType']) { + $change['customer']['contragentType'] = self::newValue($change['customer']['contragent']['contragentType']); + unset($change['customer']['contragent']); + } + + if ($fields['customer'][$change['field']] == 'phones') { + $key = count($customers[$change['customer']['id']]['phones']); + if (isset($change['oldValue'])) { + $customers[$change['customer']['id']]['phones'][$key]['old_number'] = $change['oldValue']; + } + if (isset($change['newValue'])) { + $customers[$change['customer']['id']]['phones'][$key]['number'] = $change['newValue']; + } + } else { + if ($fields['customerAddress'][$change['field']]) { + $customers[$change['customer']['id']]['address'][$fields['customerAddress'][$change['field']]] = $change['newValue']; + } elseif ($fields['customerContragent'][$change['field']]) { + $customers[$change['customer']['id']]['contragent'][$fields['customerContragent'][$change['field']]] = $change['newValue']; + } elseif ($fields['customer'][$change['field']]) { + $customers[$change['customer']['id']][$fields['customer'][$change['field']]] = self::newValue($change['newValue']); + } + + if (isset($change['created'])) { + $customers[$change['customer']['id']]['create'] = 1; + } + + if (isset($change['deleted'])) { + $customers[$change['customer']['id']]['deleted'] = 1; + } + } + } + + return $customers; + } + + public static function assemblyOrder($orderHistory) + { + $server = \Bitrix\Main\Context::getCurrent()->getServer()->getDocumentRoot(); + if (file_exists($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/objects.xml')) { + $objects = simplexml_load_file($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/objects.xml'); + foreach ($objects->fields->field as $object) { + $fields[(string)$object["group"]][(string)$object["id"]] = (string)$object; + } + } + $orders = array(); + foreach ($orderHistory as $change) { + $change['order'] = self::removeEmpty($change['order']); + if ($change['order']['items']) { + $items = array(); + foreach ($change['order']['items'] as $item) { + if (isset($change['created'])) { + $item['create'] = 1; + } + $items[$item['id']] = $item; + } + $change['order']['items'] = $items; + } + + if ($change['order']['payments']) { + $payments = array(); + foreach ($change['order']['payments'] as $payment) { + $payments[$payment['id']] = $payment; + } + $change['order']['payments'] = $payments; + } + + if ($change['order']['contragent']['contragentType']) { + $change['order']['contragentType'] = self::newValue($change['order']['contragent']['contragentType']); + unset($change['order']['contragent']); + } + + if ($orders[$change['order']['id']]) { + $orders[$change['order']['id']] = array_merge($orders[$change['order']['id']], $change['order']); + } else { + $orders[$change['order']['id']] = $change['order']; + } + + if ($change['item']) { + if ($orders[$change['order']['id']]['items'][$change['item']['id']]) { + $orders[$change['order']['id']]['items'][$change['item']['id']] = array_merge($orders[$change['order']['id']]['items'][$change['item']['id']], $change['item']); + } else { + $orders[$change['order']['id']]['items'][$change['item']['id']] = $change['item']; + } + + if (empty($change['oldValue']) && $change['field'] == 'order_product') { + $orders[$change['order']['id']]['items'][$change['item']['id']]['create'] = 1; + unset($orders[$change['order']['id']]['items'][$change['item']['id']]['delete']); + } + if (empty($change['newValue']) && $change['field'] == 'order_product') { + $orders[$change['order']['id']]['items'][$change['item']['id']]['delete'] = 1; + } + if (!$orders[$change['order']['id']]['items'][$change['item']['id']]['create'] && $fields['item'][$change['field']]) { + $orders[$change['order']['id']]['items'][$change['item']['id']][$fields['item'][$change['field']]] = $change['newValue']; + } + } elseif ($change['payment']) { + if ($orders[$change['order']['id']]['payments'][$change['payment']['id']]) { + $orders[$change['order']['id']]['payments'][$change['payment']['id']] = array_merge($orders[$change['order']['id']]['payments'][$change['payment']['id']], $change['payment']); + } else { + $orders[$change['order']['id']]['payments'][$change['payment']['id']] = $change['payment']; + } + + if (empty($change['oldValue']) && $change['field'] == 'payments') { + $orders[$change['order']['id']]['payments'][$change['payment']['id']]['create'] = 1; + unset($orders[$change['order']['id']]['payments'][$change['payment']['id']]['delete']); + } + if (empty($change['newValue']) && $change['field'] == 'payments') { + $orders[$change['order']['id']]['payments'][$change['payment']['id']]['delete'] = 1; + } + if (!$orders[$change['order']['id']]['payments'][$change['payment']['id']]['create'] && $fields['payment'][$change['field']]) { + $orders[$change['order']['id']]['payments'][$change['payment']['id']][$fields['payment'][$change['field']]] = $change['newValue']; + } + } else { + if ($fields['delivery'][$change['field']] == 'service') { + $orders[$change['order']['id']]['delivery']['service']['code'] = self::newValue($change['newValue']); + } elseif ($fields['delivery'][$change['field']]) { + $orders[$change['order']['id']]['delivery'][$fields['delivery'][$change['field']]] = self::newValue($change['newValue']); + } elseif ($fields['orderAddress'][$change['field']]) { + $orders[$change['order']['id']]['delivery']['address'][$fields['orderAddress'][$change['field']]] = $change['newValue']; + } elseif ($fields['integrationDelivery'][$change['field']]) { + $orders[$change['order']['id']]['delivery']['service'][$fields['integrationDelivery'][$change['field']]] = self::newValue($change['newValue']); + } elseif ($fields['customerContragent'][$change['field']]) { + $orders[$change['order']['id']][$fields['customerContragent'][$change['field']]] = self::newValue($change['newValue']); + } elseif (strripos($change['field'], 'custom_') !== false) { + $orders[$change['order']['id']]['customFields'][str_replace('custom_', '', $change['field'])] = self::newValue($change['newValue']); + } elseif ($fields['order'][$change['field']]){ + $orders[$change['order']['id']][$fields['order'][$change['field']]] = self::newValue($change['newValue']); + } + + if (isset($change['created'])) { + $orders[$change['order']['id']]['create'] = 1; + } + + if (isset($change['deleted'])) { + $orders[$change['order']['id']]['deleted'] = 1; + } + } + } + + return $orders; + } + + public static function shipmentUpdate($orderCrm, $optionsDelivTypes, $accountNumber = '') + { + if (strlen($accountNumber) < 1) { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'shipmentUpdate', 'ACCOUNT_NUMBER not found'); + + return false; + } + + if (isset($orderCrm['delivery']['code'])) { + $crmCode = $orderCrm['delivery']['code']; + + if (isset($orderCrm['delivery']['data']['deliveryType'])) { + $crmService = $orderCrm['delivery']['data']['deliveryType']; + } elseif (isset($orderCrm['delivery']['service'])) { + $crmService = $orderCrm['delivery']['service']['code']; + } + + //select bitrix service code + $arDeliveryServiceAll = \Bitrix\Sale\Delivery\Services\Manager::getActiveList(); + foreach ($arDeliveryServiceAll as $arDeliveryService) { + $arDeliveryCode[$arDeliveryService['CODE']] = $arDeliveryService['ID']; + $arDeliveryID[$arDeliveryService['ID']] = $arDeliveryService; + if ($arDeliveryService['ID'] == $optionsDelivTypes[$crmCode]) { + $dCode = $arDeliveryService['CODE'] . ':' . $crmService; + } + } + //We will change delivery to this id + if ($crmService && $arDeliveryCode[$dCode]) { + $nowDelivery = $arDeliveryCode[$dCode]; + } elseif (!empty($optionsDelivTypes[$crmCode])) { + $nowDelivery = $optionsDelivTypes[$crmCode]; + } else { + RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'shipmentUpdate', 'Delivery ' . $crmCode . ' not found in options'); + + return false; + } + + //Find the current delivery in the order + $cnt = Bitrix\Sale\Internals\ShipmentTable::getCount(array('ORDER_ID' => $orderCrm['externalId'])); + if ($cnt > 0) {//update + $obDeliverys = \Bitrix\Sale\Internals\ShipmentTable::getList(array('filter' => array('ORDER_ID' => $orderCrm['externalId']), + 'order' => array('ID'))); + while ($arDelivery = $obDeliverys->fetch()) { + if ($arDelivery['DELIVERY_ID'] != $nowDelivery) { + \Bitrix\Sale\OrderTable::update($orderCrm['externalId'], array('DELIVERY_ID' => $nowDelivery)); + \Bitrix\Sale\Internals\ShipmentTable::update($arDelivery['ID'], array('DELIVERY_ID' => $nowDelivery, 'DELIVERY_NAME' => $arDeliveryID[$nowDelivery]['NAME'])); + } + } + if ($cnt = 1 && $arDelivery['DELIVERY_ID'] == 0) { + $shipment = Bitrix\Sale\Internals\ShipmentTable::add(array( + 'ORDER_ID' => $orderCrm['externalId'], + 'STATUS_ID' => 'DN', + 'PRICE_DELIVERY' => 0, + 'BASE_PRICE_DELIVERY' => 0, + 'CUSTOM_PRICE_DELIVERY' => 'N', + 'ALLOW_DELIVERY' => 'N', + 'DEDUCTED' => 'N', + 'RESERVED' => 'N', + 'DELIVERY_ID' => $nowDelivery, + 'DELIVERY_NAME' => $arDeliveryID[$nowDelivery]['NAME'], + 'CANCELED' => 'N', + 'MARKED' => 'N', + 'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(), + 'SYSTEM' => 'N', + 'ACCOUNT_NUMBER' => $accountNumber . '/2', + 'EXTERNAL_DELIVERY' => 'N', + 'UPDATED_1C' => 'N', + 'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime() + )); + } + } else {//create + \Bitrix\Sale\OrderTable::update($orderCrm['externalId'], array('DELIVERY_ID' => $nowDelivery)); + $shipmentSystem = \Bitrix\Sale\Internals\ShipmentTable::add(array( + 'ORDER_ID' => $orderCrm['externalId'], + 'STATUS_ID' => 'DN', + 'CUSTOM_PRICE_DELIVERY' => 'N', + 'ALLOW_DELIVERY' => 'N', + 'DEDUCTED' => 'N', + 'RESERVED' => 'N', + 'DELIVERY_ID' => $nowDelivery, + 'DELIVERY_NAME' => $nowDelivery[$nowDelivery]['NAME'], + 'CANCELED' => 'N', + 'MARKED' => 'N', + 'SYSTEM' => 'Y', + 'ACCOUNT_NUMBER' => $accountNumber . '/1', + 'EXTERNAL_DELIVERY' => 'N', + 'UPDATED_1C' => 'N', + 'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime() + )); + $shipment = Bitrix\Sale\Internals\ShipmentTable::add(array( + 'ORDER_ID' => $orderCrm['externalId'], + 'STATUS_ID' => 'DN', + 'PRICE_DELIVERY' => 0, + 'BASE_PRICE_DELIVERY' => 0, + 'CUSTOM_PRICE_DELIVERY' => 'N', + 'ALLOW_DELIVERY' => 'N', + 'DEDUCTED' => 'N', + 'RESERVED' => 'N', + 'DELIVERY_ID' => $nowDelivery, + 'DELIVERY_NAME' => $arDeliveryID[$nowDelivery]['NAME'], + 'CANCELED' => 'N', + 'MARKED' => 'N', + 'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(), + 'SYSTEM' => 'N', + 'ACCOUNT_NUMBER' => $accountNumber . '/2', + 'EXTERNAL_DELIVERY' => 'N', + 'UPDATED_1C' => 'N', + 'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime() + )); + } + } else { + //search for the order on the delivery site and delete / replace with no delivery + $noOrderId = \Bitrix\Sale\Delivery\Services\EmptyDeliveryService::getEmptyDeliveryServiceId(); + \Bitrix\Sale\OrderTable::update($orderCrm['externalId'], array('DELIVERY_ID' => $noOrderId)); + $obDeliverys = Bitrix\Sale\Internals\ShipmentTable::getList(array('filter' => array('ORDER_ID' => $orderCrm['externalId']), + 'order' => array('ID'))); + $create = true; + while ($arDelivery = $obDeliverys->fetch()) { + \Bitrix\Sale\Internals\ShipmentTable::update($arDelivery['ID'], array('DELIVERY_ID' => $noOrderId, 'DELIVERY_NAME' => GetMessage('NO_DELIVERY'))); + $create = false; + } + if ($create) { + $shipmentSystem = \Bitrix\Sale\Internals\ShipmentTable::add(array( + 'ORDER_ID' => $orderCrm['externalId'], + 'STATUS_ID' => 'DN', + 'CUSTOM_PRICE_DELIVERY' => 'N', + 'ALLOW_DELIVERY' => 'N', + 'DEDUCTED' => 'N', + 'RESERVED' => 'N', + 'DELIVERY_ID' => $noOrderId, + 'DELIVERY_NAME' => GetMessage('NO_DELIVERY'), + 'CANCELED' => 'N', + 'MARKED' => 'N', + 'SYSTEM' => 'Y', + 'ACCOUNT_NUMBER' => $accountNumber . '/1', + 'EXTERNAL_DELIVERY' => 'N', + 'UPDATED_1C' => 'N', + 'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime() + )); + $shipment = Bitrix\Sale\Internals\ShipmentTable::add(array( + 'ORDER_ID' => $orderCrm['externalId'], + 'STATUS_ID' => 'DN', + 'PRICE_DELIVERY' => 0, + 'BASE_PRICE_DELIVERY' => 0, + 'CUSTOM_PRICE_DELIVERY' => 'N', + 'ALLOW_DELIVERY' => 'N', + 'DEDUCTED' => 'N', + 'RESERVED' => 'N', + 'DELIVERY_ID' => $noOrderId, + 'DELIVERY_NAME' => GetMessage('NO_DELIVERY'), + 'CANCELED' => 'N', + 'MARKED' => 'N', + 'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(), + 'SYSTEM' => 'N', + 'ACCOUNT_NUMBER' => $accountNumber . '/2', + 'EXTERNAL_DELIVERY' => 'N', + 'UPDATED_1C' => 'N', + 'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime() + )); + } + } + + return true; + } + + public static function updateShipmentItem($orderId) + { + $orderBasket = \Bitrix\Sale\Internals\BasketTable::getList(array( + 'filter' => array('ORDER_ID' => $orderId), + 'select' => array('ID', 'QUANTITY') + )); + + $basketItems = array(); + while ($basketItem = $orderBasket->fetch()) { + $basketItems[] = $basketItem; + $bItems[] = $basketItem['ID']; + } + + $obShipments = \Bitrix\Sale\Internals\ShipmentTable::getList(array( + 'filter' => array('ORDER_ID' => $orderId), + 'select' => array('ID') + )); + + $shipmentItems = array(); + while ($arShipment = $obShipments->fetch()) { + $dlvBaslet = \Bitrix\Sale\Internals\ShipmentItemTable::getList(array( + 'order' => array('ORDER_DELIVERY_ID'), + 'filter' => array('ORDER_DELIVERY_ID' => $arShipment['ID']) + )); + $shipmentItems[$arShipment['ID']] = array(); + while ($item = $dlvBaslet->fetch()) { + $shipmentItems[$arShipment['ID']][] = $item; + } + } + + foreach ($basketItems as $basketItem) { + foreach ($shipmentItems as $key => $arShipmentItems) { + $found = false; + foreach ($arShipmentItems as $elShipmentItem) { + if (!in_array($elShipmentItem['BASKET_ID'], $bItems)) { + //delete the element + \Bitrix\Sale\Internals\ShipmentItemTable::delete($elShipmentItem['ID']); + } + if ($elShipmentItem['BASKET_ID'] == $basketItem['ID']) { + //found + $found = true; + //update quantity + if ($elShipmentItem['QUANTITY'] != $basketItem['QUANTITY']) { + \Bitrix\Sale\Internals\ShipmentItemTable::update($elShipmentItem['ID'], array('QUANTITY' => $basketItem['QUANTITY'])); + } + + } + } + if (!$found) { + //create + \Bitrix\Sale\Internals\ShipmentItemTable::add(array( + 'ORDER_DELIVERY_ID' => $key, + 'BASKET_ID' => $basketItem['ID'], + 'DATE_INSERT' => new \Bitrix\Main\Type\DateTime(), + 'QUANTITY' => $basketItem['QUANTITY'], + 'RESERVED_QUANTITY' => '0.00', + )); + } + } + } + } + + public static function paymentsUpdate($order, $paymentsCrm, $api) + { + $optionsPayTypes = array_flip(unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_PAYMENT_TYPES, 0))); + $optionsPayment = array_flip(unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_PAYMENT, 0))); + $allPaymentSystems = RCrmActions::PaymentList(); + foreach ($allPaymentSystems as $allPaymentSystem) { + $arPaySysmems[$allPaymentSystem['ID']] = $allPaymentSystem['NAME']; + } + $paymentsList = array(); + $paymentColl = $order->getPaymentCollection(); + foreach ($paymentColl as $paymentData) { + $data = $paymentData->getFields()->getValues(); + $paymentsList[$data['ID']] = $paymentData; + } + + //data from crm + $paySumm = 0; + foreach ($paymentsCrm['payments'] as $paymentCrm) { + if (!empty($paymentCrm['externalId'])) { + //find the payment + $nowPayment = $paymentsList[$paymentCrm['externalId']]; + //update data + if ($nowPayment instanceof \Bitrix\Sale\Payment) { + $nowPayment->setField('SUM', $paymentCrm['amount']); + if ($optionsPayTypes[$paymentCrm['type']] != $nowPayment->getField('PAY_SYSTEM_ID')) { + $nowPayment->setField('PAY_SYSTEM_ID', $optionsPayTypes[$paymentCrm['type']]); + $nowPayment->setField('PAY_SYSTEM_NAME', $arPaySysmems[$optionsPayTypes[$paymentCrm['type']]]); + } + if (isset($optionsPayment[$paymentCrm['status']])) { + $nowPayment->setField('PAID', $optionsPayment[$paymentCrm['status']]); + } + $nowPayment->save(); + + unset($paymentsList[$paymentCrm['externalId']]); + } + } else { + $newPayment = $paymentColl->createItem(); + $newPayment->setField('SUM', $paymentCrm['amount']); + $newPayment->setField('PAY_SYSTEM_ID', $optionsPayTypes[$paymentCrm['type']]); + $newPayment->setField('PAY_SYSTEM_NAME', $arPaySysmems[$optionsPayTypes[$paymentCrm['type']]]); + $newPayment->setField('PAID', $optionsPayment[$paymentCrm['status']] ? $optionsPayment[$paymentCrm['status']] : 'N'); + $newPayment->setField('CURRENCY', \Bitrix\Currency\CurrencyManager::getBaseCurrency()); + $newPayment->setField('IS_RETURN', 'N'); + $newPayment->setField('PRICE_COD', '0.00'); + $newPayment->setField('EXTERNAL_PAYMENT', 'N'); + $newPayment->setField('UPDATED_1C', 'N'); + $newPayment->save(); + + $newPaymentId = $newPayment->getId(); + + unset($paymentsList[$newPaymentId]); + + //RCrmActions::apiMethod($api, 'ordersPaymentEdit', __METHOD__, array('id' => $paymentCrm['id'], 'externalId' => $newPaymentId)); + } + + if ($optionsPayment[$paymentCrm['status']] == 'Y') { + $paySumm += $paymentCrm['amount']; + } + } + foreach ($paymentsList as $payment) { + if ($payment->isPaid()) { + $payment->setPaid("N"); + } + $payment->delete(); + } + $paymentColl->save(); + + if ($paymentsCrm['totalSumm'] == $paySumm) { + $order->setFieldNoDemand('PAYED', 'Y'); + } else { + $order->setFieldNoDemand('PAYED', 'N'); + } + $order->save(); + + return $order; + } + + public static function newValue($value) + { + if (array_key_exists('code', $value)) { + return $value['code']; + } else { + return $value; + } + } + + public static function removeEmpty($inputArray) + { + $outputArray = array(); + + if (!empty($inputArray)) { + foreach ($inputArray as $key => $element) { + if (!empty($element) || $element === 0 || $element === '0') { + if (is_array($element)) { + $element = self::removeEmpty($element); + } + + $outputArray[$key] = $element; + } + } + } + + return $outputArray; + } + + public static function setProp($obj, $value = '', $prop) + { + if (!isset($obj)) { + return false; + } + if ($prop) { + $obj->setField($prop, $value); + } elseif ($value) { + $obj->setValue($value); + } else { + $obj->delete(); + } + + return true; + } + + public static function getExistsItem($basket, $moduleId, $productId) + { + foreach ($basket as $basketItem) { + $itemExists = ($basketItem->getField('PRODUCT_ID') == $productId && $basketItem->getField('MODULE') == $moduleId); + + if ($itemExists) { + return $basketItem; + } + } + + return false; + } + + public static function getInfoElement($offerId) + { + $elementInfo = CIBlockElement::GetByID($offerId)->fetch(); + $url = CAllIBlock::ReplaceDetailUrl($elementInfo['DETAIL_PAGE_URL'], $elementInfo, false, 'E'); + $catalog = CCatalogProduct::GetByID($offerId); + + $info = array( + 'NAME' => $elementInfo['NAME'], + 'URL' => $url, + 'DIMENSIONS' => serialize(serialize(array( + 'WIDTH' => $catalog['WIDTH'], + 'HEIGHT' => $catalog['HEIGHT'], + 'LENGTH' => $catalog['LENGTH'], + ))), + 'WEIGHT' => $catalog['WEIGHT'] + ); + + return $info; + } +} + +class RetailUser extends CUser +{ + public function GetID() + { + $rsUser = CUser::GetList(($by = 'ID'), ($order = 'DESC'), array('LOGIN' => 'retailcrm%')); + + if ($arUser = $rsUser->Fetch()) { + return $arUser['ID']; + } else { + $retailUser = new CUser; + + $userPassword = uniqid(); + + $arFields = array( + "NAME" => 'retailcrm', + "LAST_NAME" => 'retailcrm', + "EMAIL" => 'retailcrm@retailcrm.com', + "LOGIN" => 'retailcrm', + "LID" => "ru", + "ACTIVE" => "Y", + "GROUP_ID" => array(2), + "PASSWORD" => $userPassword, + "CONFIRM_PASSWORD" => $userPassword + ); + $id = $retailUser->Add($arFields); + + if (!$id) { + return null; + } else { + return $id; + } + } + } +} \ No newline at end of file diff --git a/intaro.retailcrm/classes/general/icml/RetailCrmICML.php b/intaro.retailcrm/classes/general/icml/RetailCrmICML.php index bdf78f4a..782d3865 100644 --- a/intaro.retailcrm/classes/general/icml/RetailCrmICML.php +++ b/intaro.retailcrm/classes/general/icml/RetailCrmICML.php @@ -45,7 +45,7 @@ class RetailCrmICML 'g' => 'g', 'kg' => 'g', ); - + protected $measure = array ( 'pc. 1' => 'pc', 'm' => 'm', @@ -55,59 +55,59 @@ class RetailCrmICML public function Load() { - global $USER; - if (!isset($_SESSION["SESS_AUTH"]["USER_ID"]) || !$_SESSION["SESS_AUTH"]["USER_ID"]) { - $USER = new CUser; - } + global $USER; + if (!isset($_SESSION["SESS_AUTH"]["USER_ID"]) || !$_SESSION["SESS_AUTH"]["USER_ID"]) { + $USER = new CUser; + } - $this->isLogged = true; + $this->isLogged = true; - $defaultSite = CSite::GetList($by = "def", $order = "desc", array('DEF' => 'Y'))->Fetch(); - $this->encodingDefault = $defaultSite["CHARSET"]; - - $url = 'https://' . $this->serverName; - $curlHandler = curl_init(); - curl_setopt($curlHandler, CURLOPT_URL, $url); - $responseBody = curl_exec($curlHandler); - $statusCode = curl_getinfo($curlHandler, CURLINFO_HTTP_CODE); - curl_close($curlHandler); - if ($statusCode == 200) { - $this->protocol = 'https://'; - } else { - $this->protocol = 'http://'; - } - - $this->PrepareSettings(); + $defaultSite = CSite::GetList($by = "def", $order = "desc", array('DEF' => 'Y'))->Fetch(); + $this->encodingDefault = $defaultSite["CHARSET"]; - $this->fp = $this->PrepareFile($this->filename. '.tmp'); + $url = 'https://' . $this->serverName; + $curlHandler = curl_init(); + curl_setopt($curlHandler, CURLOPT_URL, $url); + $responseBody = curl_exec($curlHandler); + $statusCode = curl_getinfo($curlHandler, CURLINFO_HTTP_CODE); + curl_close($curlHandler); + if ($statusCode == 200) { + $this->protocol = 'https://'; + } else { + $this->protocol = 'http://'; + } - if ($this->isLogged) { - $this->fpLog = $this->PrepareFile($this->logFile); - $this->WriteLog("Start Loading"); - } + $this->PrepareSettings(); - $this->PreWriteCatalog(); + $this->fp = $this->PrepareFile($this->filename. '.tmp'); - $categories = $this->GetCategories(); + if ($this->isLogged) { + $this->fpLog = $this->PrepareFile($this->logFile); + $this->WriteLog("Start Loading"); + } - $this->WriteCategories($categories); + $this->PreWriteCatalog(); - $this->PreWriteOffers(); - $this->BuildOffers($categories); - $this->PostWriteOffers(); + $categories = $this->GetCategories(); - $this->PostWriteCatalog(); + $this->WriteCategories($categories); - if ($this->isLogged) { - $this->WriteLog("Loading was ended successfully (peek memory usage: " . memory_get_peak_usage() . ")"); - } + $this->PreWriteOffers(); + $this->BuildOffers($categories); + $this->PostWriteOffers(); - $this->CloseFile($this->fp); - $this->CloseFile($this->fpLog); - unlink($defaultSite['ABS_DOC_ROOT'] . $this->filename); - rename($defaultSite['ABS_DOC_ROOT'] . $this->filename. '.tmp', $defaultSite['ABS_DOC_ROOT'] . $this->filename); + $this->PostWriteCatalog(); - return true; + if ($this->isLogged) { + $this->WriteLog("Loading was ended successfully (peek memory usage: " . memory_get_peak_usage() . ")"); + } + + $this->CloseFile($this->fp); + $this->CloseFile($this->fpLog); + unlink($defaultSite['ABS_DOC_ROOT'] . $this->filename); + rename($defaultSite['ABS_DOC_ROOT'] . $this->filename. '.tmp', $defaultSite['ABS_DOC_ROOT'] . $this->filename); + + return true; } @@ -136,49 +136,48 @@ class RetailCrmICML protected function PrepareFile($filename) { - $fullFilename = $_SERVER["DOCUMENT_ROOT"] . $filename; - CheckDirPath($fullFilename); + $fullFilename = $_SERVER["DOCUMENT_ROOT"] . $filename; + CheckDirPath($fullFilename); - if ($fp = @fopen($fullFilename, "w")){ - return $fp; - } else { - return false; - } + if ($fp = @fopen($fullFilename, "w")){ + return $fp; + } else { + return false; + } } protected function PreWriteCatalog() { - @fwrite($this->fp, "PrepareValue(Date("Y-m-d H:i:s")) . "\">\n - \n - " . $this->PrepareValue(COption::GetOptionString("main", "site_name", ""))."\n - " . $this->PrepareValue(COption::GetOptionString("main", "site_name", ""))."\n" - ); - + @fwrite($this->fp, "PrepareValue(Date("Y-m-d H:i:s")) . "\">\n + \n + " . $this->PrepareValue(COption::GetOptionString("main", "site_name", ""))."\n + " . $this->PrepareValue(COption::GetOptionString("main", "site_name", ""))."\n" + ); } protected function WriteCategories($categories) { - $stringCategories = ""; - @fwrite($this->fp, "\n"); - foreach ($categories as $category) { - $stringCategories .= $this->BuildCategory($category); - } - @fwrite($this->fp, $stringCategories); - @fwrite($this->fp, "\n"); + $stringCategories = ""; + @fwrite($this->fp, "\n"); + foreach ($categories as $category) { + $stringCategories .= $this->BuildCategory($category); + } + @fwrite($this->fp, $stringCategories); + @fwrite($this->fp, "\n"); } protected function PreWriteOffers() { - @fwrite($this->fp, "\n"); + @fwrite($this->fp, "\n"); } - protected function PostWriteOffers() + protected function PostWriteOffers() { - @fwrite($this->fp, "\n"); + @fwrite($this->fp, "\n"); } - protected function WriteOffers($offers) + protected function WriteOffers($offers) { - @fwrite($this->fp, $offers); + @fwrite($this->fp, $offers); } protected function WriteLog($text) @@ -190,53 +189,51 @@ class RetailCrmICML protected function PostWriteCatalog() { - @fwrite($this->fp, "\n - \n"); + @fwrite($this->fp, "\n + \n"); } protected function CloseFile($fp) { - @fclose($fp); + @fclose($fp); } - protected function GetCategories() { - $categories = array(); - foreach ($this->iblocks as $id) { - $filter = array("IBLOCK_ID" => $id); + $categories = array(); + foreach ($this->iblocks as $id) { + $filter = array("IBLOCK_ID" => $id); - $dbRes = CIBlockSection::GetList(array("left_margin" => "asc"), $filter); - $hasCategories = false; - while ($arRes = $dbRes->Fetch()) { - $categories[$arRes['ID']] = $arRes; - $hasCategories = true; - } - if (!$hasCategories) { - $iblock = CIBlock::GetByID($id)->Fetch(); - - $arRes = Array(); - $arRes['ID'] = $this->mainSection + $id; - $arRes['IBLOCK_SECTION_ID'] = 0; - $arRes['NAME'] = sprintf(GetMessage('ROOT_CATEGORY_FOR_CATALOG'), $iblock['NAME']); - $categories[$arRes['ID']] = $arRes; - } + $dbRes = CIBlockSection::GetList(array("left_margin" => "asc"), $filter); + $hasCategories = false; + while ($arRes = $dbRes->Fetch()) { + $categories[$arRes['ID']] = $arRes; + $hasCategories = true; } - - return $categories; + if (!$hasCategories) { + $iblock = CIBlock::GetByID($id)->Fetch(); + $arRes = Array(); + $arRes['ID'] = $this->mainSection + $id; + $arRes['IBLOCK_SECTION_ID'] = 0; + $arRes['NAME'] = sprintf(GetMessage('ROOT_CATEGORY_FOR_CATALOG'), $iblock['NAME']); + $categories[$arRes['ID']] = $arRes; + } + } + + return $categories; } protected function BuildCategory($arCategory) { - return " - PrepareValue($arCategory["ID"]) . "\"" - . ( intval($arCategory["IBLOCK_SECTION_ID"] ) > 0 ? - " parentId=\"" . $this->PrepareValue($arCategory["IBLOCK_SECTION_ID"]) . "\"" - :"") - . ">" - . $this->PrepareValue($arCategory["NAME"]) - . "\n"; + return " + PrepareValue($arCategory["ID"]) . "\"" + . ( intval($arCategory["IBLOCK_SECTION_ID"] ) > 0 ? + " parentId=\"" . $this->PrepareValue($arCategory["IBLOCK_SECTION_ID"]) . "\"" + :"") + . ">" + . $this->PrepareValue($arCategory["NAME"]) + . "\n"; } @@ -276,7 +273,6 @@ class RetailCrmICML $arSelectOffer = array( 'ID', - 'ACTIVE', "NAME", "DETAIL_PAGE_URL", "DETAIL_PICTURE", @@ -417,7 +413,7 @@ class RetailCrmICML $offer['DETAIL_PAGE_URL'] = $product["DETAIL_PAGE_URL"]; $offer['PICTURE'] = $product["PICTURE"]; $offer['PRODUCT_NAME'] = $product["NAME"]; - $offer['PRODUCT_ACTIVE'] = $offer["ACTIVE"]; + $offer['PRODUCT_ACTIVE'] = $product["ACTIVE"]; $offer['PRICE'] = $offer['CATALOG_PRICE_' . $basePriceId]; $offer['PURCHASE_PRICE'] = $offer['CATALOG_PURCHASING_PRICE']; $offer['QUANTITY'] = $offer["CATALOG_QUANTITY"]; @@ -553,7 +549,7 @@ class RetailCrmICML } else { $offer .= '' . "\n"; } - + } $offer.= "\n"; diff --git a/intaro.retailcrm/classes/general/inventories/RetailCrmInventories.php b/intaro.retailcrm/classes/general/inventories/RetailCrmInventories.php new file mode 100644 index 00000000..3b373bcd --- /dev/null +++ b/intaro.retailcrm/classes/general/inventories/RetailCrmInventories.php @@ -0,0 +1,163 @@ +storesList()->stores; + } catch (\RetailCrm\Exception\CurlException $e) { + RCrmActions::eventLog( + 'RetailCrmInventories::inventoriesUpload()', 'RetailCrm\ApiClient::storesList::CurlException', + $e->getCode() . ': ' . $e->getMessage() + ); + + return false; + } + + $inventoriesType = array(); + if (count($inventoriesList) > 0) { + foreach ($inventoriesList as $inventory) { + $inventoriesType[$inventory['code']] = $inventory['inventoryType']; + } + } else { + RCrmActions::eventLog('RetailCrmInventories::inventoriesUpload()', '$inventoriesList', 'Stores in crm not found'); + + return false; + } + if (count($shops) == 0) { + RCrmActions::eventLog('RetailCrmInventories::inventoriesUpload()', '$shops', 'No stores selected for download'); + + return false; + } + + if (count($infoBlocks) > 0) { + $log = new Logger(); + + foreach ($infoBlocks as $id) { + $iblockOffer = CCatalogSKU::GetInfoByProductIBlock($id); + + $arNavStatParams = array( + 'iNumPage' => 1, + 'nPageSize' => self::$pageSize, + ); + + do { + $dbResProductsIds = CIBlockElement::GetList(array('ID'), array('IBLOCK_ID' => $id), false, $arNavStatParams, array('ID')); + $products = array(); + while ($product = $dbResProductsIds->fetch()) { + $products[$product['ID']] = $product; + $products[$product['ID']]['offers'] = array(); + } + + if (!empty($iblockOffer['IBLOCK_ID'])) { + $arFilterOffer = array( + 'IBLOCK_ID' => $iblockOffer['IBLOCK_ID'], + 'PROPERTY_' . $iblockOffer['SKU_PROPERTY_ID'] => array_keys($products), + ); + + $dbResOffers = CIBlockElement::GetList(array('ID'), $arFilterOffer, false, false, array('ID', 'PROPERTY_' . $iblockOffer['SKU_PROPERTY_ID'])); + while ($offer = $dbResOffers->fetch()) { + $products[$offer['PROPERTY_' . $iblockOffer['SKU_PROPERTY_ID'] . '_VALUE']]['offers'][] = $offer['ID']; + } + } + + $elems = array(); + foreach ($products as $product) { + if (count($product['offers']) > 0) { + $elems = array_merge($elems, $product['offers']); + } else { + $elems[] = $product['ID']; + } + } + + $invUpload = array(); + $dbStoreProduct = CCatalogStoreProduct::GetList( + array(), + array('PRODUCT_ID' => $elems, 'STORE_ID' => array_keys($stores)), + false, + false, + array('PRODUCT_ID', 'STORE_ID', 'AMOUNT') + ); + while ($arStoreProduct = $dbStoreProduct->Fetch()) { + if (!isset($invUpload[$arStoreProduct['PRODUCT_ID']])) { + $invUpload[$arStoreProduct['PRODUCT_ID']] = array( + 'externalId' => $arStoreProduct['PRODUCT_ID'] + ); + } + $invUpload[$arStoreProduct['PRODUCT_ID']]['stores'][] = array( + 'code' => $stores[$arStoreProduct['STORE_ID']], + 'available' => self::switchCount($arStoreProduct['AMOUNT'], $inventoriesType[$stores[$arStoreProduct['STORE_ID']]]), + ); + } + //for log + $splitedItems = array_chunk($invUpload, 200); + foreach ($splitedItems as $chunk) { + $log->write($chunk, 'inventoriesUpload'); + + foreach ($shops as $shop) { + RCrmActions::apiMethod($api, 'storeInventoriesUpload', __METHOD__, $chunk, $shop); + time_nanosleep(0, 250000000); + } + } + + $arNavStatParams['iNumPage'] = $dbResProductsIds->NavPageNomer + 1; + } while($dbResProductsIds->NavPageNomer < $dbResProductsIds->NavPageCount); + } + } else { + RCrmActions::eventLog('RetailCrmInventories::inventoriesUpload()', '$infoBlocks', 'No iblocks selected'); + + return false; + } + + return 'RetailCrmInventories::inventoriesUpload();'; + } + + public static function switchCount($val, $type) + { + if ($val < 0) { + $val = 0; + } elseif ($val > 999999) { + $val = 999999; + } + + if ($type == 'available' && $val > 0) { + $val = 1; + } + + return $val; + } +} \ No newline at end of file diff --git a/intaro.retailcrm/classes/general/order/RetailCrmOrder.php b/intaro.retailcrm/classes/general/order/RetailCrmOrder_v4.php similarity index 94% rename from intaro.retailcrm/classes/general/order/RetailCrmOrder.php rename to intaro.retailcrm/classes/general/order/RetailCrmOrder_v4.php index 891c539d..de7db1d6 100644 --- a/intaro.retailcrm/classes/general/order/RetailCrmOrder.php +++ b/intaro.retailcrm/classes/general/order/RetailCrmOrder_v4.php @@ -57,32 +57,31 @@ class RetailCrmOrder $arParams['optionsOrderTypes'][$arFields['PERSON_TYPE_ID']] : '', 'status' => isset($arParams['optionsPayStatuses'][$arFields['STATUS_ID']]) ? $arParams['optionsPayStatuses'][$arFields['STATUS_ID']] : '', - 'statusComment' => $arFields['REASON_CANCELED'], 'customerComment' => $arFields['USER_DESCRIPTION'], 'managerComment' => $arFields['COMMENTS'], 'delivery' => array( 'cost' => $arFields['PRICE_DELIVERY'] ), ); - if (isset($_COOKIE['_rc']) && $_COOKIE['_rc'] != '') { + if ($send && isset($_COOKIE['_rc']) && $_COOKIE['_rc'] != '') { $order['customer']['browserId'] = $_COOKIE['_rc']; } $order['contragent']['contragentType'] = $arParams['optionsContragentType'][$arFields['PERSON_TYPE_ID']]; - //свойства + //fields foreach ($arFields['PROPS']['properties'] as $prop) { if ($search = array_search($prop['CODE'], $arParams['optionsLegalDetails'][$arFields['PERSON_TYPE_ID']])) { - $order['contragent'][$search] = $prop['VALUE'][0];//юр данные заказа + $order['contragent'][$search] = $prop['VALUE'][0];//legal order data } elseif ($search = array_search($prop['CODE'], $arParams['optionsCustomFields'][$arFields['PERSON_TYPE_ID']])) { - $order['customFields'][$search] = $prop['VALUE'][0];//кастомные свойства - } elseif ($search = array_search($prop['CODE'], $arParams['optionsOrderProps'][$arFields['PERSON_TYPE_ID']])) {//остальное - if (in_array($search, array('fio', 'phone', 'email'))) {//фио, телефон, почта + $order['customFields'][$search] = $prop['VALUE'][0];//custom properties + } elseif ($search = array_search($prop['CODE'], $arParams['optionsOrderProps'][$arFields['PERSON_TYPE_ID']])) {//other + if (in_array($search, array('fio', 'phone', 'email'))) {//fio, phone, email if ($search == 'fio') { - $order = array_merge($order, RCrmActions::explodeFIO($prop['VALUE'][0]));//добавляем поля фио + $order = array_merge($order, RCrmActions::explodeFIO($prop['VALUE'][0]));//add fio fields } else { - $order[$search] = $prop['VALUE'][0];//телефон и почта + $order[$search] = $prop['VALUE'][0];//phone, email } - } else {//остальное - адрес + } else {//address if ($prop['TYPE'] == 'LOCATION' && isset($prop['VALUE'][0]) && $prop['VALUE'][0] != '') { $arLoc = \Bitrix\Sale\Location\LocationTable::getByCode($prop['VALUE'][0])->fetch(); if ($arLoc) { @@ -105,7 +104,6 @@ class RetailCrmOrder $order['countryIso'] = $countrys[$countryOrder['NAME']]; } } - } $prop['VALUE'][0] = $location['NAME']; } @@ -115,7 +113,7 @@ class RetailCrmOrder } } - //доставки + //deliverys if (array_key_exists($arFields['DELIVERYS'][0]['id'], $arParams['optionsDelivTypes'])) { $order['delivery']['code'] = $arParams['optionsDelivTypes'][$arFields['DELIVERYS'][0]['id']]; if (isset($arFields['DELIVERYS'][0]['service']) && $arFields['DELIVERYS'][0]['service'] != '') { @@ -123,7 +121,7 @@ class RetailCrmOrder } } - //корзина + //basket foreach ($arFields['BASKET'] as $product) { $item = array( 'quantity' => $product['QUANTITY'], @@ -144,22 +142,21 @@ class RetailCrmOrder $order['items'][] = $item; } - //отправка + //send if (function_exists('retailCrmBeforeOrderSend')) { $newResOrder = retailCrmBeforeOrderSend($order, $arFields); if (is_array($newResOrder) && !empty($newResOrder)) { $order = $newResOrder; + } elseif ($newResOrder === false) { + RCrmActions::eventLog('RetailCrmOrder::orderSend', 'retailCrmBeforeOrderSend()', 'OrderID = ' . $arFields['ID'] . '. Sending canceled after retailCrmBeforeOrderSend'); + + return false; } } $normalizer = new RestNormalizer(); $order = $normalizer->normalize($order, 'orders'); - if (isset($arParams['optionsSitesList']) && is_array($arParams['optionsSitesList']) && - array_key_exists($arFields['LID'], $arParams['optionsSitesList'])) { - $site = $arParams['optionsSitesList'][$arFields['LID']]; - } - $log = new Logger(); $log->write($order, 'order'); diff --git a/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php b/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php new file mode 100644 index 00000000..02a2af7d --- /dev/null +++ b/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php @@ -0,0 +1,420 @@ + $customer) + */ + public static function orderSend($arFields, $api, $arParams, $send = false, $site = null, $methodApi = 'ordersEdit') + { + if (!$api || empty($arParams)) { // add cond to check $arParams + return false; + } + if (empty($arFields)) { + RCrmActions::eventLog('RetailCrmOrder::orderSend', 'empty($arFields)', 'incorrect order'); + return false; + } + + $order = array( + 'number' => $arFields['NUMBER'], + 'externalId' => $arFields['ID'], + 'createdAt' => new \DateTime($arFields['DATE_INSERT']), + 'customer' => array('externalId' => $arFields['USER_ID']), + 'orderType' => isset($arParams['optionsOrderTypes'][$arFields['PERSON_TYPE_ID']]) ? + $arParams['optionsOrderTypes'][$arFields['PERSON_TYPE_ID']] : '', + 'status' => isset($arParams['optionsPayStatuses'][$arFields['STATUS_ID']]) ? + $arParams['optionsPayStatuses'][$arFields['STATUS_ID']] : '', + 'customerComment' => $arFields['USER_DESCRIPTION'], + 'managerComment' => $arFields['COMMENTS'], + 'delivery' => array( + 'cost' => $arFields['PRICE_DELIVERY'] + ), + ); + if ($send && isset($_COOKIE['_rc']) && $_COOKIE['_rc'] != '') { + $order['customer']['browserId'] = $_COOKIE['_rc']; + } + $order['contragent']['contragentType'] = $arParams['optionsContragentType'][$arFields['PERSON_TYPE_ID']]; + + //fields + foreach ($arFields['PROPS']['properties'] as $prop) { + if ($search = array_search($prop['CODE'], $arParams['optionsLegalDetails'][$arFields['PERSON_TYPE_ID']])) { + $order['contragent'][$search] = $prop['VALUE'][0];//legal order data + } elseif ($search = array_search($prop['CODE'], $arParams['optionsCustomFields'][$arFields['PERSON_TYPE_ID']])) { + $order['customFields'][$search] = $prop['VALUE'][0];//custom properties + } elseif ($search = array_search($prop['CODE'], $arParams['optionsOrderProps'][$arFields['PERSON_TYPE_ID']])) {//other + if (in_array($search, array('fio', 'phone', 'email'))) {//fio, phone, email + if ($search == 'fio') { + $order = array_merge($order, RCrmActions::explodeFIO($prop['VALUE'][0]));//add fio fields + } else { + $order[$search] = $prop['VALUE'][0];//phone, email + } + } else {//address + if ($prop['TYPE'] == 'LOCATION' && isset($prop['VALUE'][0]) && $prop['VALUE'][0] != '') { + $arLoc = \Bitrix\Sale\Location\LocationTable::getByCode($prop['VALUE'][0])->fetch(); + if ($arLoc) { + $server = \Bitrix\Main\Context::getCurrent()->getServer()->getDocumentRoot(); + $countrys = array(); + if (file_exists($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/objects.xml')) { + $countrysFile = simplexml_load_file($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/country.xml'); + foreach ($countrysFile->country as $country) { + $countrys[RCrmActions::fromJSON((string) $country->name)] = (string) $country->alpha; + } + } + $location = \Bitrix\Sale\Location\Name\LocationTable::getList(array( + 'filter' => array('=LOCATION_ID' => $arLoc['CITY_ID'], 'LANGUAGE_ID' => 'ru') + ))->fetch(); + if (count($countrys) > 0) { + $countryOrder = \Bitrix\Sale\Location\Name\LocationTable::getList(array( + 'filter' => array('=LOCATION_ID' => $arLoc['COUNTRY_ID'], 'LANGUAGE_ID' => 'ru') + ))->fetch(); + if(isset($countrys[$countryOrder['NAME']])){ + $order['countryIso'] = $countrys[$countryOrder['NAME']]; + } + } + } + $prop['VALUE'][0] = $location['NAME']; + } + + $order['delivery']['address'][$search] = $prop['VALUE'][0]; + } + } + } + + //deliverys + if (array_key_exists($arFields['DELIVERYS'][0]['id'], $arParams['optionsDelivTypes'])) { + $order['delivery']['code'] = $arParams['optionsDelivTypes'][$arFields['DELIVERYS'][0]['id']]; + if (isset($arFields['DELIVERYS'][0]['service']) && $arFields['DELIVERYS'][0]['service'] != '') { + $order['delivery']['service']['code'] = $arFields['DELIVERYS'][0]['service']; + } + } + + //basket + foreach ($arFields['BASKET'] as $product) { + $item = array( + 'quantity' => $product['QUANTITY'], + 'offer' => array('externalId' => $product['PRODUCT_ID'], + 'xmlId' => $product['PRODUCT_XML_ID'] + ), + 'productName' => $product['NAME'] + ); + + $pp = CCatalogProduct::GetByID($product['PRODUCT_ID']); + if (is_null($pp['PURCHASING_PRICE']) == false) { + $item['purchasePrice'] = $pp['PURCHASING_PRICE']; + } + $item['discountManualAmount'] = (double) $product['DISCOUNT_PRICE']; + $item['discountManualPercent'] = 0; + $item['initialPrice'] = (double) $product['PRICE'] + (double) $product['DISCOUNT_PRICE']; + + $order['items'][] = $item; + } + + //payments + $payments = array(); + foreach ($arFields['PAYMENTS'] as $payment) { + $pm = array( + 'type' => isset($arParams['optionsPayTypes'][$payment['PAY_SYSTEM_ID']]) ? $arParams['optionsPayTypes'][$payment['PAY_SYSTEM_ID']] : '', + 'amount' => $payment['SUM'] + ); + if (!empty($payment['ID'])) { + $pm['externalId'] = $payment['ID']; + } + if (!empty($payment['DATE_PAID'])) { + $pm['paidAt'] = new \DateTime($payment['DATE_PAID']); + } + if (!empty($arParams['optionsPayment'][$payment['PAID']])) { + $pm['status'] = $arParams['optionsPayment'][$payment['PAID']]; + } + $payments[] = $pm; + } + if (count($payments) > 0) { + $order['payments'] = $payments; + } + + //send + if (function_exists('retailCrmBeforeOrderSend')) { + $newResOrder = retailCrmBeforeOrderSend($order, $arFields); + if (is_array($newResOrder) && !empty($newResOrder)) { + $order = $newResOrder; + } elseif ($newResOrder === false) { + RCrmActions::eventLog('RetailCrmOrder::orderSend', 'retailCrmBeforeOrderSend()', 'OrderID = ' . $arFields['ID'] . '. Sending canceled after retailCrmBeforeOrderSend'); + + return false; + } + } + + $normalizer = new RestNormalizer(); + $order = $normalizer->normalize($order, 'orders'); + + $log = new Logger(); + $log->write($order, 'order'); + + if($send) { + if (!RCrmActions::apiMethod($api, $methodApi, __METHOD__, $order, $site)) { + return false; + } + + if ($methodApi == 'ordersEdit') { + $crmPayments = array(); + if (!empty($arParams['crmOrder']['payments'])) { + foreach ($arParams['crmOrder']['payments'] as $crmPayment) { + if (isset($crmPayment['externalId'])) { + $crmPayments['externalIds'][$crmPayment['externalId']] = $crmPayment; + } else { + $crmPayments['ids'][$crmPayment['id']] = $crmPayment; + } + } + } + + foreach ($order['payments'] as $payment) { + if (isset($crmPayments['externalIds'][$payment['externalId']])) { + //update payment + if(RCrmActions::apiMethod($api, 'ordersPaymentEdit', __METHOD__, $payment, $site)){ + unset($crmPayments['externalIds'][$payment['externalId']]); + } + } else { + //create + $payment['order']['externalId'] = $order['externalId']; + RCrmActions::apiMethod($api, 'ordersPaymentCreate', __METHOD__, $payment, $site); + } + } + + //delete in crm + if (!empty($crmPayments['ids'])) { + foreach ($crmPayments['ids'] as $payment) { + //delete + RCrmActions::apiMethod($api, 'ordersPaymentDelete', __METHOD__, $payment['id']); + } + } + if (!empty($crmPayments['externalIds'])) { + foreach ($crmPayments['externalIds'] as $payment) { + //delete + RCrmActions::apiMethod($api, 'ordersPaymentDelete', __METHOD__, $payment['id']); + } + } + } + } + + return $order; + } + + /** + * Mass order uploading, without repeating; always returns true, but writes error log + * @param $pSize + * @param $failed -- flag to export failed orders + * @return boolean + */ + public static function uploadOrders($pSize = 50, $failed = false, $orderList = false) + { + if (!CModule::IncludeModule("iblock")) { + RCrmActions::eventLog('RetailCrmOrder::uploadOrders', 'iblock', 'module not found'); + return true; + } + if (!CModule::IncludeModule("sale")) { + RCrmActions::eventLog('RetailCrmOrder::uploadOrders', 'sale', 'module not found'); + return true; + } + if (!CModule::IncludeModule("catalog")) { + RCrmActions::eventLog('RetailCrmOrder::uploadOrders', 'catalog', 'module not found'); + return true; + } + + $resOrders = array(); + $resCustomers = array(); + $orderIds = array(); + + $lastUpOrderId = COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_LAST_ID, 0); + $failedIds = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_FAILED_IDS, 0)); + + if ($failed == true && $failedIds !== false && count($failedIds) > 0) { + $orderIds = $failedIds; + } elseif ($orderList !== false && count($orderList) > 0) { + $orderIds = $orderList; + } else { + $dbOrder = \Bitrix\Sale\Internals\OrderTable::GetList(array( + 'order' => array("ID" => "ASC"), + 'filter' => array('>ID' => $lastUpOrderId), + 'limit' => $pSize, + 'select' => array('ID') + )); + while ($arOrder = $dbOrder->fetch()) { + $orderIds[] = $arOrder['ID']; + } + } + + if (count($orderIds) <= 0) { + return false; + } + + $api_host = COption::GetOptionString(self::$MODULE_ID, self::$CRM_API_HOST_OPTION, 0); + $api_key = COption::GetOptionString(self::$MODULE_ID, self::$CRM_API_KEY_OPTION, 0); + + $optionsSitesList = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_SITES_LIST, 0)); + $optionsOrderTypes = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_TYPES_ARR, 0)); + $optionsDelivTypes = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_DELIVERY_TYPES_ARR, 0)); + $optionsPayTypes = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_PAYMENT_TYPES, 0)); + $optionsPayStatuses = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_PAYMENT_STATUSES, 0)); // --statuses + $optionsPayment = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_PAYMENT, 0)); + $optionsOrderProps = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_PROPS, 0)); + $optionsLegalDetails = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_LEGAL_DETAILS, 0)); + $optionsContragentType = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_CONTRAGENT_TYPE, 0)); + $optionsCustomFields = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_CUSTOM_FIELDS, 0)); + + $api = new RetailCrm\ApiClient($api_host, $api_key); + + $arParams = array( + 'optionsOrderTypes' => $optionsOrderTypes, + 'optionsDelivTypes' => $optionsDelivTypes, + 'optionsPayTypes' => $optionsPayTypes, + 'optionsPayStatuses' => $optionsPayStatuses, + 'optionsPayment' => $optionsPayment, + 'optionsOrderProps' => $optionsOrderProps, + 'optionsLegalDetails' => $optionsLegalDetails, + 'optionsContragentType' => $optionsContragentType, + 'optionsSitesList' => $optionsSitesList, + 'optionsCustomFields' => $optionsCustomFields, + ); + + $recOrders = array(); + foreach ($orderIds as $orderId) { + $id = \Bitrix\Sale\Order::load($orderId); + if (!$id) { + continue; + } + $order = self::orderObjToArr($id); + $user = Bitrix\Main\UserTable::getById($order['USER_ID'])->fetch(); + + if(array_key_exists($arOrder['LID'], $optionsSitesList)) { + $site = $optionsSitesList[$arOrder['LID']]; + } else { + $site = null; + } + + $arCustomers = RetailCrmUser::customerSend($user, $api, $optionsContragentType[$order['PERSON_TYPE_ID']], false, $site); + $arOrders = self::orderSend($order, $api, $arParams, false, $site); + + if (!$arCustomers || !$arOrders) { + continue; + } + + $resCustomers[$order['LID']][] = $arCustomers; + $resOrders[$order['LID']][] = $arOrders; + + $recOrders[] = $orderId; + } + + if (count($resOrders) > 0) { + foreach ($resCustomers as $key => $customerLoad) { + if(array_key_exists($key, $optionsSitesList)) { + $site = $optionsSitesList[$key]; + } else { + $site = null; + } + if (RCrmActions::apiMethod($api, 'customersUpload', __METHOD__, $customerLoad, $site) === false) { + return false; + } + if (count($optionsSitesList) > 1) { + time_nanosleep(0, 250000000); + } + } + foreach ($resOrders as $key => $orderLoad) { + if(array_key_exists($key, $optionsSitesList)) { + $site = $optionsSitesList[$key]; + } else { + $site = null; + } + if (RCrmActions::apiMethod($api, 'ordersUpload', __METHOD__, $orderLoad, $site) === false) { + return false; + } + if (count($optionsSitesList) > 1) { + time_nanosleep(0, 250000000); + } + } + if ($failed == true && $failedIds !== false && count($failedIds) > 0) { + COption::SetOptionString(self::$MODULE_ID, self::$CRM_ORDER_FAILED_IDS, serialize(array_diff($failedIds, $recOrders))); + } elseif ($lastUpOrderId < max($recOrders) && $orderList === false) { + COption::SetOptionString(self::$MODULE_ID, self::$CRM_ORDER_LAST_ID, max($recOrders)); + } + } + + return true; + } + + public static function orderObjToArr($obOrder) + { + $arOrder = array( + 'ID' => $obOrder->getId(), + 'NUMBER' => $obOrder->getField('ACCOUNT_NUMBER'), + 'LID' => $obOrder->getSiteId(), + 'DATE_INSERT' => $obOrder->getDateInsert(), + 'STATUS_ID' => $obOrder->getField('STATUS_ID'), + 'USER_ID' => $obOrder->getUserId(), + 'PERSON_TYPE_ID' => $obOrder->getPersonTypeId(), + 'CURRENCY' => $obOrder->getCurrency(), + 'PAYMENTS' => array(), + 'DELIVERYS' => array(), + 'PRICE_DELIVERY' => $obOrder->getDeliveryPrice(), + 'PROPS' => $obOrder->getPropertyCollection()->getArray(), + 'DISCOUNTS' => $obOrder->getDiscount()->getApplyResult(), + 'BASKET' => array(), + 'USER_DESCRIPTION' => $obOrder->getField('USER_DESCRIPTION'), + 'COMMENTS' => $obOrder->getField('COMMENTS'), + 'REASON_CANCELED' => $obOrder->getField('REASON_CANCELED'), + ); + + $shipmentList = $obOrder->getShipmentCollection(); + foreach ($shipmentList as $shipmentData) { + if ($shipmentData->getDeliveryId()) { + $delivery = \Bitrix\Sale\Delivery\Services\Manager::getById($shipmentData->getDeliveryId()); + if ($delivery['PARENT_ID']) { + $servise = explode(':', $delivery['CODE']); + $shipment = array('id' => $delivery['PARENT_ID'], 'service' => $servise[1]); + } else { + $shipment = array('id' => $delivery['ID']); + } + $arOrder['DELIVERYS'][] = $shipment; + } + } + + $paymentList = $obOrder->getPaymentCollection(); + foreach ($paymentList as $paymentData) { + $arOrder['PAYMENTS'][] = $paymentData->getFields()->getValues(); + } + + $basketItems = $obOrder->getBasket(); + foreach ($basketItems as $item) { + $arOrder['BASKET'][] = $item->getFields(); + } + + return $arOrder; + } +} diff --git a/intaro.retailcrm/classes/general/prices/RetailCrmPrices.php b/intaro.retailcrm/classes/general/prices/RetailCrmPrices.php new file mode 100644 index 00000000..242fb9c2 --- /dev/null +++ b/intaro.retailcrm/classes/general/prices/RetailCrmPrices.php @@ -0,0 +1,137 @@ + 0) { + $log = new Logger(); + + foreach ($infoBlocks as $id) { + $iblockOffer = CCatalogSKU::GetInfoByProductIBlock($id); + + $arNavStatParams = array( + 'iNumPage' => 1, + 'nPageSize' => self::$pageSize, + ); + + do { + $dbResProductsIds = CIBlockElement::GetList(array('ID'), array('IBLOCK_ID' => $id), false, $arNavStatParams, array('ID')); + $products = array(); + while ($product = $dbResProductsIds->fetch()) { + $products[$product['ID']] = $product; + $products[$product['ID']]['offers'] = array(); + } + + if (!empty($iblockOffer['IBLOCK_ID'])) { + $arFilterOffer = array( + 'IBLOCK_ID' => $iblockOffer['IBLOCK_ID'], + 'PROPERTY_' . $iblockOffer['SKU_PROPERTY_ID'] => array_keys($products), + ); + + $dbResOffers = CIBlockElement::GetList(array('ID'), $arFilterOffer, false, false, array('ID', 'PROPERTY_' . $iblockOffer['SKU_PROPERTY_ID'])); + while ($offer = $dbResOffers->fetch()) { + $products[$offer['PROPERTY_' . $iblockOffer['SKU_PROPERTY_ID'] . '_VALUE']]['offers'][] = $offer['ID']; + } + } + + $elems = array(); + foreach ($products as $product) { + if (count($product['offers']) > 0) { + $elems = array_merge($elems, $product['offers']); + } else { + $elems[] = $product['ID']; + } + } + + $pricesUpload = array(); + $dbPricesProduct = CPrice::GetList( + array(), + array('PRODUCT_ID' => $elems, 'CATALOG_GROUP_ID' => array_keys($prices)), + false, + false, + array('PRODUCT_ID', 'CATALOG_GROUP_ID', 'PRICE') + ); + while ($arPricesProduct = $dbPricesProduct->Fetch()) { + foreach ($shops as $shop) { + if (!isset($pricesUpload[$arPricesProduct['PRODUCT_ID'] . '-' . $shop])) { + $pricesUpload[$arPricesProduct['PRODUCT_ID'] . '-' . $shop] = array( + 'externalId' => $arPricesProduct['PRODUCT_ID'], + 'site' => $shop + ); + } + $pricesUpload[$arPricesProduct['PRODUCT_ID'] . '-' . $shop]['prices'][] = array( + 'code' => $prices[$arPricesProduct['CATALOG_GROUP_ID']], + 'price' => $arPricesProduct['PRICE'], + ); + } + } + + //for log + $splitedItems = array_chunk($pricesUpload, 200); + foreach ($splitedItems as $chunk) { + $log->write($chunk, 'storePricesUpload'); + + foreach ($shops as $shop) { + RCrmActions::apiMethod($api, 'storePricesUpload', __METHOD__, $chunk, $shop); + time_nanosleep(0, 250000000); + } + } + + $arNavStatParams['iNumPage'] = $dbResProductsIds->NavPageNomer + 1; + } while($dbResProductsIds->NavPageNomer < $dbResProductsIds->NavPageCount); + } + } else { + RCrmActions::eventLog('RetailCrmPrices::pricesUpload()', '$infoBlocks', 'No iblocks selected'); + + return false; + } + + return 'RetailCrmPrices::pricesUpload();'; + } +} \ No newline at end of file diff --git a/intaro.retailcrm/classes/general/ua/RetailCrmUa.php b/intaro.retailcrm/classes/general/ua/RetailCrmUa.php new file mode 100644 index 00000000..87e88460 --- /dev/null +++ b/intaro.retailcrm/classes/general/ua/RetailCrmUa.php @@ -0,0 +1,69 @@ + + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); + ga('create', '" . $uaKeys[SITE_ID]['ID'] . "', 'auto'); + function getRetailCrmCookie(name) { + var matches = document.cookie.match(new RegExp( + '(?:^|; )' + name + '=([^;]*)' + )); + return matches ? decodeURIComponent(matches[1]) : ''; + } + ga('set', 'dimension" . $uaKeys[SITE_ID]['INDEX'] . "', getRetailCrmCookie('_ga')); + ga('send', 'pageview'); + "; + if (isset($_GET['ORDER_ID'])) { + CModule::IncludeModule("sale"); + $arOrder = CSaleOrder::GetByID($_GET['ORDER_ID']); + $ua .= ""; + + $APPLICATION->AddHeadString($ua); + } + } +} \ No newline at end of file diff --git a/intaro.retailcrm/classes/general/user/RetailCrmUser.php b/intaro.retailcrm/classes/general/user/RetailCrmUser.php index edf45290..a1188d46 100644 --- a/intaro.retailcrm/classes/general/user/RetailCrmUser.php +++ b/intaro.retailcrm/classes/general/user/RetailCrmUser.php @@ -4,7 +4,7 @@ class RetailCrmUser { public static function customerSend($arFields, $api, $contragentType, $send = false, $site = null) { - if (!$api || empty($contragentType)) { // add cond to check $arParams + if (!$api || empty($contragentType)) { return false; } if (empty($arFields)) { @@ -22,13 +22,13 @@ class RetailCrmUser 'createdAt' => new \DateTime($arFields['DATE_REGISTER']), 'contragentType' => $contragentType ); - if (isset($arFields['PERSONAL_PHONE'])) { + if (!empty($arFields['PERSONAL_PHONE'])) { $customer['phones'][]['number'] = $arFields['PERSONAL_PHONE']; } - if (isset($arUser['WORK_PHONE'])) { + if (!empty($arFields['WORK_PHONE'])) { $customer['phones'][]['number'] = $arFields['WORK_PHONE']; } - if (isset($_COOKIE['_rc']) && $_COOKIE['_rc'] != '') { + if ($send && isset($_COOKIE['_rc']) && $_COOKIE['_rc'] != '') { $customer['browserId'] = $_COOKIE['_rc']; } @@ -36,6 +36,10 @@ class RetailCrmUser $newResCustomer = retailCrmBeforeCustomerSend($customer); if (is_array($newResCustomer) && !empty($newResCustomer)) { $customer = $newResCustomer; + } elseif ($newResCustomer === false) { + RCrmActions::eventLog('RetailCrmUser::customerSend', 'retailCrmBeforeCustomerSend()', 'UserID = ' . $arFields['ID'] . '. Sending canceled after retailCrmBeforeCustomerSend'); + + return false; } } @@ -68,15 +72,15 @@ class RetailCrmUser 'email' => $arFields['EMAIL'], 'address' => array('city' => $arFields['PERSONAL_CITY'], 'text' => $arFields['PERSONAL_STREET'], 'index' => $arFields['PERSONAL_ZIP']), ); - if (isset($arFields['PERSONAL_PHONE'])) { + if (!empty($arFields['PERSONAL_PHONE'])) { $customer['phones'][]['number'] = $arFields['PERSONAL_PHONE']; } - if (isset($arFields['WORK_PHONE'])) { + if (!empty($arFields['WORK_PHONE'])) { $customer['phones'][]['number'] = $arFields['WORK_PHONE']; } $found = false; - if (count($optionsSitesList) > 1) { + if (count($optionsSitesList) > 0) { foreach ($optionsSitesList as $site) { $userCrm = RCrmActions::apiMethod($api, 'customersGet', __METHOD__, $arFields['ID'], $site); if (isset($userCrm['customer'])) { @@ -91,7 +95,7 @@ class RetailCrmUser $found = true; } } - + if ($found) { $normalizer = new RestNormalizer(); $customer = $normalizer->normalize($customer, 'customers'); @@ -99,12 +103,17 @@ class RetailCrmUser $log = new Logger(); $log->write($customer, 'customer'); - if (function_exists('retailcrmBeforeCustomerSend')) { - $newResCustomer = intarocrm_before_customer_send($customer); + if (function_exists('retailCrmBeforeCustomerSend')) { + $newResCustomer = retailCrmBeforeCustomerSend($customer); if (is_array($newResCustomer) && !empty($newResCustomer)) { $customer = $newResCustomer; + } elseif ($newResCustomer === false) { + RCrmActions::eventLog('RetailCrmUser::customerEdit', 'retailCrmBeforeCustomerSend()', 'UserID = ' . $arFields['ID'] . '. Sending canceled after retailCrmBeforeCustomerSend'); + + return false; } } + RCrmActions::apiMethod($api, 'customersEdit', __METHOD__, $customer, $site); } diff --git a/intaro.retailcrm/description.ru b/intaro.retailcrm/description.ru index d926d8b7..6d13e466 100644 --- a/intaro.retailcrm/description.ru +++ b/intaro.retailcrm/description.ru @@ -1,6 +1,3 @@ -- Добавлены единицы измерения в экспорте каталога -- Исправлены пути в include -- Добавлено время нового формата в валидатор -- Исправлено неверное изменение типа заказа по истории -- Исправлена ошибка с некорректным разбиением ФИО -- Небольшие исправления по коду \ No newline at end of file +- Добавлена встроенная функция retailCrmApiResult +- Добавлен триггерный вариант истории изменений +- Исправлены ошибки \ No newline at end of file diff --git a/intaro.retailcrm/export/export_setup.php b/intaro.retailcrm/export/export_setup.php index b9ed2f60..f29c68a2 100644 --- a/intaro.retailcrm/export/export_setup.php +++ b/intaro.retailcrm/export/export_setup.php @@ -96,10 +96,7 @@ if (file_exists($_SERVER["DOCUMENT_ROOT"]."/bitrix/php_interface/retailcrm/expor echo ShowError(implode('
', $arSetupErrors)); - if ($STEP==1) - { - - + if ($STEP==1) { ?>
BeginNextTab(); ?> - + @@ -538,9 +803,11 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) { @@ -664,10 +931,7 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) { BeginNextTab(); ?> - - - - + @@ -770,26 +1034,197 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) { BeginNextTab(); ?> - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + 0) :?> + + + + + + + + > + + + + + + > + + + + + + + > + + + + + + + + > + + + + + + > + + + + + + + + > + + + + + + + 0) :?> + + + + + + + + > + + + + + + + + > + + + + + + + > + + + + + + + + > + + + + + + > + + + + + + + + > + + + + + + + + + + + + + + + > + + + + + + > + () + + + + + + + + + + + + + + > + + () + + + > + + + + + + > + + + + + + Buttons(); ?> @@ -920,7 +1355,8 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) { $('input[name="start"]').live('click', function() { BX.showWait(); - + $('#indicator').css('width', 0); + $('#percent2').html('0%'); orderUpload(); return false;