1
0
Fork 0
mirror of synced 2025-04-04 06:13:32 +03:00

Compare commits

...

773 commits

Author SHA1 Message Date
ellynoize
e61259ded9
Исправлена передача габаритов при выгрузке заказов по агенту (#388) 2025-03-26 15:53:37 +03:00
ellynoize
0359315c79
Исправлена передача некорректного статуса оплаты для отмененных заказов (#387) 2025-03-26 15:45:25 +03:00
Kocmonavtik
08ff21ce04
Исправление обновления модуля (#385) 2025-03-05 10:33:10 +03:00
ellynoize
de7ecd4100
Исправлена ошибка экспорта дополнительных свойств товаров (#386) 2025-03-03 12:58:48 +03:00
ellynoize
54692c50d4
Исправлена ошибка установки модуля на PHP 8.0 2025-02-04 09:07:06 +03:00
ellynoize
61044988d5
Передача нулевой закупочной стоимости в экспорте каталога (#382) 2025-01-30 09:20:26 +03:00
ellynoize
7a36fa5de7
Исправлена ошибка редактирования интеграционных доставок (#381) 2025-01-28 11:47:01 +03:00
ellynoize
8cf4420592
Исправлено некорректное удаление признака применения промокода (#380) 2025-01-28 10:45:49 +03:00
Kocmonavtik
84c7d10146
Исправлены ошибки при обновлении модуля (#379) 2025-01-15 10:24:03 +03:00
ellynoize
8c38d21477
Исправлена выгрузка архива заказов при установке модуля (#378) 2025-01-14 15:05:46 +03:00
Kocmonavtik
115cf33423
Исправление API методов по работе с пользовательскими полями (#377) 2024-12-17 15:11:37 +03:00
Kocmonavtik
3162031b65
Динамическое добавление свойств в ICML (#375) 2024-12-10 14:33:00 +03:00
Aleksei Novikov
1ec3bccd0c
Исправлена поломка заказов с промокодом Maxma при включенной передаче корзины в CRM (#376) 2024-12-09 12:48:35 +03:00
ellynoize
41257b9d7c
Исправлена выгрузка заказов через агент (#372) 2024-11-05 12:42:39 +03:00
Kocmonavtik
b68779a054
Исправлена подписка модуля на событие сохранения заказа (#371) 2024-11-05 09:24:39 +03:00
ellynoize
d25c7fc484
Передача профилей модуля Почты России (#370) 2024-10-28 11:21:46 +03:00
ellynoize
317a30b682
Бамп версии модуля (#369) 2024-10-24 10:33:08 +03:00
ellynoize
534757e6c6
Исправлена подписка на событие сохранения заказа (#368) 2024-10-23 17:05:39 +03:00
ellynoize
7e260a2d22
Исправлена ошибка агента выгрузки изменений при наличии у заказа клиента без магазина (#367) 2024-10-22 09:42:58 +03:00
ellynoize
6fb061e6cc
Добавлена передача дополнительных параметров в GET запросах (#366) 2024-10-14 16:59:41 +03:00
ellynoize
a77b29cd49
Исправлена подписка на событие при обновлении (#365) 2024-10-03 12:46:41 +03:00
ellynoize
c1deb9e91e
Добавлено логирование ответа от API при неудачном создании заказа (#364) 2024-09-24 14:12:33 +03:00
ellynoize
1d2a87f277
Добавление передачи контрагентов с типом ИП (#363) 2024-09-23 13:21:59 +03:00
ellynoize
74833ed2db
Перенос подписки на событие сохрания заказа в установку модуля (#362) 2024-09-23 09:46:10 +03:00
alexxmoree
8eab4864c5
Исправление возврата статуса заказа на предыдущий (#361) 2024-09-11 12:41:17 +03:00
Rinacoder
169509c263
Исправлена передача изменений по клиентам, отсутствующим в Bitrix (#360) 2024-09-06 15:10:19 +03:00
Kocmonavtik
1b64044013
Исправлено удаление модуля (#359) 2024-09-02 09:12:05 +03:00
Uryvskiy Dima
a83ff3cc6b
Улучшена генерация каталога с маркированными товарами (#357) 2024-08-12 11:58:24 +03:00
Kocmonavtik
6a6a4545b8
Добавление переводов для программы лояльности (#356) 2024-08-08 09:47:15 +03:00
Uryvskiy Dima
10745c4c8d
Исправлена ошибка с присвоением externalId при добавлении товара в заказ как разные товарные позиции из CRM (#355) 2024-08-06 11:17:14 +03:00
Kocmonavtik
ebb32869aa
Добавлена передача скидок на торговые позиции в брошенных корзинах (#353) 2024-07-18 14:14:36 +03:00
Uryvskiy Dima
3e3e37b297
Добавлена передача поля link при выгрузке брошенных корзин (#352) 2024-07-15 17:24:27 +03:00
Kocmonavtik
1ab3dacaf7
ref #93680 Рефакторинг настроек и установки модуля, добавление переводов в настройках модуля (#351) 2024-06-21 11:37:07 +03:00
roadmoore
0550d8ffba
Исправление работы программы лояльности при использования опции "Подтверждение списания по смс" (#350) 2024-06-18 09:21:06 +03:00
Kocmonavtik
51f8c98010
ref #95555 Добавлена возможность исправления даты регистрации клиентов в системе (#349) 2024-06-06 18:17:43 +03:00
Uryvskiy Dima
ee6d654d8c
ref #73933 Добавлена передача признака маркировки товара в ICML каталоге (#348) 2024-06-04 12:05:51 +03:00
Kocmonavtik
453bc495c0
ref #88907 Доработка аннотаций в модуле (#346) 2024-04-29 11:44:31 +03:00
Kocmonavtik
1eabbe323b
ref #95225 Добавлена передача услуг через ICML каталог (#345) 2024-04-24 09:48:51 +03:00
Xyslik
c1f59ead7f
#95443 Исправляем работу кнопки "Выгрузка служб доставок" (#344) 2024-04-22 09:24:27 +03:00
Kocmonavtik
cbddd69001
Исправление присваивания номера заказа к платежу при синхронизации с CRM (#343) 2024-04-03 10:59:10 +03:00
Kocmonavtik
7f69ebfa1f
ref #93089 Исправлена ошибка подстановки домена при генерации каталога (#342) 2024-04-01 09:34:11 +03:00
Kocmonavtik
830fe34e3e
ref #94529 Исправление ошибки дублирования скидок (#341) 2024-04-01 09:04:43 +03:00
Kocmonavtik
85749c8602
Обновление версии модуля (#340) 2024-03-18 14:25:20 +03:00
Kocmonavtik
d298cffb22
ref# 94173 Доработка вывода ошибок при установке и настройке модуля. (#339) 2024-03-18 14:00:13 +03:00
Kocmonavtik
50997b729f
Исправление проверки ФИО при отправке заказа в систему (#338) 2024-03-01 14:04:26 +03:00
Kocmonavtik
4f07b9a16b
ref #94088 (#336) 2024-02-05 10:53:22 +03:00
Kocmonavtik
ad04daa904
ref #92904 Передача данных интегрированных оплат (#335) 2024-01-24 15:01:13 +03:00
Kocmonavtik
b8ac495a37
ref #93387 Экспорт дополнительных свойств товаров через конфигурируемый файл (#334) 2024-01-18 11:48:35 +03:00
Kocmonavtik
d9cdfced49
ref #92570 Исправление вывода справочников при установке модуля (#333) 2024-01-15 12:27:40 +03:00
Kocmonavtik
a66ec1d663
ref #93511 Исправление передачи адреса доставки (#332) 2024-01-09 10:44:17 +03:00
MichaelTkach94
46570494a3
Исправлен баг с двойной сериализацией при получении списка пользователей (#331) 2023-12-28 11:35:36 +03:00
Uryvskiy Dima
62b165f5de
ref #93164 Не выгружать на сайт 1C-Bitrix заказы с определенным способом оформления (#330) 2023-12-21 17:24:46 +03:00
Kocmonavtik
3d3326018a
ref #92774 Исправлено отображение настройки пользовательских полей (#329) 2023-12-21 15:09:31 +03:00
Kocmonavtik
6d479ae441
ref #92774 Поддержка пользовательских полей (#323) 2023-12-19 17:13:31 +03:00
Uryvskiy Dima
e918317f6a
ref #93307 Исправлена ошибка с получением данных программы лояльности администратора при изменении заказа в админке (#327) 2023-12-13 17:22:33 +03:00
Uryvskiy Dima
992162c01e
ref #93434 Исправлена критическая ошибка при переходе в настройки модуля (#326) 2023-12-12 16:51:15 +03:00
Uryvskiy Dima
d47852dc31
Добавил описание изменений для релиза (#325) 2023-12-08 17:10:13 +03:00
Uryvskiy Dima
18a10bf916
Исправлена ошибка при передаче подписки на рекламно-информационные рассылки (#324) 2023-12-08 12:27:10 +03:00
Kocmonavtik
748ebdf4a3
ref #92358 Передача трек номера из системы (#321) 2023-10-26 14:36:22 +03:00
Uryvskiy Dima
693031012d
ref #91901 Исправлена ошибка при деактивации модуля (#319) 2023-10-24 12:53:02 +03:00
Uryvskiy Dima
a0005e1ff8
ref #92177 Добавлена передача адреса пункта самовывоза в заказе из Bitrix в CRM (#317) 2023-10-18 16:16:35 +03:00
Uryvskiy Dima
7b7371e37f
ref #92205 Добавил описание изменений для релиза 2023-10-16 10:15:44 +03:00
Uryvskiy Dima
7404105dec
ref #92205 Изменена логика передачи адреса доставки в заказе из Bitrix в CRM (#315) 2023-10-13 12:49:09 +03:00
Kocmonavtik
8db6531fc8
ref #91633 обработка ФИО покупателя в заказе (#314) 2023-09-11 09:51:36 +03:00
Kocmonavtik
b9030b94ac
ref #90954 Удаление поддержки API V4 (#312) 2023-09-01 14:06:23 +03:00
Uryvskiy Dima
0a6c409e11
ref #91505 Исправлены ошибки при работе с программой лояльности (#313) 2023-09-01 10:10:38 +03:00
Kocmonavtik
4f438b6f0f
ref #91590 Добавление проверок валюты в CMS при мультивалютности CRM (#311) 2023-08-30 14:11:04 +03:00
Kocmonavtik
8ce4f5d6c6
ref #89535 Исправлено очищение корзины для корпоративных клиентов (#310) 2023-08-29 17:40:10 +03:00
Kocmonavtik
e003b63f2f
ref #91532 Исправление передачи даты регистрации клиента (#309) 2023-08-25 11:27:22 +03:00
Kocmonavtik
25b4a17e40
ref #91040 Добавить возможность создания клиентов с признаком "Подписан" (#303) 2023-08-22 13:09:20 +03:00
Kocmonavtik
9b3bfaf3ff
Добавлена документация по кастомизированию классов. (#308) 2023-08-11 16:11:49 +03:00
Uryvskiy Dima
7008ac92f0
ref #91243 Исправлена ошибка некорректного вывода информации о программе лояльности в личном кабинете клиента (#307) 2023-07-25 13:11:29 +03:00
Kocmonavtik
8832287cdd
ref #89546 Добавлена возможность кастомизации генерации каталога (#306) 2023-07-24 09:10:28 +03:00
Kocmonavtik
56ab4b43de
ref #90908 Исправление передачи брошенных корзин (#305) 2023-07-20 15:02:29 +03:00
Uryvskiy Dima
7c667112d5
ref #90482 Добавлен функционал передачи примененного купона в заказе Битрикс в пользовательское поле заказа CRM (#302) 2023-07-05 10:34:37 +03:00
Uryvskiy Dima
c7cec20c02
ref #77474 Добавлена передача НДС товаров (#301) 2023-07-03 10:05:52 +03:00
Kocmonavtik
17e3b00dd7
ref #90439 Обработка исключений агента orderAgent (#300) 2023-06-22 15:46:25 +03:00
Uryvskiy Dima
7a2ab16cf3
ref #89248 Исправлена ошибка при изменении торгового предложения в товаре (#299) 2023-06-12 20:16:23 +03:00
Smiley48
ce5ea1f1a5
Правка генерации каталога при работе со значением Без НДС (#297) 2023-06-12 17:49:53 +03:00
Kocmonavtik
f44cf792b2
ref #89494 Исправление ошибок при обновлении модуля и переходе на php 8 версии (#298) 2023-06-09 13:34:02 +03:00
Kocmonavtik
57419cadc6
ref #89521 Исправление ошибки при изменении настроек модуля (#296) 2023-06-08 09:33:56 +03:00
Kocmonavtik
555d7e2513
ref #90085 Проверка на доступность типа оплат и доставок для текущего магазина для настройки модуля (#295) 2023-06-07 14:39:34 +03:00
Uryvskiy Dima
de7a2bc1de
ref #89446 Исправление ошибок генерации ICML каталога при установке модуля (#294) 2023-06-01 13:33:41 +03:00
Smiley48
595d713931
Исправление ошибки при получении НДС (#293) 2023-06-01 12:29:25 +03:00
Dmitriy
bc31ffa50c
Исправлено получение основного сайта (#290) 2023-06-01 12:17:12 +03:00
Uryvskiy Dima
83c7a3305b
ref #78215 Управление активностью интеграции через интерфейс модуля (#291) 2023-05-29 14:26:39 +03:00
Kocmonavtik
cbf8c9ac17
ref #76758 Разрашено обновления номера телефона, адреса и других полей заказа, связанных с курьерской доставкой (#292) 2023-05-29 14:13:05 +03:00
Uryvskiy Dima
c67eb37124
ref #89486 Оптимизирован алгоритм получения истории заказов и клиентов (#289) 2023-04-26 17:18:38 +03:00
Uryvskiy Dima
198d8b2e9e
Добавлена поддержка PHP 8.1-8.2 2023-04-17 12:50:04 +03:00
Kocmonavtik
0ca2527c5f
ref #85233 Добавление в генерацию каталога свойства активности товара (#286) 2023-04-13 13:50:18 +03:00
Kocmonavtik
be1447c6ec
ref #89247 Добавление валидации на тип свойства в экспорте каталога (#285) 2023-04-11 12:20:53 +03:00
Kocmonavtik
cf6729cbdc
Добавление предачи информации о корзинах в систему (#284) 2023-04-11 11:57:06 +03:00
Kocmonavtik
9c5ce1e53b
ref #86982 предотвращение создания дублей пользователей по истории (#282) 2023-03-31 11:44:26 +03:00
Uryvskiy Dima
b8aab91880
ref #88500 Исправление ошибок при установке модуля и выгрузке истории заказов (#283) 2023-03-31 11:29:58 +03:00
Kocmonavtik
b4f4aaa023
ref #88945 улучшение настроек модуля (#281)
* Автоматическое соотношение контрагентов по умолчанию, фильтр активности значений
* Добавлен фильтр активных складов и типов цен
2023-03-29 10:39:52 +03:00
Uryvskiy Dima
c7aad78e5f
ref #87970 Передача менеджера при изменени заказа по истории (#280) 2023-03-28 18:12:03 +03:00
Uryvskiy Dima
2e6b105d8d
Добавлена поддержка PHP 8.0 (#279) 2023-03-15 11:55:04 +03:00
Kocmonavtik
6cd01dd572
ref #87785 Добавление передачи сайта для корпоративных клиентов (#277) 2023-03-02 16:20:57 +03:00
Uryvskiy Dima
4c61df9701
Add manager filter (#276) 2023-01-26 13:49:36 +03:00
Kocmonavtik
6a07f5220b
Исправление отправки заказа в црм систему (#275) 2023-01-24 15:54:48 +03:00
Smiley48
656c076195
Блокировка резервирования в отгруженном заказе 2023-01-23 14:27:15 +03:00
Kocmonavtik
3267e72b7c
ref #74694 Changing loyalty program update in admin panel
* Removing unnecessary elements, fixing a broken method, adding code to OrderHistory
* Changing the verification to update the properties of the loyalty program order
2023-01-16 11:05:29 +03:00
Kocmonavtik
be5d7ba33e
ref #87457 generate password corporate client and checking emptines user in order (#271) 2023-01-09 12:18:37 +03:00
Kocmonavtik
e046a1d6f1
Filtering inactive statuses and data books for mapping (#270) 2022-12-13 16:11:00 +03:00
Kocmonavtik
ccdc6f489e
Removing outdated functionality (Configuration management cron) (#269) 2022-12-07 11:23:57 +03:00
Kocmonavtik
6f5cd18a07
fix reg empty client email, sending a comment the order status 2022-12-05 16:32:28 +03:00
Alex Lushpai
6322f25c36
Fix canceling orders in bitrix 2022-12-05 14:46:22 +03:00
KMityai
f7a5a39e1b updated description.ru 2022-12-02 13:34:09 +03:00
KMityai
26639fd5d6 bump to 6.1.8 2022-11-22 10:41:35 +03:00
KMityai
37b94086fe fix order canceling 2022-09-30 13:05:58 +03:00
Alex Lushpai
d4204b71d6
Корректировка получения истории удалённых товаров 2022-09-12 11:13:17 +03:00
Mozgito
526f55bd3b fix product delete from HL 2022-09-09 14:41:23 +03:00
Vlad
61177b712d
Корректировка логики создания/редактирования клиента в Bitrix 2022-09-07 10:35:40 +03:00
Alex Lushpai
f14a087b16
Корректировка получения НДС товаров в каталоге 2022-08-22 11:14:10 +03:00
Mozgito
a012f48a20 Корректировка получения НДС товаров в каталоге 2022-08-22 10:26:21 +03:00
Vlad
f87c07e2e1
Исправление ошибки при записи товаров в HL блок лояльности (#263) 2022-07-21 14:11:52 +03:00
Smiley48
19fbf04f60
Fix existing customer in loyalty (#262) 2022-07-20 12:46:32 +03:00
Vlad
d52974c7d1
Исправление передачи корпоративных клиентов (#260) 2022-07-01 15:47:59 +03:00
Alex Lushpai
5c6ac38b12
Исправление ошибки удаления модуля 2022-06-29 10:16:13 +03:00
Mozgito
9b8f5282b7 Исправление ошибки удаления модуля 2022-06-28 17:35:54 +03:00
Vlad
96e5bce336
Исправление работы со скидками (#258) 2022-06-28 15:28:28 +03:00
Vlad
9b1e641b16
Замена устаревшего jQuery метода 2022-06-17 11:49:38 +03:00
Vlad
af7982f790
Исправление автозагрузки классов для мультисайта (#256)
* Исправление автозагрузки классов для мультисайта
* Лишний параметр в методе создания заказа
2022-06-14 14:08:43 +03:00
Smiley48
9cf274ec66
Setup fix (#254) 2022-06-14 12:00:14 +03:00
Vlad
60e818e793
Исправление передачи местоположения в адресе доставки по истории (#253)
* Корректировка передачи местоположения в адресе доставки по истории
2022-06-14 11:57:44 +03:00
Vlad
134c92199a
Исправление автозагрузки классов (#252) 2022-05-13 15:52:21 +03:00
Alex Lushpai
6e792412de
Empty product properties fix 2022-05-13 13:44:03 +03:00
Mozgito
a8d99c2a08 empty product properties fix 2022-05-05 10:20:15 +03:00
Alex Lushpai
dfad5edffb update to 6.0.2 2022-04-18 16:49:59 +03:00
Alex Lushpai
243ec1ee99 Добавлена передача параметра site для методоа получения списка заказов 2022-04-18 16:43:52 +03:00
Alex Lushpai
38e6ce092a
Передача параметра site для метода работы с корпоративными клиентами 2022-04-18 16:38:14 +03:00
Alex Lushpai
56f6e54dcc
Исправление редактирования свойств заказа в 1С Битрикс 2022-04-18 16:21:02 +03:00
Alex Lushpai
bec3ede2f5
Исправление конвертирования строк из utf-8 2022-04-18 16:20:03 +03:00
KMityai
bbdf690bb3 fix editing propertys in bitrix orders 2022-04-13 17:07:58 +03:00
KMityai
976d5511fc fix converting strings from utf-8 2022-04-13 16:59:27 +03:00
KMityai
e8aedb39be site rewrite fixed 2022-04-13 16:54:59 +03:00
Vlad
559bf79f7b
Fix customized classes load (#245)
* fix customized classes load
* bump to 6.0.1
2022-04-08 18:21:05 +03:00
Сергей Чазов
34e8105583
Loyalty (#241)
* Loyalty program
* fix dot bug for shops-exoprt option
* delete credantials request from services
* add CurlException for credentials catch
* add catching CurlException
* edit error msgs
* add supportind double bonuses
* add any step for bonus-input field in sale.order.ajax template
* recalculate bonuses
* fix bonus rounded
* strtoupper for params in icml
* change delivery service code
2022-03-02 15:40:53 +03:00
Alex Lushpai
e3e0d41ff5
Backport (#242)
* Add PRICE_DELIVERY for history exchange
* Fix bug with LocationTable fqn
* Fix bug with ProductType
* Changed options for prices and corps
* CustomersUpload: finding uniq clients by externalId
* Restore shipment before deleting

Co-authored-by: Sergey Chazov <oitv18@gmail.com>
2022-02-04 15:16:14 +03:00
Alex Lushpai
a1d6e00d18
5.8.4 2021-11-15 11:59:46 +03:00
c391379515 bump to 5.8.4 2021-11-15 11:21:09 +03:00
Vlad
1d814d69bc
fix catalog re-generation (#225) 2021-11-12 17:11:52 +03:00
64ac89d1d3
Fix icml generator path (#223) 2021-11-12 13:53:40 +03:00
Сергей Чазов
2b20702e58
Bump to 5.8.2 2021-11-02 15:43:20 +03:00
Сергей Чазов
3e5a04af62
Catalog fix
* add empty array Instead of  and add xml-header with charsets
* fix catalog purchasePrice
* use file_put_contents for flush
2021-11-02 11:25:26 +03:00
Vlad
380e1f0081
Fix catalog purchasePrice 2021-11-02 11:23:42 +03:00
Сергей Чазов
c3216f72d3
Optimize generator (#215) 2021-09-08 16:31:17 +03:00
Сергей Чазов
d06cb3c6e6
Remove date for integration payment (#214) 2021-09-08 13:00:50 +03:00
Сергей Чазов
9354bca0b3
multisite order export bug (#208) 2021-09-08 10:19:29 +03:00
Сергей Чазов
30ef0ebf8a
ICML simple product props (#207) 2021-09-08 10:05:09 +03:00
Alex Lushpai
a3c5cc9632
Merge pull request #213 from Neur0toxine/bump-version
bump version
2021-08-19 16:03:56 +03:00
e519a933f0 bump version 2021-08-19 15:59:07 +03:00
Сергей Чазов
8458360a30
Service for manager sync
* added service for manager sync
* added manager event handler in history uploading methods
* deleted logger dependence from repository
* extract config provider proxy methods from repository to service
2021-08-19 15:46:03 +03:00
Alex Lushpai
c731fae369
Inventories upload fix 2021-08-16 10:16:00 +03:00
vasilevdm
876e255be8 Inventories upload fix 2021-08-14 12:18:03 +03:00
Сергей Чазов
3676808046
Corp uploading fix (#210) 2021-07-08 16:29:34 +03:00
Сергей Чазов
3967130660
Fix return type in getIntegrationPaymentTypes method (#209) 2021-06-28 17:36:10 +03:00
Сергей Чазов
a4c06ed8ee
New ICML generator 2021-05-31 16:33:02 +03:00
Сергей Чазов
c37b05c6d2
fix custom prices (#204) 2021-05-31 11:14:02 +03:00
RenCurs
4f2bc1a1b1
Remove status from integration payment (#192) 2021-04-19 15:38:09 +03:00
Alex Lushpai
e422557514
Replace CustomerBuilder 2021-04-16 15:12:27 +03:00
Sergey Chazov
c40e049485 deleted bump version 2021-04-16 13:52:52 +03:00
Sergey Chazov
176278ece4 deleted params types in CustomerAddresses 2021-04-06 16:23:38 +03:00
Sergey Chazov
de2b68c349 deleted return types in setters CustomerBuilder class 2021-04-05 14:57:04 +03:00
Alex Lushpai
554a182d66
fixed fqn for EventActions class 2021-04-05 14:13:31 +03:00
Sergey Chazov
8e444e0880 deleted return types in setters CustomerBuilder class 2021-04-05 13:40:53 +03:00
Alex Lushpai
6fd52027df
Check existence of order with UA 2021-04-02 11:59:32 +03:00
RenCurs
06ccfd9add
Create customer without contact (#189) 2021-04-02 11:58:44 +03:00
Сергей Чазов
f842142791
Check products array for emptiness (#193) 2021-04-01 15:09:16 +03:00
Ruslan Efanov
b2b637f016 fixed fqn for EventActions 2021-03-25 16:34:02 +03:00
Ruslan Efanov
422c0fa787 change check existence of order with UA 2021-03-24 13:42:15 +03:00
Sergey Chazov
2689836c65 add reset in customer bulder and bump version 2021-03-23 14:39:19 +03:00
Sergey Chazov
cec1dafd36 replace CustomerBuilder 2021-03-23 12:29:02 +03:00
Alex Lushpai
1d2a9dca82
CDN correct url in icml 2021-01-15 14:45:40 +03:00
Alex Lushpai
26bc64f5e1
fix wiping 'fio' field if it is doesn`t present in history 2021-01-14 17:24:12 +03:00
vasilevdm
72c53b8bd4 added check to fix wiping 'fio' field if it is doesn`t present in history 2021-01-14 16:38:56 +03:00
gorokh
2c161d3d26 CDN correct url in icml 2021-01-14 16:19:31 +03:00
Alex Lushpai
185434f531
Убрана некорректная запись внешнего идентификатора платежа для новых платежей по истории
fixed #168
2021-01-14 13:46:13 +03:00
gorokh
12ae53cfea fixed #168 2021-01-13 17:51:36 +03:00
RenCurs
797a4d41de
Check email field length (#163) 2020-12-22 13:03:32 +03:00
Akolzin Dmitry
4a5c5d6fd2
Update document links (#166) 2020-12-15 13:51:13 +03:00
Akolzin Dmitry
ae16e5b0f0
Rebranding (#164) 2020-12-15 12:39:38 +03:00
9822ba1c23
fix for country names (#161) 2020-12-08 17:01:26 +03:00
RenCurs
559ff1d8f7
OnlineConsultant (#154) 2020-11-24 12:14:26 +03:00
Evgeniy-Goroh
b34da9a756
english translation (#159) 2020-11-23 17:54:39 +03:00
0fa7c8d819
Fix comparison before building release (#160) 2020-11-23 17:02:44 +03:00
Alex Lushpai
83534eaf0f
Update README.md 2020-11-23 15:45:30 +03:00
e705ba456a
Move CI to GitHub Actions (#158) 2020-11-23 15:38:53 +03:00
Yura
460b254a13
fix #152 Проверка данных ФИО при заполнении поля в истории (#153) 2020-11-11 14:46:27 +03:00
Evgeniy-Goroh
4f5ae21915
add country (#155) 2020-11-11 11:30:07 +03:00
Alex Lushpai
f0a7350ae5
Country list update 2020-10-21 22:01:10 +03:00
gorokh
c1cef99627 counttry fixed 2020-10-21 13:20:09 +03:00
Alex Lushpai
4c2c80e324
orderCreate fix 2020-10-15 16:02:26 +03:00
gorokh
7d806a5fea fixed on create orders agent unset fields 2020-10-15 15:49:14 +03:00
Alex Lushpai
4ba328ac7b
Fix for bad encoding in the module settings 2020-10-01 16:58:42 +03:00
f123652591 fix for bad encoding in the module settings 2020-10-01 16:15:44 +03:00
Alex Lushpai
a0897cdefb
Fix updater crash 2020-09-29 16:46:44 +03:00
42f05ea7d8 fix updater crash 2020-09-29 15:47:16 +03:00
Alex Lushpai
da6074da36
bump version (#142)
* Ability to disable payment passthrough
* Fix unseting delivery fields method
2020-09-29 13:03:47 +03:00
Sergey Chazov
80066dc6d7 add descripteion for version bump2 2020-09-28 16:35:06 +03:00
Sergey Chazov
365720fc0f add descripteion for version bump 2020-09-28 16:32:40 +03:00
Sergey Chazov
2355f3dd6a bump version 2020-09-28 13:48:07 +03:00
Сергей Чазов
ec8f5ac661
fix unseting delivery fields method (#141) 2020-09-28 13:02:03 +03:00
Evgeniy-Goroh
82d6c10c07
Manual order upload (#137) 2020-09-25 12:31:45 +03:00
4125565570
Ability to disable payment passthrough (#140)
* optional payment total in the order
* updater won't fail in case of error
2020-09-25 12:17:29 +03:00
Evgeniy-Goroh
cf8a8eb0ab
Fixed module installation upload (#136) 2020-09-11 15:06:37 +03:00
vasilevdm
c39f0eb888
fix order save when corporate isn`t enabled and CRM_CC is undefined (#135) 2020-09-08 14:31:42 +03:00
d64dd971d3
Fixed module installation error when there are no orders 2020-09-02 15:33:02 +03:00
vasilevdm
b19c857cc3
fix error during installation when orders count equals zero (#130) 2020-09-02 14:37:16 +03:00
5d49d16955
Payment status fix 2020-09-02 11:00:12 +03:00
Сергей Чазов
235ebd051f
change method for add PAYED status (#127) 2020-08-28 13:04:26 +03:00
ecb845546d
fix order upload error during installation (#125) 2020-08-26 11:21:56 +03:00
346a0ea5fe
Bump version (#124) 2020-08-25 12:37:59 +03:00
Сергей Чазов
eff355041f
Add history filter (#122) 2020-08-25 11:14:47 +03:00
DanielWeiser
458febab46
Remove cyrillic symbols (#123) 2020-08-25 10:30:16 +03:00
Evgeniy-Goroh
745d1afd5a
корректное добавление id товара при редактировании заказа (#120) 2020-08-18 15:33:54 +03:00
Akolzin Dmitry
17df3a2b22
Fix release build 2020-08-18 11:34:09 +03:00
1451d0c230
ICML optimizations 2020-07-24 14:02:29 +03:00
DanielWeiser
2bc97c84ff
Payment and shipment status 2020-07-23 16:28:36 +03:00
DanielWeiser
ad73c0c1dc
Phone required 2020-07-23 14:49:55 +03:00
DanielWeiser
a43881166b
Unset integration delivery fields on orders edit method 2020-07-22 15:11:27 +03:00
09f82bcfdf
Customer change
* remove useless request for history
* append new address to corporate customer
* centralized configuration provider
* use companyName filter in event & pass companyName into order
* add AdressBuilder* fixed for regressions
* fixed double contact problem
2020-07-14 13:47:26 +03:00
Evgeniy-Goroh
d0252f4ef2
fix encoding in icml (#109)
Co-authored-by: gorokh <gorokh@retailcrm.ru>
2020-06-02 12:55:44 +03:00
Akolzin Dmitry
50caf0240f
exit for encoding error (#107) 2020-05-18 11:53:03 +03:00
Akolzin Dmitry
5521b7fd82
Encoding fixes 2020-05-04 14:56:20 +03:00
Evgeniy-Goroh
5f7f234dd9
fix rewriting item 2020-04-30 11:56:43 +03:00
Akolzin Dmitry
1cee1ff6af
Fixes for vat rate 2020-04-29 17:47:25 +03:00
Alex Lushpai
672598a228
Update version.php 2020-04-28 14:23:17 +03:00
Alex Lushpai
d89461b366
Update description.ru 2020-04-28 14:22:44 +03:00
aee9926dfb
Correct ICML parameters names for offers 2020-04-28 14:16:12 +03:00
acaaf98c56
Corporate client support 2020-04-24 13:18:18 +03:00
Alex Lushpai
bbfb2f600a
v5.2.6 release
* Улучшена работа со скидками
* Добавлен сброс закупочной цены в icml при её отсутствии
2020-04-15 17:32:26 +03:00
Alex Lushpai
9a3ce0fc29 v5.2.6 2020-04-15 17:27:40 +03:00
Alex Lushpai
0fec821438
Cброс закупочной цены в icml при её отсутствии 2020-04-15 17:22:03 +03:00
gorokh
735b0f977d logic fix 2020-04-15 16:01:21 +03:00
gorokh
30555f8146 add options purchasePrice 2020-04-08 17:27:05 +03:00
gorokh
fa207afd15 issues #92 2020-04-07 13:55:59 +03:00
Akolzin Dmitry
d14a078804
Update deployment (#97)
* fix deploy stage
2020-03-24 11:36:32 +03:00
Alex Lushpai
6713bc9245
Update README.md 2020-03-23 15:18:11 +03:00
Akolzin Dmitry
86a51c8401
Update CI build (#96)
* cli Bitrix installation
* update travis config
* update installer
2020-03-23 15:12:07 +03:00
Alex Lushpai
bc64f8e1bd
Merge pull request #95 from Evgeniy-Goroh/fix_discount
поправлена передача скидки
2020-02-20 15:07:06 +03:00
Evgeniy-Goroh
7630dedc84
Merge pull request #1 from Neur0toxine/fix_discount
fix discounts for multiple positions & annotations
2020-02-19 14:59:03 +03:00
0e67c1d93d don't write in DISCOUNT_PRICE 2020-02-19 14:57:03 +03:00
d47709ba87 fix discounts for multiple positions & annotations 2020-02-19 14:35:56 +03:00
gorokh
594feae948 fix discount 2020-02-18 10:54:42 +03:00
gorokh
686548ab63 поправлена передача скидки 2020-02-12 12:25:39 +03:00
Alex Lushpai
0c3fd7e491
Merge pull request #93 from Evgeniy-Goroh/add_externalIds
передача externalIds у позиций товаров в заказе
2020-01-09 13:12:52 +03:00
gorokh
331e76e28a fix version 2020-01-09 12:22:08 +03:00
gorokh
ae0ebc55b4 fix 2020-01-09 11:55:04 +03:00
gorokh
0085f1af2c передача externalIds у позиций товаров в заказе 2020-01-09 11:55:04 +03:00
Alex Lushpai
d183a3350f
Merge pull request #94 from Evgeniy-Goroh/add_field
Добавлено разделение поля строение/корпус на два отдельных
2020-01-09 11:32:53 +03:00
gorokh
1a8340e0e4 Добавлено разделение поля строение/корпус на два отдельных 2020-01-09 11:21:35 +03:00
Alex Lushpai
d475c95a01
Merge pull request #91 from Evgeniy-Goroh/order_history
обработка номера заказа по истории
2019-12-20 14:34:45 +03:00
gorokh
a1bce2bda0 fix conflicts 2019-12-20 14:22:53 +03:00
Alex Lushpai
0956021d8c
Merge pull request #90 from Evgeniy-Goroh/dublicate-item
обработка дублирующих товаров по externalId
2019-12-20 13:57:45 +03:00
gorokh
af3720f80d fix 2019-12-20 13:53:46 +03:00
gorokh
37c347276c fix version 2019-12-20 13:49:32 +03:00
gorokh
c4109cf1c6 обработка дублирующих товаров по externalId 2019-12-11 11:08:50 +03:00
Ilyas Salikhov
0ca164a825
Merge pull request #88 from Evgeniy-Goroh/master
добавлена обработка пустых полей
2019-11-20 16:47:17 +03:00
gorokh
00e6f1716e добавлена обработка пустых полей 2019-11-14 18:06:23 +03:00
Ilyas Salikhov
202e0ffd17
Merge pull request #87 from Evgeniy-Goroh/master
Исправлены мелкие ошибки и недочеты
2019-11-14 17:06:38 +03:00
gorokh
b6828440f7 добавлена обработка пустого адреса 2019-11-14 13:49:24 +03:00
gorokh
027e3571a5 add changelog and version 2019-11-01 14:36:29 +03:00
gorokh
17c853144c issues #84 добавлена обработка для contragent 2019-11-01 14:22:23 +03:00
gorokh
b81cd1ccc4 добавлены customFileds при обработке истории в customer 2019-11-01 13:49:02 +03:00
gorokh
f0aeabe505 issues #78 в событии retailCrmAfterOrderSave добавлен externalId заказа 2019-11-01 13:33:07 +03:00
gorokh
bdc764e492 issues #81 добавлена проверка на id оплаты 2019-11-01 12:15:54 +03:00
gorokh
46c50034f3 issues #75 запись в лог перед отправкой в црм 2019-11-01 12:00:54 +03:00
Alex Lushpai
a0db53017c
Merge pull request #83 from Evgeniy-Goroh/master
Поддержка одинаковых позицый товаров в CRM
2019-10-17 13:02:39 +03:00
gorokh
27a4e558fb fix 2019-10-17 12:32:59 +03:00
gorokh
b98c6ba9ea Поддержка функции добавления одинакового товара в заказ как разные товарные позиции из CRM 2019-10-17 12:26:04 +03:00
Alex Lushpai
defebe6439
Merge pull request #86 from Frosin/master
fixed service bug
2019-10-17 11:41:01 +03:00
Frosin
80e9a279f1 fixed service bug 2019-10-08 16:23:18 +03:00
Alex Lushpai
58b2348ce3
Merge pull request #82 from Frosin/master
Добавлены обработки ошибок при сохранении платежей.
2019-10-03 15:52:05 +03:00
Alex Lushpai
da0f976f1f
Merge pull request #85 from KMityai/master
fixed getting product price from order basket
2019-10-03 15:45:03 +03:00
Дмитрий
3ea5e69e81 fixed getting product price from order basket 2019-10-03 11:29:46 +03:00
Frosin
6fb591c39b fixed RetailCrmHistory_v5 2019-09-10 13:29:23 +03:00
Frosin
36bed88ef3 fixed RetailCrmHistory_v5 2019-09-10 13:23:51 +03:00
Alex Lushpai
d06567ce7f
Merge pull request #80 from Frosin/master
fixed register new user
2019-09-06 15:40:18 +03:00
Frosin
7fe717b76a fixed register new user 2019-08-30 17:20:39 +03:00
Alex Lushpai
88ad72354e
Merge pull request #79 from sergeygw1990/master
Исправление генерации единиц измерения
2019-08-29 13:58:45 +03:00
Sergey
f26e36052f исправление генерации единиц измерения 2019-08-28 15:34:33 +03:00
Alex Lushpai
a56965dcba
Merge pull request #74 from Frosin/master
Fixed duplicate creation bug
2019-08-14 22:03:29 +03:00
Frosin
e706ae7d25 Fixed duplicate creation bug 2019-07-30 09:58:15 +03:00
Alex Lushpai
93315c7a5b
Merge pull request #72 from Evgeniy-Goroh/master
fix order double create
2019-07-29 10:45:17 +03:00
gorokh
83121c4518 fix order double create 2019-07-26 17:44:37 +03:00
Alex Lushpai
f8d7c03ac1
Merge pull request #71 from Evgeniy-Goroh/master
fix changelog
2019-07-18 12:57:27 +03:00
gorokh
d5d38b2e46 fix changelog 2019-07-18 12:29:22 +03:00
Alex Lushpai
3e8b496e95
Merge pull request #70 from Evgeniy-Goroh/master
search city by zip code
2019-07-18 11:59:35 +03:00
gorokh
3bf7da198d search city by zip code 2019-07-12 15:00:41 +03:00
Alex Lushpai
6d379c52f5
Merge pull request #68 from Neur0toxine/master
Изменена логика генерации externalId для оплат
2019-07-04 10:37:54 +03:00
c9cf33cfbb Fix MySQL error in Travis CI 2019-07-03 14:03:14 +03:00
24f862d93f Update description.ru 2019-07-03 13:36:50 +03:00
d65e248ba8 Remove copied method 2019-07-03 13:34:33 +03:00
376024e2bd Backward compatibility with previously created payments 2019-07-03 13:19:34 +03:00
5eb64d9c84 fix: don't remove payments after changes in retailCRM 2019-07-03 13:19:34 +03:00
366e3e2b1d Closes: #61 2019-07-03 13:19:34 +03:00
057a529170 Изменена логика генерации externalId для оплат 2019-07-03 13:19:34 +03:00
Alex Lushpai
65e5085275
Merge pull request #69 from Evgeniy-Goroh/master
Fixed sending empty order when deleting order from CMS
2019-07-03 10:53:13 +03:00
gorokh
58f4ed739d fix travis 2019-07-01 14:59:29 +03:00
gorokh
fa706de2e1 Fixed sending empty order when deleting order from CMS 2019-07-01 14:38:11 +03:00
Alex Lushpai
1c5a15d30b
Merge pull request #67 from Frosin/master
Исправлен баг связанный с некорректным externalId заказа
2019-05-30 14:37:05 +03:00
Konstantin
fb9be7859e Исправлен баг связанный с некооректным externalId 2019-05-29 13:07:59 +03:00
Frosin
b4bc21815b
Merge pull request #1 from retailcrm/master
Свежая версия66
2019-05-29 13:02:29 +03:00
Alex Lushpai
0d9458ad2d
Merge pull request #66 from sergeygw1990/master
Удаление неактивного типа цены у товара
2019-05-24 11:38:48 +03:00
Sergey
04c1cc4c98 Удаление неактивного типа цены у товара 2019-05-23 17:01:49 +03:00
Alex Lushpai
581b7de410
Merge pull request #65 from Frosin/master
Fixed delivery service bug
2019-05-07 17:32:05 +03:00
Konstantin
5c94edd285 fixed generating icml bug highload block without sku 2019-05-07 16:41:57 +03:00
Konstantin
b4cadedadd Fixed the legal data encoding bug 2019-05-07 08:28:15 +03:00
Konstantin
8b1c130ba6 fixed delivery service bug 2019-04-18 09:52:35 +03:00
Konstantin
f41d04fb0e fixed delivery service bug 2019-04-18 09:51:26 +03:00
Konstantin
e28ce27b89 Fixed bug with incorrect value of delivery service received by order history 2019-04-18 09:43:44 +03:00
Alex Lushpai
dbccb53eb4
Merge pull request #64 from sergeygw1990/master
v2.4.6
2019-03-28 17:50:20 +03:00
Sergey
ba74cc6847 fix order history 2019-03-28 16:54:56 +03:00
Sergey
6665799bfc fix history 2019-03-28 16:36:42 +03:00
Alex Lushpai
c62fe78703
Merge pull request #62 from sergeygw1990/master
v2.4.5
2019-03-28 16:30:34 +03:00
Sergey
e1c2dcd09d updated config/retailcrm.json 2019-03-28 14:35:26 +03:00
Alex Lushpai
8c360e512a
Merge pull request #60 from iyzoer/master
Tests
2019-02-28 17:06:37 +03:00
Akolzin Dmitry
462acb2218 update README.md 2019-02-28 16:37:37 +03:00
Akolzin Dmitry
4c9654eac9 test env 2019-02-28 15:57:30 +03:00
Akolzin Dmitry
d98992abe9 update bootstrap 2019-02-28 15:42:04 +03:00
Akolzin Dmitry
27f4d6e6e9 update composer.json 2019-02-28 15:38:54 +03:00
Akolzin Dmitry
1a84e87e82 fix rollback dump 2019-02-28 15:35:09 +03:00
Akolzin Dmitry
92ce32d8a0 update .travis.yml 2019-02-28 15:25:32 +03:00
Akolzin Dmitry
6c7e717a07 fix downloading bitrix 2019-02-28 15:15:41 +03:00
Akolzin Dmitry
e61d68a4db fix tests 2019-02-28 15:11:49 +03:00
Akolzin Dmitry
b223a0ae5b update before script 2019-02-28 14:53:03 +03:00
Akolzin Dmitry
aac8e50559 add .travis.yml 2019-02-28 14:47:16 +03:00
Akolzin Dmitry
6bb711bc52 travis 2019-02-28 14:45:39 +03:00
Alex Lushpai
54bfa6ceeb
Merge pull request #59 from iyzoer/master
v2.4.4
2019-01-23 10:10:18 +03:00
Akolzin Dmitry
7a429e0129 Fixed #58 v2.4.4 2019-01-22 11:46:03 +03:00
Alex Lushpai
2f5ec11017
Merge pull request #57 from iyzoer/master
v2.4.3
2019-01-16 10:37:31 +03:00
Akolzin Dmitry
524b815a47 v2.4.3 2019-01-16 10:28:11 +03:00
Alex Lushpai
6f6fb032e7
Merge pull request #56 from iyzoer/master
v2.4.2
2018-12-26 11:56:23 +03:00
Akolzin Dmitry
eba735b740 v2.4.2 2018-12-26 11:41:06 +03:00
Akolzin Dmitry
1ad5ecf6a2 Добавлены изображения для категорий в ICML 2018-12-18 12:24:02 +03:00
Alex Lushpai
91349647ed
Merge pull request #55 from sergeygw1990/master
v2.4.1
2018-12-14 18:15:30 +03:00
Sergey
16c4020982 v2.4.1 2018-12-14 14:18:55 +03:00
Alex Lushpai
e4ba1db330
Merge pull request #54 from sergeygw1990/master
v2.4.0
2018-11-07 12:52:47 +03:00
Sergey
562d16a597 v2.4.0 2018-11-02 17:41:00 +03:00
Sergey
f80fed989a v2.4.0 2018-11-02 16:51:13 +03:00
Sergey
a91c8b4952 merge 2018-11-02 12:29:43 +03:00
Sergey
5187ec6e1f merge fork 2018-11-02 12:27:29 +03:00
Alex Lushpai
27ff20e9b1
Merge pull request #53 from iyzoer/master
v2.3.14
2018-11-01 15:33:04 +03:00
Akolzin Dmitry
ee067af354 v2.3.14 2018-11-01 09:18:26 +03:00
Sergey
e0903610b5 v2.4.0 2018-10-31 16:25:53 +03:00
Alex Lushpai
93db4eb3c7
Merge pull request #52 from iyzoer/master
v2.3.13
2018-10-25 10:47:40 +03:00
Akolzin Dmitry
3efbd85c16 v2.3.13 2018-10-25 10:43:50 +03:00
Akolzin Dmitry
35ea2532f2 Fix catalog 2018-10-25 10:43:50 +03:00
Akolzin Dmitry
4e244d9791 Add send configuration method 2018-10-25 10:43:50 +03:00
Akolzin Dmitry
5f80630806 Поправил передачу данных по модулю в маркетплейсе для v4 2018-10-25 10:43:50 +03:00
Akolzin Dmitry
e1f429449f Добавлена передача ссылки на настройки модуля в админке 2018-10-25 10:43:50 +03:00
Akolzin Dmitry
24ee93d335 Добавлена отправка запроса на активацию модуля в маркетплейсе при установке, и на деактивацию при удалении 2018-10-25 10:43:50 +03:00
Alex Lushpai
69f9cd2219
Merge pull request #51 from sergeygw1990/master
v 2.3.12
2018-10-18 11:17:25 +03:00
Sergey
730791b834 v2.3.12 2018-10-17 17:27:31 +03:00
Sergey
0c423865e4 v2.3.12 2018-10-17 12:49:16 +03:00
Alex Lushpai
7fd94ccd6e
Merge pull request #50 from iyzoer/master
v2.3.11
2018-10-09 13:59:56 +03:00
Akolzin Dmitry
038739d45f v2.3.11 2018-10-04 16:28:14 +03:00
Sergey
b22d464b56 v2.3.11 2018-10-04 15:47:23 +03:00
Alex Lushpai
71a057387d
Merge pull request #49 from iyzoer/master
v2.3.10
2018-09-26 13:59:53 +03:00
Sergey
cccc4072c7 v2.3.10 2018-09-26 13:34:54 +03:00
Alex Lushpai
c81b2e0038
Merge pull request #48 from iyzoer/master
v2.3.9
2018-08-08 13:05:11 +03:00
Akolzin Dmitry
74aea02a61 Edit CHANGELOG 2018-08-08 13:03:47 +03:00
Akolzin Dmitry
4320aec880 v2.3.9 2018-08-08 10:30:36 +03:00
Alex Lushpai
457cce647b
Merge pull request #47 from iyzoer/master
v2.3.8
2018-07-16 17:45:32 +03:00
Akolzin Dmitry
7e3ea3fa87 v2.3.8 2018-07-16 16:01:19 +03:00
Alex Lushpai
6412e6bf7f
Update README.md 2018-06-18 13:58:36 +03:00
Alex Lushpai
e52cdd6859
Merge pull request #45 from iyzoer/master
v2.3.7
2018-06-15 09:55:52 +03:00
Akolzin Dmitry
0ebb1be7d1 v2.3.7 2018-06-13 13:06:27 +03:00
Alex Lushpai
83d3ec1dc1
Merge pull request #44 from iyzoer/master
v2.3.6
2018-05-23 14:27:52 +03:00
Akolzin Dmitry
ab51935b92 v2.3.6 2018-05-23 12:19:59 +03:00
Alex Lushpai
6b98bf0ee2
Merge pull request #41 from iyzoer/master
v.2.3.5
2018-03-23 13:30:40 +03:00
Akolzin Dmitry
7ae099236c v.2.3.5 2018-03-22 16:11:04 +03:00
Akolzin Dmitry
1e1426f6d3
v.2.3.4 (#39) 2018-02-27 15:29:43 +03:00
Akolzin Dmitry
a27d2f361e
v.2.3.3 (#38) 2018-01-23 17:24:32 +03:00
Dmitry Mamontov
cf41e3dc20 Fix a bug with 100% discount and null payment (#37) 2018-01-23 10:20:53 +03:00
Akolzin Dmitry
02e6beb385
v.2.3.2 (#36) 2018-01-12 11:14:33 +03:00
Akolzin Dmitry
6d398f7160
v.2.3.0 (#35)
* v.2.2.8
* v.2.2.10
* v.2.3.0
* Displaying error message about forbidden api method
2017-12-04 17:44:30 +03:00
Akolzin Dmitry
c357c45072
v.2.2.10 (#34)
* v.2.2.8
* v.2.2.10
2017-11-20 15:47:11 +03:00
Akolzin Dmitry
1e12e4d418
v.2.2.9 (#33) 2017-11-13 11:05:11 +03:00
Akolzin Dmitry
0e1ec2b03c Merge pull request #32 from iyzoer/master
v.2.2.7
2017-10-26 16:35:44 +03:00
Akolzin Dmitry
09fdf232b7 v.2.2.7 2017-10-26 16:30:50 +03:00
Akolzin Dmitry
a6486001f2 Merge pull request #31 from iyzoer/master
v2.2.6
2017-10-25 13:47:14 +03:00
Akolzin Dmitry
f495f98468 2.2.6 2017-10-25 12:34:33 +03:00
Akolzin Dmitry
99bf28c786 2.2.6 2017-10-25 12:15:04 +03:00
Akolzin Dmitry
3c27283ba4 2.2.6 2017-10-25 11:48:44 +03:00
Akolzin Dmitry
d73b150c80 Fix install, fix arrays in ApiClient class 2017-10-25 11:25:09 +03:00
Akolzin Dmitry
e405c683ed Updated payments, bug fix history 2017-10-24 11:41:11 +03:00
Евгений
0557b573a3 v.2.2.5 (#30)
* Теперь учитываются группы доставки
* Изменен алгоритм передачи оплат
* Исправлено задваивание количества товаров в отгрузке
* Небольшие исправления
2017-09-22 15:28:19 +03:00
Евгений
ef4c4a7d33 2.2.4 (#29)
* v.2.2.4 user history fix
2017-09-07 13:27:28 +03:00
Евгений
8d646a735c v.2.2.3 (#28) 2017-09-05 13:52:49 +03:00
Евгений
f77294b6d2 v.2.2.2 (#27) 2017-09-04 15:51:40 +03:00
Евгений
fea35d72ae v.2.2.1 (#26) 2017-09-04 11:36:04 +03:00
Alex Lushpai
02dc926ea3 Merge pull request #24 from ghostrainman/master
v.2.1.2
2016-12-27 13:19:26 +03:00
tishevgeniy
ab2f363db0 v.2.1.2 2016-12-13 14:01:48 +03:00
Alex Lushpai
c330a7fbd2 Merge pull request #23 from ghostrainman/master
v.2.1.1
2016-11-15 17:51:05 +03:00
Евгений Тыщицкий
6504288ab4 v.2.1.1 2016-11-15 17:17:09 +03:00
Alex Lushpai
8ee4e81104 Merge pull request #22 from ghostrainman/master
v.2.0.9
2016-11-01 15:44:44 +04:00
Евгений Тыщицкий
02b4e5cf08 v.2.1.0 2016-10-31 17:56:11 +03:00
Евгений Тыщицкий
7856d7942b v.2.0.9 2016-10-25 17:56:50 +03:00
Alex Lushpai
8768ab86a0 Merge pull request #21 from ghostrainman/master
v.2.0.8
2016-10-21 13:39:30 +04:00
Евгений Тыщицкий
aaad8c1670 v.2.0.8 2016-10-20 17:41:07 +03:00
Alex Lushpai
8e8415f6ea Merge pull request #20 from ghostrainman/master
v.2.0.7
2016-10-20 14:47:09 +04:00
Евгений Тыщицкий
f7393dd251 v.2.0.7 2016-10-20 13:16:59 +03:00
Alex Lushpai
eaa54795c5 Bugfix release
* Исправлена ошибка при обработке Ф.И.О.
* Исправлена ошибка с неверной кодировкой свойств
* Исправлена ошибка формирования списка статусов
* Оптимизация History
* Исправлены ошибки
2016-10-14 16:35:34 +04:00
Евгений Тыщицкий
1482c93cdc v.2.0.6 2016-10-14 15:25:02 +03:00
Евгений Тыщицкий
0b4c15d819 v.2.0.5 2016-10-12 11:40:18 +03:00
Alex Lushpai
99e634d8ce Merge pull request #18 from ghostrainman/master
v.2.0.4
2016-10-06 18:42:33 +04:00
Евгений Тыщицкий
3f858702c4 v.2.0.4 2016-10-06 17:34:35 +03:00
Alex Lushpai
526c74631b Merge pull request #17 from ghostrainman/master
v.2.0.3
2016-10-04 19:04:42 +04:00
Евгений Тыщицкий
02828f45e6 v.2.0.3 2016-10-04 17:57:39 +03:00
Alex Lushpai
8507c71c27 Merge pull request #16 from ghostrainman/master
v.2.0.1
2016-10-03 17:06:48 +03:00
Евгений Тыщицкий
53c1117621 v.2.0.1 2016-10-03 16:56:59 +03:00
Alex Lushpai
9353834226 Merge pull request #15 from ghostrainman/master
order upload fix
2016-09-16 12:36:24 +03:00
Евгений Тыщицкий
26788ef82f order upload fix 2016-09-16 11:46:44 +03:00
Alex Lushpai
256f87ae9a Merge pull request #14 from ghostrainman/master
changelog
2016-09-15 17:52:12 +03:00
Евгений Тыщицкий
3dc3799408 changelog 2016-09-15 17:41:31 +03:00
Alex Lushpai
6de40139e1 merge new version 2016-09-15 17:12:13 +03:00
Евгений Тыщицкий
84bccdac53 v.2.0.0 2016-09-15 16:42:10 +03:00
Alex Lushpai
18dc543494 Merge pull request #12 from iksmail/master
include Logger.php in install
2016-07-14 12:10:08 +03:00
Konstantin Ivanchenko
f8e378a7a7 include Logger.php in install 2016-07-14 11:46:34 +03:00
Alex Lushpai
b6fee101cc Merge pull request #10 from cyradin/master
fix orderHistory exception
2016-04-11 18:26:22 +04:00
Alex Lushpai
61574183e8 Merge pull request #11 from iksmail/master
Обработка неперехватываемого исключения в CSaleOrder::Update
2016-04-11 18:26:13 +04:00
iks
ff9970b2be Catch exception from CSaleOrder::Update 2016-04-11 17:17:43 +03:00
cyradin
6fec60fdd2 fix orderHistory exception 2016-04-08 12:22:38 +03:00
Alex Lushpai
2380ce6108 Merge pull request #9 from ghostrainman/master
v.1.1.3
2015-11-10 10:45:45 +03:00
Евгений Тыщицкий
d032ce81a2 v.1.1.3 2015-11-09 17:46:32 +03:00
Alex Lushpai
8481fed0a9 Update CHANGELOG.md 2015-05-20 10:54:03 +03:00
Alex Lushpai
7da2d5cdf0 Merge pull request #8 from ghostrainman/master
v.1.1.2
2015-05-20 10:50:08 +03:00
Евгений Тыщицкий
3d85b30c42 v.1.1.2 2015-05-18 17:38:06 +03:00
Alex Lushpai
ae4f284107 Merge pull request #6 from dmamontov/master
bug fixes & improvements
2015-03-19 15:55:15 +03:00
Dmitry Mamontov
85c8837079 update description 2015-03-19 15:20:40 +03:00
Dmitry Mamontov
a5095603e9 v.1.1.1
Bug fix
2015-03-19 15:09:37 +03:00
Alex Lushpai
5bd37b65a2 Merge pull request #5 from ghostrainman/master
lang file
2015-03-10 12:50:20 +03:00
Евгений Тыщицкий
1cc9533a25 lang file 2015-03-10 12:44:25 +03:00
Alex Lushpai
7fb059d21d Merge pull request #4 from ghostrainman/master
update module
2015-03-10 12:39:47 +03:00
user
1589ec0395 fix null history 2015-03-04 11:24:57 +03:00
user
8ff572ec56 fix getLocationIDbyCODE 2015-03-04 11:11:07 +03:00
user
50196887e4 v1.1.0 2015-03-03 16:37:34 +03:00
Alex Lushpai
2613b2a2d7 Merge pull request #3 from dmamontov/master
v.1.0.16 fix many bugs
2015-02-17 11:07:58 +03:00
Dmitry Mamontov
325ddbb697 fix clear array && explode fio 2015-02-16 12:21:49 +03:00
Dmitry Mamontov
8c90db7d2c clear trash && fix find user 2015-02-16 11:44:14 +03:00
Dmitry Mamontov
f93924eed4 Update ICrmOrderActions.php 2015-02-16 10:36:39 +03:00
Dmitry Mamontov
b8299b7718 update chngelog 2015-02-16 10:30:04 +03:00
Dmitry Mamontov
88ca56156e fix comment and method 2015-02-13 17:56:50 +03:00
Dmitry Mamontov
54e953eec4 Update users to log changes of the order 2015-02-13 17:52:33 +03:00
Dmitry Mamontov
3a90a7c28e Add users to log changes of the order 2015-02-13 16:15:58 +03:00
Dmitry Mamontov
a570eede61 update changelog 2015-02-12 17:48:01 +03:00
Dmitry Mamontov
2f7235654b Merge branch 'master' of https://github.com/dmamontov/bitrix-module 2015-02-12 17:26:13 +03:00
Dmitry Mamontov
aa506c5c6b update agent 2015-02-12 17:25:35 +03:00
Dmitry Mamontov
b140140a9b Update CHANGELOG.md 2015-02-12 17:20:53 +03:00
Dmitry Mamontov
7bdf5ebea6 v.1.0.16 - update agent && users 2015-02-12 17:18:46 +03:00
Alex Lushpai
80ab0cb4c6 Create LICENSE 2015-02-02 16:24:22 +03:00
Grigory Pomadchin
56b70beb36 multiple site fix 2014-11-27 18:58:34 +03:00
Grigory Pomadchin
fa612ab5a4 multiple site fix 2014-11-27 18:37:59 +03:00
Grigory Pomadchin
37634e19a4 installation fix 2014-11-27 16:06:04 +03:00
Grigory Pomadchin
983f653d86 rm unness var 2014-11-27 16:00:10 +03:00
Grigory Pomadchin
f6ce86310d security fixes 2014-11-27 15:59:01 +03:00
Grigory Pomadchin
3f3d2e4ef3 rmdir fix 2014-11-25 16:11:09 +03:00
Grigory Pomadchin
b2a82791df compatibility fix 2014-11-25 15:58:33 +03:00
Grigory Pomadchin
567ebf1c22 compatibility fix 2014-11-25 15:57:33 +03:00
Grigory Pomadchin
467e5f19f7 compatibility fix 2014-11-25 15:56:18 +03:00
Grigory Pomadchin
dc54ac50e2 fix file exists 2014-11-25 15:32:28 +03:00
Grigory Pomadchin
546a89429f isForkable fix 2014-11-25 01:21:19 +03:00
Grigory Pomadchin
07d4eb31c7 version fix 2014-11-25 00:12:30 +03:00
Grigory Pomadchin
1b5e41cd10 modified installation 2014-11-24 22:13:58 +03:00
Grigory Pomadchin
9846d3612e +curl agent 2014-11-24 22:06:02 +03:00
Grigory Pomadchin
464e568156 v1.0.16 2014-11-24 20:29:35 +03:00
Grigory Pomadchin
5085dfbd66 +forkedAgent 2014-11-24 20:17:16 +03:00
Ilyas Salikhov
bbaec03723 Disallow the intersection of common fields and properties symbol codes 2014-11-18 18:30:43 +03:00
Grisha Pomadchin
c03d1e4b65 v1.0.15; +upd: RestApiClient; +new: createOrder events 2014-11-18 16:50:21 +04:00
Grisha Pomadchin
e45cde522a rm inllegal productId unset 2014-11-11 14:58:42 +04:00
Grisha Pomadchin
42995cef29 lang files fix 2014-11-09 20:08:30 +04:00
Grisha Pomadchin
ef1327f153 v1.0.14 2014-11-09 19:51:24 +04:00
Ilyas Salikhov
a16a08aa5d Wrong ms_id sending 2014-11-04 21:03:28 +03:00
Ilyas Salikhov
7627f5cfa2 Update README.md 2014-11-04 21:00:53 +03:00
Ilyas Salikhov
949f5ce35d Merge pull request #1 from muxx/master
Change IntaroCRM to retailCRM
2014-11-04 20:59:48 +03:00
Ilyas Salikhov
fde49c3c9c Change IntaroCRM to retailCRM 2014-11-01 14:52:40 +03:00
Grisha Pomadchin
2964ea86d8 v1.0.13 2014-10-28 16:54:10 +04:00
Grisha Pomadchin
b536c07e78 puchasing price fix 2014-10-28 16:32:58 +04:00
Ilyas Salikhov
570a01ea77 Disallow the intersection of common fields and properties symbol codes 2014-10-24 09:24:43 +04:00
Grisha Pomadchin
cd5f791b6d restapi client fix 2014-10-08 23:24:26 +04:00
Grisha Pomadchin
adb09334a8 v1.0.12 2014-10-08 21:15:18 +04:00
Grisha Pomadchin
09fa897f07 v1.0.11 2014-10-03 19:20:05 +04:00
Grisha Pomadchin
4aaaaf0f57 +version 2014-10-03 19:06:56 +04:00
Grisha Pomadchin
10962c7fe6 #fix uninit usage in orderHistory method; #fix wrong encoding cancat created user name; #fixes possible crush due to spec php settings (possible crash on usages od undefined array field) 2014-10-03 19:05:21 +04:00
Grisha Pomadchin
eb69ba73ec Merge branch 'generated-items' of github.com:intarocrm/bitrix-module 2014-10-02 13:47:40 +04:00
Grisha Pomadchin
1a4eb93684 install step fix 2014-09-18 18:08:19 +04:00
Grisha Pomadchin
e68139ab54 order fio concat fix 2014-09-15 11:49:44 +04:00
tikijian
a67fbd3a2f Bugfix. correct item array for generated items, created from admin inteface 2014-09-11 14:58:53 +04:00
Grisha Pomadchin
6624be556e v1.0.10 2014-09-04 17:50:57 +04:00
Grisha Pomadchin
c28ad23f56 minor fix 2014-08-12 10:53:26 +04:00
Grisha Pomadchin
0c534c11a7 more codintions to skip order 2014-07-22 16:30:06 +04:00
Grisha Pomadchin
74eb5f1d39 +fix userCreation without crm id; v1.0.9 2014-07-22 15:35:57 +04:00
Grisha Pomadchin
9218018b7c deliveryCost fix 2014-07-17 11:06:42 +04:00
Grisha Pomadchin
31e1941f0b v1.0.8 2014-07-14 11:05:27 +04:00
Grisha Pomadchin
928d7f59ac +clear empty option arrays install.php 2014-07-09 16:51:51 +04:00
Grisha Pomadchin
3502aa4433 +clear empty option arrays 2014-07-09 16:39:03 +04:00
Grisha Pomadchin
ea2ea70c05 rm unness log write 2014-07-09 14:44:19 +04:00
Grisha Pomadchin
743b29c484 default orderType fix 2014-07-09 14:42:45 +04:00
Grisha Pomadchin
120aa7c713 fix orderType escape issue 2014-07-09 12:51:08 +04:00
Grisha Pomadchin
e5f7b0e1d6 price settings fix 2014-07-08 13:38:26 +04:00
Grisha Pomadchin
5c492b6e9c upd restApi client 2014-06-20 17:59:52 +04:00
Grisha Pomadchin
ea4348a856 version fix 2014-06-20 16:47:45 +04:00
Grisha Pomadchin
ab8fcffa66 merge master 2014-06-20 16:11:47 +04:00
Grisha Pomadchin
4d42861b07 event lock global fix 2014-06-20 16:06:20 +04:00
Grisha Pomadchin
400e8c4958 +orderAgent(); +reserveOrderEvents; +basePrice selection on export; +event intarocrm_before_order_send; +fix issues with incorrect order status changing. 2014-06-20 16:03:46 +04:00
Grisha Pomadchin
c4ce5da2fe onBeforeOrderAccountNumberSet fix 2014-06-19 16:24:04 +04:00
Grisha Pomadchin
f02c9c7b57 v1.0.6 2014-05-29 19:33:00 +04:00
Chernyavtsev Ivan
0d1edca441 Merge branch 'master' of https://github.com/intarocrm/bitrix-module 2014-05-29 18:09:14 +04:00
Chernyavtsev Ivan
480b4345ce add convert charset for comments in orderHistory method 2014-05-29 18:06:47 +04:00
Grisha Pomadchin
6c7ab6c47b v1.0.5 2014-05-29 12:14:11 +04:00
Chernyavtsev Ivan
ca8c7a2719 product_xml_id and catalog_xml_id fixed in basket when order created in IntaroCRM 2014-05-29 12:07:40 +04:00
Chernyavtsev Ivan
d051204e4b fix convert charset for comments in orderCreate method 2014-05-28 16:13:24 +04:00
Grisha Pomadchin
fc4447d925 multiship format fix 2014-05-22 18:29:03 +04:00
Grisha Pomadchin
76e0db8202 +multiship 2014-05-22 17:50:33 +04:00
Grisha Pomadchin
3a738a5d00 +multiship 2014-05-22 17:48:44 +04:00
Grisha
7f952813be Update version.php 2014-05-19 13:43:02 +04:00
Grisha Pomadchin
562d60bd5a +apiv3 2014-05-19 13:41:10 +04:00
Grisha Pomadchin
e04486e6db install lang fix 2014-05-06 20:35:41 +04:00
Grisha Pomadchin
acae7ab0bb v.1.0.4 2014-05-06 12:40:38 +04:00
Grisha Pomadchin
6225fbc041 install crash fix 2014-05-06 11:58:29 +04:00
Grisha Pomadchin
1378c1d531 version setup 2014-04-17 12:49:53 +04:00
Grisha Pomadchin
77bb3160c1 Merge branch 'purchase-price' of github.com:intarocrm/bitrix-module into 1.0.3a 2014-04-17 11:40:11 +04:00
Grisha Pomadchin
62ad023f03 LOCATION fix 2014-04-17 11:35:34 +04:00
Ilyas Salikhov
4b5dea4263 Upload purchase price in order products 2014-04-16 15:41:17 +04:00
Grisha Pomadchin
c5c0804ee7 fix locations 2014-04-16 14:34:05 +04:00
Grisha Pomadchin
9e4b72c3ae fix location props 2014-04-16 12:27:34 +04:00
Grisha Pomadchin
f73a4feeb9 Merge branch 'purchase-price' of github.com:intarocrm/bitrix-module into 1.0.3a 2014-04-16 11:31:49 +04:00
Grisha Pomadchin
9f0a2a1b1d Revert to 7dcc438 2014-04-16 11:28:00 +04:00
Ilyas Salikhov
2406c71652 Purchase price loading 2014-04-15 20:31:11 +04:00
Grisha Pomadchin
695f26cc67 fix address format 2014-04-02 10:59:12 +04:00
Grisha Pomadchin
7dcc438fe8 api class methods fix 2014-03-22 15:15:37 +04:00
Grisha Pomadchin
7657ae434a api class fix 2014-03-22 15:08:51 +04:00
Grisha Pomadchin
38e7157d18 +apiv2; +upd RestApi 2014-03-22 14:52:17 +04:00
Grisha Pomadchin
92d559d822 version fix 2014-03-14 20:56:46 +04:00
Grisha Pomadchin
413bab2be6 delivery Service upload fix 2014-03-13 18:37:07 +04:00
Grisha Pomadchin
4fadc1d43c global fix 2014-03-13 13:37:16 +04:00
Grisha Pomadchin
abb4bae99a v1.0.1 2014-03-13 13:21:43 +04:00
Grisha Pomadchin
6f70fcaac7 history fix; v1.0.01 2014-03-13 13:00:51 +04:00
Grisha Pomadchin
274fd7a9a4 event side effects (hisotry) fix 2014-03-13 12:58:52 +04:00
Grisha Pomadchin
2f309dee4a history fix & new version 2014-03-13 12:07:52 +04:00
Grisha Pomadchin
b16af9db1f options php vis fix 2014-02-20 17:11:43 +04:00
Ilyas Salikhov
0f885e2e54 optimize catalog export + added limitation on offers fetching 2014-02-19 15:18:35 +04:00
Ilyas Salikhov
45662c78ed https in urls in ICML 2014-02-14 18:51:19 +03:00
Grisha Pomadchin
a1cf53dedf order status empty fix 2014-02-13 17:34:42 +04:00
Grisha Pomadchin
8dbcb9e55d options indicate custom order type 2014-02-13 16:25:26 +04:00
m.korolev
e53d63116d Merge branch 'origin/master' 2014-02-13 15:20:31 +04:00
m.korolev
5cbab8609f fix server_name 2014-02-13 15:20:23 +04:00
Grisha Pomadchin
3590e998f5 fix custom order type func 2014-02-12 11:19:46 +04:00
m.korolev
14d7d2d201 Merge branch 'exportICMLSize' 2014-02-12 11:10:20 +04:00
Grisha Pomadchin
663431dc19 fix custom order type funcs 2014-02-12 11:06:32 +04:00
Grisha Pomadchin
1df0d65827 upd custom type func calls 2014-02-12 09:44:35 +04:00
m.korolev
9fa0d8e1b8 fix added param, param 2014-02-11 15:06:40 +04:00
Grisha Pomadchin
5d0f4e745a fix custom order type function names 2014-02-10 15:23:57 +04:00
Grisha Pomadchin
74fb142f05 crm to bitrix type function 2014-02-10 12:25:18 +04:00
Grisha Pomadchin
98a6012fe5 custom type function 2014-02-10 12:19:36 +04:00
m.korolev
d2d814f731 Merge branch 'exportICMLSize' 2014-02-03 12:32:41 +04:00
m.korolev
512cac0b27 fix global User creating 2014-02-03 12:32:11 +04:00
Grisha Pomadchin
8718f7f637 price fix 2014-02-01 17:02:40 +04:00
Grisha Pomadchin
513f852b60 fixes 2014-02-01 12:12:29 +04:00
Grisha Pomadchin
1fdd539252 fixes 2014-01-31 20:20:37 +04:00
m.korolev
8910c7ef37 Merge branch 'exportICMLSize' 2014-01-31 20:11:52 +04:00
m.korolev
68aefcf6c5 Fix USER 2014-01-31 20:11:28 +04:00
m.korolev
ffc5c8c3b4 Merge branch 'origin/master' 2014-01-30 15:59:36 +04:00
m.korolev
db0f8e4bd7 Merge branch 'exportICMLSize' 2014-01-30 15:59:09 +04:00
m.korolev
5c1917a8e8 fix ICML Loading - check if is an array 2014-01-30 15:54:49 +04:00
Grisha Pomadchin
88af200829 Merge branch 'fullExport' of github.com:intarocrm/bitrix-module 2014-01-30 12:37:23 +04:00
Grisha Pomadchin
296c7a82c1 Merge branch 'exportICMLSize' of github.com:intarocrm/bitrix-module into fullExport 2014-01-30 12:31:46 +04:00
m.korolev
75d44cd73e Merge branch 'exportICMLSize' 2014-01-30 12:27:01 +04:00
m.korolev
98ad65413c Fix ICML Loading 2014-01-30 12:26:37 +04:00
Grisha Pomadchin
4469c44861 deliveryServices export in options.php; several fixes. 2014-01-30 12:17:58 +04:00
Grisha Pomadchin
2de2077055 opt export DeliveryServices 2014-01-29 18:42:52 +04:00
Grisha Pomadchin
091d13b163 Merge branch 'exportICMLSize' of github.com:intarocrm/bitrix-module into fullExport 2014-01-28 17:50:11 +04:00
Grisha Pomadchin
a8f746d1bd fix orderHistory init time; 2014-01-28 17:46:27 +04:00
Grisha Pomadchin
08c5169417 fix orderHistory init time; 2014-01-28 17:45:02 +04:00
m.korolev
af06a1decd Fix names in settings 2014-01-28 17:09:46 +04:00
Grisha Pomadchin
83f84ebb7f version fix 2014-01-28 12:55:49 +04:00
Grisha Pomadchin
f08b54033e email from customer obj 2014-01-28 12:53:36 +04:00
Grisha Pomadchin
fb148315d7 create users 2014-01-28 12:44:20 +04:00
Grisha Pomadchin
13a91ebf6a Merge branch 'exportICMLSize' of github.com:intarocrm/bitrix-module into fullExport 2014-01-28 10:23:59 +04:00
Grisha Pomadchin
48a19f8ce5 workin' ver 2014-01-27 19:14:43 +04:00
Grisha Pomadchin
7fd2c09059 rm option settings 2014-01-24 17:57:49 +04:00
Grisha Pomadchin
3f7cc6b963 +deliveryServices options & install; -order send 2014-01-23 17:50:58 +04:00
m.korolev
ccf74770a9 Dimensions have added 2014-01-23 17:05:07 +04:00
Grisha Pomadchin
34f83d5dcc fix commit 2014-01-22 10:36:18 +04:00
Grisha Pomadchin
c024e9609c incl lang file 2013-12-30 00:37:29 +04:00
Grisha Pomadchin
3b41004926 lang fix 2013-12-29 21:27:23 +04:00
Grisha Pomadchin
4eaaec53b7 order discount fix 2013-12-28 19:20:38 +04:00
Grisha Pomadchin
36a5c31bae history session fix 2013-12-26 20:40:11 +04:00
Grisha Pomadchin
098d966039 history session fix 2013-12-26 01:49:50 +04:00
b12
4bc57cc63a fix bugs in product status processing 2013-12-25 18:38:25 +04:00
Ilyas Salikhov
deac6e4cb4 ready for product statuses 2013-12-25 16:30:46 +04:00
Grisha Pomadchin
be1041a38f Merge branch 'master' of github.com:intarocrm/bitrix-module 2013-12-03 15:54:27 +04:00
Grisha Pomadchin
d4abc60e2f user creation fix 2013-11-28 17:02:21 +04:00
m.korolev
5ce54327c2 get encoding from default site 2013-11-28 15:42:22 +04:00
Grisha Pomadchin
5df36eaa5d option charset fix 2013-11-28 15:09:42 +04:00
Grisha Pomadchin
18906ce9ce to v0.5.1 2013-11-28 15:08:07 +04:00
Grisha Pomadchin
531799b16a null dicount 2013-11-15 17:51:51 +04:00
Grisha Pomadchin
870c1f4a11 null dicount 2013-11-15 17:49:40 +04:00
Grisha Pomadchin
fae73904d2 discount fix 2013-11-15 17:26:51 +04:00
Grisha Pomadchin
344a952f99 discount fix 2013-11-15 16:51:57 +04:00
Grisha Pomadchin
63d03327f3 fixes due to status and site 2013-11-15 15:55:54 +04:00
Grisha Pomadchin
8f2d6befbc cancel event fix; discount upd fix. 2013-11-14 16:41:19 +04:00
m.korolev
c67359ce94 bugfix encoding ICML loading 2013-11-14 15:53:26 +04:00
Grisha Pomadchin
e8ffdbc62c change version file 2013-11-14 12:12:47 +04:00
Grisha Pomadchin
6f2d8b2a7b options encoding fix 2013-11-13 23:25:29 +04:00
Grisha Pomadchin
c8e6ec6e59 step3 cp1251 fix 2013-11-13 23:18:47 +04:00
Grisha Pomadchin
b9e681a683 fix summ null error 2013-11-13 23:05:19 +04:00
Grisha Pomadchin
5e33d50f98 fix summ null error 2013-11-13 22:58:53 +04:00
Grisha Pomadchin
60c3af7f97 fix index, cancel status, % priceoff fix 2013-11-13 18:01:44 +04:00
Grisha Pomadchin
317b580d8a comment lines for sites support 2013-11-12 15:22:35 +04:00
Grisha Pomadchin
f22f5d310c Merge branch 'master' of github.com:intarocrm/bitrix-module 2013-11-09 01:12:44 +04:00
Grisha Pomadchin
c6b9fe67c5 added upd with methods 2013-11-09 01:12:20 +04:00
m.korolev
3ee055c215 bugfix charset error from cli 2013-11-08 19:21:08 +04:00
Grisha Pomadchin
2de51507a7 general order sum fix 2013-11-06 16:01:25 +04:00
Grisha Pomadchin
3d2ac096d2 price history fix 2013-11-06 15:24:22 +04:00
Grisha Pomadchin
2f83fed243 exp orders by event in defaults 2013-11-01 17:08:09 +04:00
Grisha Pomadchin
cbff7073bf empty phones fix 2013-10-31 11:45:26 +04:00
Grisha Pomadchin
270bb72c9d empty phones fix 2013-10-31 11:44:12 +04:00
Grisha Pomadchin
7cdda7aa11 api changes fix 2013-10-31 10:49:20 +04:00
Grisha Pomadchin
45c180c40e upd +0.4.3 2013-10-30 17:01:34 +04:00
Grisha Pomadchin
43cb653ee2 fixes 2013-10-29 19:29:42 +04:00
Grisha Pomadchin
fb16243351 charset fix 2013-10-29 19:21:04 +04:00
Grisha Pomadchin
6603923d53 cancel status fix 2013-10-29 19:16:32 +04:00
Grisha Pomadchin
24ff76ee0d datetime fix 2013-10-29 17:14:03 +04:00
Grisha Pomadchin
3e45e317bd histoty date init and remove 2013-10-29 16:15:40 +04:00
Grisha Pomadchin
16a94ebac4 upd version file 2013-10-29 15:30:47 +04:00
Grisha Pomadchin
b79577105a Merge branch 'history' of github.com:intarocrm/bitrix-module 2013-10-29 14:41:46 +04:00
m.korolev
52e6e1d933 fix loading not active products 2013-10-15 15:58:25 +04:00
m.korolev
d4c6d405dd 1. Added load not active products
2. Remake loading ICML
2013-10-10 17:46:14 +04:00
Grisha Pomadchin
3623a8e134 order final fixes 2013-10-09 19:29:07 +04:00
Grisha Pomadchin
59ed1b87cc fix order history 2013-10-09 19:24:28 +04:00
Grisha Pomadchin
eddf81659d revert to 494b5a270 2013-10-08 17:07:55 +04:00
Grisha Pomadchin
78c5ff8252 descr files 2013-10-08 16:48:46 +04:00
Grisha Pomadchin
494b5a2701 Merge branch 'exportExtendedProperties' of github.com:intarocrm/bitrix-module into history 2013-10-08 16:45:22 +04:00
m.korolev
c070e5bec5 Merge branch 'exportExtendedProperties'
Conflicts:
	intaro.intarocrm/export/export_run.php
	intaro.intarocrm/export/export_setup.php
	intaro.intarocrm/install/index.php
	intaro.intarocrm/install/step5.php
	intaro.intarocrm/lang/ru/icml_export_setup.php
2013-10-08 16:39:50 +04:00
Grisha Pomadchin
a616532ae9 version file 2013-10-08 16:24:38 +04:00
Grisha Pomadchin
0a84b8f2ba changed working prot 2013-10-04 16:56:57 +04:00
Grisha Pomadchin
323b67d400 history fix duplicate products 2013-10-04 16:36:43 +04:00
Grisha Pomadchin
3644c385b3 rm var_dump 2013-10-02 17:49:24 +04:00
Grisha Pomadchin
8508c6bebb new orders create 2013-10-02 17:45:28 +04:00
Grisha Pomadchin
0d8d174980 v0.4.1 2013-10-02 17:42:20 +04:00
m.korolev
b2ae04bebb fix complex array storage in bitrix 2013-09-25 20:36:49 +04:00
m.korolev
2b0b5c0049 Merge branch 'exportExtendedProperties' 2013-09-23 18:28:48 +04:00
m.korolev
a6f94494c7 fix JavaScript in step 5 2013-09-23 18:27:47 +04:00
m.korolev
5265c5d5c8 Delete update.php 2013-09-23 18:16:26 +04:00
m.korolev
d058783a60 Add translations to ICML export 2013-09-23 18:05:37 +04:00
m.korolev
62bbcc0f48 Merge branch 'master'
Conflicts:
	intaro.intarocrm/classes/general/ICMLLoader.php
2013-09-23 17:44:26 +04:00
Grisha Pomadchin
f63a3271a6 number fix 2013-09-22 23:12:29 +04:00
Grisha Pomadchin
78087575a8 lang fix 2013-09-22 22:51:12 +04:00
Grisha Pomadchin
66c0d8998b event fixes 2013-09-22 21:28:28 +04:00
Grisha Pomadchin
6c2552881b catalog export fix 2013-09-22 20:03:35 +04:00
Grisha Pomadchin
0e5c9b5b6c fixes due to upload event & upload agent 2013-09-20 19:12:01 +04:00
Grisha Pomadchin
7af1925bb2 uninstallation fix 2013-09-19 00:20:56 +04:00
Grisha Pomadchin
e210a7a26f histore update fixes 2013-09-19 00:18:32 +04:00
Grisha Pomadchin
e13fddda75 +getLocationCityId 2013-09-17 19:02:19 +04:00
Grisha Pomadchin
622dd0e56c fixed order status update 2013-09-17 18:31:15 +04:00
Grisha Pomadchin
e3ceadfe67 fix onOrderUpdateEvent 2013-09-17 18:06:58 +04:00
Grisha Pomadchin
77abe318ac removed test log 2013-09-17 15:40:23 +04:00
Grisha Pomadchin
13f72cc89f options fix 2013-09-17 15:17:39 +04:00
m.korolev
d59d100afc It update old profiles to new format 2013-09-16 15:37:22 +04:00
m.korolev
596709946c Extended properties add to export 2013-09-13 16:15:54 +04:00
Grisha Pomadchin
e8f55aa087 removed repl lines 2013-09-13 14:16:58 +04:00
Grisha Pomadchin
084147eb2b merge fix; v0.4.0 2013-09-12 19:00:46 +04:00
Grisha Pomadchin
90ea4b3eab update icml 2013-09-12 17:31:32 +04:00
Grisha Pomadchin
ebbc5d2763 merge fix 2013-09-12 17:16:54 +04:00
Grisha Pomadchin
4a9375d906 merge 2013-09-12 17:05:02 +04:00
Grisha Pomadchin
903774d57d after merge 2013-09-12 17:01:29 +04:00
Grisha Pomadchin
cbff873be0 install fix 2013-09-12 16:56:14 +04:00
Grisha Pomadchin
597696b692 merge 2013-09-12 16:53:24 +04:00
Grisha Pomadchin
e6731c7a65 Merge branch 'master' of github.com:intarocrm/bitrix-module into mode-discharge 2013-09-12 16:37:34 +04:00
Grisha Pomadchin
3f1840b323 last id fix 2013-09-12 16:29:55 +04:00
Grisha Pomadchin
3e9f019f7e fio fix 2013-09-12 16:27:43 +04:00
Grisha Pomadchin
c6e2a8c1b7 fix order last id in event 2013-09-12 11:32:50 +04:00
m.korolev
6db7bc93e1 Writing offers to file has been paginate 2013-09-11 15:37:50 +04:00
Grisha Pomadchin
5ef7ec6538 mode change in options 2013-09-10 17:15:41 +04:00
m.korolev
0397aad602 Before commit: Collect data about categories, then format this, collect data about offers, then format this, and then write all to file.
After commit: Collect all data, then format all data and write all
2013-09-10 09:25:17 +04:00
Grisha Pomadchin
22b82eff3f fix explode 2013-09-09 17:55:13 +04:00
Grisha Pomadchin
3e8013c29a fix explode 2013-09-09 17:54:38 +04:00
Grisha Pomadchin
fc469781b2 fix explode 2013-09-09 17:53:58 +04:00
Grisha Pomadchin
f09cec3e5d fex method 2013-09-09 17:52:55 +04:00
Grisha Pomadchin
8271e5ab45 fix explode name 2013-09-09 16:56:57 +04:00
Grisha Pomadchin
98aa0afcbb fio fix 2013-09-09 16:55:28 +04:00
Grisha Pomadchin
84a512eefa line fix 2013-09-09 16:53:09 +04:00
Grisha Pomadchin
b3f1800754 fix of fio fix 2013-09-09 16:52:30 +04:00
Grisha Pomadchin
f29c0f62a4 fio parsing fix 2013-09-09 16:49:08 +04:00
Grisha Pomadchin
3fa296423b added explodeFIO func 2013-09-09 16:46:37 +04:00
Grisha Pomadchin
1524a94db0 fio parsing fix 2013-09-09 16:43:44 +04:00
Grisha Pomadchin
2ccc2999e6 fixes 2013-09-09 16:35:22 +04:00
Grisha Pomadchin
0812440edc fixed fio parsing 2013-09-09 16:26:01 +04:00
Grisha Pomadchin
5dd88b798d disable multiple sites support 2013-09-05 14:01:56 +04:00
Grisha Pomadchin
f4e33b5af5 lang files fix 2013-09-05 13:43:04 +04:00
Grisha Pomadchin
ba82f22b64 +order Types support 2013-09-05 13:38:58 +04:00
Grisha Pomadchin
6f97c22b54 +step in installer 2013-09-05 12:11:29 +04:00
Ilyas Salikhov
8d7ee7b132 fix 0.3.11 2013-09-05 09:38:38 +04:00
Grisha Pomadchin
be7d3d76cd removed var_dumps 2013-09-04 20:50:49 +04:00
Grisha Pomadchin
0ce0403311 +orderHistory agent 2013-09-04 20:49:07 +04:00
Grisha Pomadchin
1d611ef2f7 class fixes 2013-09-04 20:41:51 +04:00
m.korolev
bb94fba4c3 Merge branch 'origin/master' 2013-09-04 12:20:46 +04:00
m.korolev
a3a72718f8 At now categories load from IB of product 2013-09-04 12:20:33 +04:00
Grisha Pomadchin
edcadcd052 +upd class 2013-09-03 18:23:27 +04:00
Grisha Pomadchin
c2729dcb93 inserted into options; new branch 2013-09-03 18:00:12 +04:00
Grisha Pomadchin
c1c298b4eb timezone fix; v0.3.9.1 2013-09-03 13:22:05 +04:00
Grisha Pomadchin
84d9727fa4 info in install 2013-09-02 18:17:42 +04:00
Grisha Pomadchin
76ff775810 info in install 2013-09-02 18:16:12 +04:00
Grisha Pomadchin
28ccea77e7 info in install 2013-09-02 18:15:11 +04:00
Grisha Pomadchin
3ebf5a1d31 At now articles load from Product InfoBlock 2013-09-02 17:52:56 +04:00
Grisha Pomadchin
fbddb65f37 At now articles load from Product InfoBlock 2013-09-02 17:51:12 +04:00
Grisha Pomadchin
4306e37e5d At now articles load from Product InfoBlock 2013-09-02 17:50:23 +04:00
Grisha Pomadchin
cb94c210c0 history update 2013-09-02 17:41:05 +04:00
m.korolev
f684763ea9 At now articles load from Product InfoBlock 2013-09-02 17:40:21 +04:00
Grisha Pomadchin
d02d4a9f1a added timezone check before install 2013-09-02 16:30:50 +04:00
Grisha Pomadchin
6d77b107cf added timezone check before install 2013-09-02 16:29:54 +04:00
Grisha Pomadchin
3b8ea43d80 added desciption file 2013-09-02 16:25:39 +04:00
Grisha Pomadchin
6c340f17b2 added timezone check before install 2013-09-02 16:24:30 +04:00
Grisha Pomadchin
24088aa568 added timezone check before install 2013-09-02 16:23:15 +04:00
Grisha Pomadchin
8d883e407d v0.4.0 2013-09-02 16:03:27 +04:00
Grisha Pomadchin
bb22ddb413 fixes 2013-09-02 15:57:16 +04:00
Grisha Pomadchin
db6f1d7013 multi site support 2013-09-02 15:48:38 +04:00
Grisha Pomadchin
2bb2331047 agent fix 2013-08-28 12:43:37 +04:00
Grisha Pomadchin
fbd56c2512 upd 2013-08-27 18:05:55 +04:00
Grisha Pomadchin
eda0e3b68b Merge branch 'master' of github.com:intarocrm/bitrix-module into referenceDeliveryTypeExport 2013-08-27 15:37:28 +04:00
Grisha Pomadchin
f0b87087e7 delete updater from master 2013-08-26 11:05:33 +04:00
Ilyas Salikhov
0e4988e415 Merge branch '0.3.9'
Conflicts:
	intaro.intarocrm/export/export_setup.php
	intaro.intarocrm/install/version.php
2013-08-26 10:42:47 +04:00
Ilyas Salikhov
a592053447 fix encoding 2013-08-26 10:38:52 +04:00
Ilyas Salikhov
535e665fc7 v0.3.9 2013-08-26 10:33:51 +04:00
Ilyas Salikhov
42d54b1982 fix in messages 2013-08-21 19:00:14 +04:00
m.korolev
63b10e658f add empty option in select articles 2013-08-21 18:40:45 +04:00
m.korolev
82fce596dc bugfix profile editing 2013-08-21 17:08:02 +04:00
m.korolev
b1a71726fc Articles is not modatory now 2013-08-20 13:42:13 +04:00
m.korolev
57335ffb54 bugfix with & 2013-08-20 13:06:31 +04:00
m.korolev
04ea0ea00e refactoring export run and setup 2013-08-20 12:53:32 +04:00
m.korolev
a1258b9af2 bugfix Count of profile 2013-08-19 18:13:26 +04:00
m.korolev
2a66f0a67b bug fix ICMLLoader.php 2013-08-19 15:14:36 +04:00
m.korolev
6bb71edd15 Fix bugs in export encoding 2013-08-19 10:43:59 +04:00
Grisha Pomadchin
3926b01901 update up to 3.8 2013-08-16 16:29:11 +04:00
Grisha Pomadchin
07e42e793c Revert to cf6a9ab20 2013-08-16 16:24:12 +04:00
Grisha Pomadchin
9ce341cf43 update up to 0.3.8 2013-08-16 16:18:06 +04:00
Grisha Pomadchin
cf6a9ab203 stable 2013-08-15 22:05:06 +04:00
Grisha Pomadchin
9a3ec002d6 added method 2013-08-15 19:41:07 +04:00
Grisha Pomadchin
67781a6f00 merge exportICML 2013-08-15 19:29:32 +04:00
Grisha Pomadchin
e68db44642 fixes 2013-08-15 19:19:12 +04:00
Grisha Pomadchin
ca6e71d55f sending delivery types without pay systems 2013-08-15 18:49:54 +04:00
m.korolev
f2097f72f0 Actual index 2013-08-15 18:14:41 +04:00
m.korolev
4c12e36c67 BugFix names 2013-08-15 18:01:03 +04:00
m.korolev
c947c7109f 1. added error handler
2. added updater
2013-08-15 17:34:29 +04:00
m.korolev
a7d5828caa Exports files has been added 2013-08-15 14:46:13 +04:00
Grisha Pomadchin
b1b2d685db event reovery 2013-08-14 20:12:40 +04:00
Grisha Pomadchin
d0a5ad4cf0 update 0.3.7 -> 0.3.8 2013-08-14 19:56:52 +04:00
pomadchin
bba1df38dc deprecated parameters removing 2013-08-14 16:54:00 +04:00
pomadchin
f564c6c8e0 only package mode 2013-08-14 16:51:40 +04:00
pomadchin
8d5918cfc3 lang files mod 2013-08-14 12:23:00 +04:00
pomadchin
5e99c0c71d fixed issue 2013-08-14 12:12:09 +04:00
pomadchin
33f279f90c merge export 2013-08-14 11:42:01 +04:00
pomadchin
dec7cd50ea merging second 2013-08-14 11:05:37 +04:00
pomadchin
1a7cd55b46 del confl files 2013-08-14 10:50:30 +04:00
МЫ
6d7829b03c test merge 2013-08-14 10:45:05 +04:00
МЫ
29bf585826 test 2013-08-14 10:44:27 +04:00
Grisha Pomadchin
f92a62f70e statuses ajax update 2013-08-07 14:45:25 +04:00
m.korolev
e6c8e49fc1 Delete old Export to ICML 2013-08-06 19:16:55 +04:00
m.korolev
14dce123c4 Export to ICML has been modified
Added step4 into install
2013-08-06 19:13:49 +04:00
Grisha Pomadchin
878a958ee3 orderCreate fix 2013-08-05 15:20:07 +04:00
Grisha Pomadchin
03a72e37a3 deleted version ~ 2013-08-05 10:57:33 +04:00
Grisha Pomadchin
b52e3062ca fixes 2013-08-02 18:44:59 +04:00
Grisha Pomadchin
f33f4c304f final fix 2013-07-31 17:18:33 +04:00
Grisha Pomadchin
db12c374d3 fixes 2013-07-31 10:24:47 +04:00
Grisha Pomadchin
eb9b3c46ed lastUpORderId fix 2013-07-29 21:25:40 +04:00
Grisha Pomadchin
2da03f3025 some fixes 2013-07-29 18:59:51 +04:00
Grisha Pomadchin
72bf320605 working customerUpload + send city fix; 2013-07-29 18:40:36 +04:00
Grisha Pomadchin
befb6f59d4 working customerUpload + send city fix; 2013-07-29 18:38:15 +04:00
Grisha Pomadchin
4f934aed10 api module fix 2013-07-29 17:53:54 +04:00
Grisha Pomadchin
e1776dfb46 customersUpload beta (not working) 2013-07-29 17:48:24 +04:00
705 changed files with 121066 additions and 4402 deletions

12
.docker/Dockerfile Executable file
View file

@ -0,0 +1,12 @@
FROM php:8.0-apache
RUN a2enmod rewrite
RUN set -xe \
&& apt-get update \
&& apt-get install -y unzip libpng-dev libzip-dev libonig-dev libjpeg-dev libmcrypt-dev wget \
&& docker-php-ext-install mysqli zip
RUN curl --insecure https://getcomposer.org/composer.phar -o /usr/bin/composer && chmod +x /usr/bin/composer
WORKDIR /bitrix-module

25
.docker/php.ini Executable file
View file

@ -0,0 +1,25 @@
[php]
short_open_tag = On
display_errors = On
error_log = "/var/log/php/error.log"
error_reporting = E_ALL
log_errors = On
display_startup_errors = On
cgi.fix_pathinfo = 0
date.timezone = "Europe/Moscow"
default_charset = utf-8
max_input_vars = 10000
post_max_size = 1024M
memory_limit = 256M
upload_max_filesize = 1024M
pcre.jit = 0
pcre.recursion_limit = 10485760
[opcache]
opcache.revalidate_freq = 0
opcache.validate_timestamps = 1
opcache.max_accelerated_files = 100000
opcache.memory_consumption = 512
opcache.interned_strings_buffer = 64
opcache.fast_shutdown = 1
opcache.error_log = "/var/log/php/opcache.log"

6
.env.dist Executable file
View file

@ -0,0 +1,6 @@
DB_BITRIX_HOST=""
DB_BITRIX_LOGIN=""
DB_BITRIX_PASS=""
DB_BITRIX_NAME=""
BITRIX_PATH=/var/www/html
BITRIX_EDITION=small_business_encode

116
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,116 @@
name: ci
on:
push:
branches:
- '**'
tags-ignore:
- '*.*'
pull_request:
env:
DB_BITRIX_HOST: 0.0.0.0
DB_BITRIX_LOGIN: root
DB_BITRIX_PASS: root
DB_BITRIX_NAME: bitrix
BITRIX_PATH: ${{ github.workspace }}/bitrix
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['8.1']
bitrix-edition: ['small_business_encode', 'business_encode']
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: ${{ env.DB_BITRIX_PASS }}
MYSQL_DATABASE: bitrix
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5
steps:
- uses: actions/checkout@v2
- name: Setup PHP ${{ matrix.php-version }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
ini-values: short_open_tag=On, mbstring.func_overload=2, mbstring.internal_encoding="UTF-8"
coverage: xdebug
- name: Install Bitrix
env:
BITRIX_EDITION: ${{ matrix.bitrix-edition }}
run: make install_bitrix
- name: Enable debug mode for tests
run: php bin/enable_debugging "${{ env.BITRIX_PATH }}"
- name: Validate composer.json and composer.lock
run: composer validate
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: make deps
- name: Run tests
run: make test
- name: Coverage
run: bash <(curl -s https://codecov.io/bash)
deploy:
needs: ['test']
if: success() && github.event_name == 'push' && github.repository_owner == 'retailcrm' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup PHP 8.1
uses: shivammathur/setup-php@v2
with:
php-version: 8.1
ini-values: short_open_tag=On, mbstring.func_overload=2, mbstring.internal_encoding="UTF-8"
- name: Build release
run: |
git fetch origin --unshallow --tags
export CURRENT_VERSION=`php bin/bitrix-version`
export ARCHIVE_PATH="${{ github.workspace }}/release/$CURRENT_VERSION.tar.gz"
export LAST_TAG=`git describe --tags $(git rev-list --tags --max-count=1) || true`
export RELEASE_TAG=v$CURRENT_VERSION
echo CURRENT_VERSION=$CURRENT_VERSION >> $GITHUB_ENV
echo LAST_TAG=$LAST_TAG >> $GITHUB_ENV
echo ARCHIVE_NAME="$CURRENT_VERSION.tar.gz" >> $GITHUB_ENV
echo ARCHIVE_PATH=$ARCHIVE_PATH >> $GITHUB_ENV
echo RELEASE_TAG=$RELEASE_TAG >> $GITHUB_ENV
echo Current version is $CURRENT_VERSION, release tag will be v$CURRENT_VERSION
echo Last tag is $LAST_TAG, archive will be saved to $ARCHIVE_PATH
make build_release
- name: Create Release
id: create_release
uses: actions/create-release@v1
if: env.LAST_TAG != env.RELEASE_TAG
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.RELEASE_TAG }}
release_name: ${{ env.RELEASE_TAG }}
body_path: ${{ github.workspace }}/intaro.retailcrm/description.ru
draft: false
prerelease: false
- name: Upload Release Asset
id: upload-release-asset
if: env.LAST_TAG != env.RELEASE_TAG
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ${{ env.ARCHIVE_PATH }}
asset_name: ${{ env.ARCHIVE_NAME }}
asset_content_type: application/gzip
- name: Cleanup
if: env.LAST_TAG != env.RELEASE_TAG
run: make cleanup

17
.gitignore vendored Normal file
View file

@ -0,0 +1,17 @@
.DS_Store
*~
/nbproject/*
/.idea/*
/*tags*
.idea
.idea/*
/.idea
/.idea/*
/intaro.retailcrm/log/*
/tmp/
/vendor/
.env
.phpunit.result.cache
/release/
coverage.xml

749
CHANGELOG.md Normal file
View file

@ -0,0 +1,749 @@
## 2025-03-26 v6.6.11
- Исправлена передача габаритов при выгрузке заказов по агенту
## 2025-03-25 v6.6.10
- Исправлено некорректное изменение статуса оплаты отмененных заказов
## 2025-03-04 v6.6.9
- Исправлено обновление модуля
## 2025-03-03 v6.6.8
- Исправлена ошибка экспорта дополнительных свойств товаров
## 2025-02-04 v6.6.7
- Исправлена ошибка установки модуля на PHP 8.0
## 2025-01-29 v6.6.6
- Поддержка нулевой закупочной стоимости при генерации каталога
## 2025-01-28 v6.6.5
- Исправлена ошибка редактирования интеграционных доставок при активации опции передачи статусов интеграционных оплат
## 2025-01-27 v6.6.4
- Исправлено некорректное удаление признака применения промокода при изменении состава заказа в CRM
## 2025-01-14 v6.6.3
- Исправлены ошибки при обновлении модуля
## 2025-01-14 v6.6.2
- Исправлена выгрузка архива заказов при установке модуля
## 2024-12-17 v6.6.1
- Исправлены API методы по взаимодействию с пользовательскими полями и справочниками
## 2024-12-09 v6.6.0
- Добавлено динамическое изменение свойств товаров при настройке экспорта
## 2024-12-08 v6.5.39
- Исправлена поломка заказов с промокодом Maxma при включенной передаче корзины в CRM
## 2024-10-31 v6.5.38
- Исправлена выгрузка заказов через агент
## 2024-10-30 v6.5.37
- Исправлена подписка модуля на событие сохранения заказа
## 2024-10-24 v6.5.36
- Добавлена передача профилей доставки Официального модуля Почты России
## 2024-10-22 v6.5.35
- Исправлена подписка модуля на событие сохранения заказа
## 2024-10-21 v6.5.34
- Исправлена ошибка агента выгрузки изменений при наличии у заказа клиента без магазина
## 2024-10-14 v6.5.33
- Добавлена передача дополнительных параметров в GET запросах
## 2024-10-03 v6.5.32
- Исправлена подписка на событие создания заказа при обновлении
## 2024-09-23 v6.5.31
- Добавлено логирование ответа от API при неудачном создании заказа
## 2024-09-23 v6.5.30
- Добавлена передача контрагентов с типом ИП
## 2024-09-19 v6.5.29
- Исправлена подписка модуля на событие сохранения заказа
## 2024-09-11 v6.5.28
- Исправлен возврат на предыдущий статус в заказе Bitrix
## 2024-09-02 v.6.5.27
- Исправлена передача изменений по клиентам, отсутствующим в Bitrix
## 2024-08-26 v.6.5.26
- Исправлено удаление модуля
## 2024-08-12 v.6.5.25
- Улучшена генерация каталога с маркированными товарами
## 2024-08-06 v.6.5.24
- Добавлены переводы текста в программе лояльности
- Установка функционала программы лоялности перенесена в настройки модуля
## 2024-08-06 v.6.5.23
- Исправлена ошибка с присвоением externalId при добавлении товара в заказ как разные товарные позиции из CRM
## 2024-07-18 v.6.5.22
- Добавлена передача скидок на торговые позиции в брошенных корзинах
## 2024-07-15 v.6.5.21
- Добавлена передача поля link при выгрузке брошенных корзин
## 2024-06-20 v.6.5.20
- Рефакторинг настроек модуля
## 2024-06-14 v.6.5.19
- Исправление работы программы лояльности при использовании подтверждения списание бонусов по SMS
## 2024-06-05 v.6.5.18
- Добавлена возможность исправления даты регистрации клиентов в CRM
## 2024-06-04 v.6.5.17
- Добавлена передача признака маркировки товара в ICML каталоге
## 2024-04-27 v.6.5.16
- Обновлены аннотации в коде модуля
## 2024-04-23 v.6.5.15
- Добавлена передача услуг через ICML каталог
## 2024-04-18 v.6.5.14
- Исправление работы кнопки "Выгрузка служб доставок"
## 2024-04-03 v.6.5.13
- Исправление присваивания номера заказа к платежу при синхронизации с CRM
## 2024-03-28 v.6.5.12
- Исправлена подстановка домена при генерации каталога
## 2024-03-28 v.6.5.11
- Исправлена ошибка дублирования скидок
## 2024-03-18 v.6.5.10
- Добавлена валидация прав API ключа
## 2024-03-01 v.6.5.9
- Исправлена проверка ФИО при отправке заказа в систему
## 2024-02-05 v.6.5.8
- Удалена возможность выбора свойств с множественным выбором в настройках экспорта каталога
## 2024-01-22 v.6.5.7
- Доработана передача данных интеграционных оплат в систему
## 2024-01-12 v.6.5.6
- Добавлена передача дополнительных свойств товаров через конфигурируемый файл
## 2024-01-09 v.6.5.5
- Исправлен вывод справочников при установке модуля
## 2023-12-29 v.6.5.4
- Исправлена передача адреса доставки
## 2023-12-27 v.6.5.3
- Исправлена ошибка с двойной сериализацией при получении списка пользователей
## 2023-12-21 v.6.5.2
- Добавлена функциональность, позволяющая выгружать из CRM в Bitrix заказы с определенным способом оформления
## 2023-12-19 v.6.5.1
- Исправлено отображение настройки пользовательских полей
## 2023-12-18 v.6.5.0
- Добавлена поддержка функционала пользовательских полей
## 2023-12-13 v.6.4.13
- Исправлена ошибка с получением данных программы лояльности администратора при изменении заказа в админке
## 2023-12-12 v.6.4.12
- Исправлена критическая ошибка при переходе в настройки модуля
## 2023-12-08 v.6.4.11
- Исправлена ошибка при передаче подписки на рекламно-информационные рассылки
## 2023-10-25 v.6.4.10
- Добавлена передача трек-номера в заказе из CRM в Bitrix
## 2023-10-24 v.6.4.9
- Исправлена ошибка при деактивации модуля
## 2023-10-17 v.6.4.8
- Добавлена передача адреса пункта самовывоза в заказе из Bitrix в CRM
## 2023-10-10 v.6.4.7
- Изменена логика передачи адреса доставки в заказе из Bitrix в CRM
## 2023-09-07 v.6.4.6
- Исправлена передача ФИО покупателя в заказе
## 2023-09-01 v.6.4.5
- Удалена поддержка API V4
## 2023-09-01 v.6.4.4
- Исправлены ошибки при работе с программой лояльности
## 2023-08-29 v.6.4.3
- Добавлена валидация валют при настройке модуля
## 2023-08-23 v.6.4.2
- Исправлена ошибка создания заказов для корпоративных клиентов при использовании функционала брошенных корзин
## 2023-08-22 v.6.4.1
- Исправлена передача даты регистрации клиента
## 2023-08-22 v.6.4.0
- Добавлена функция подписки на рекламно-информационные рассылки
## 2023-07-25 v.6.3.20
- Исправлена ошибка некорректного вывода информации о программе лояльности в личном кабинете клиента
## 2023-07-21 v.6.3.19
- Добавлена возможность кастомизации генерации каталога
## 2023-07-20 v.6.3.18
- Исправлена передача брошенных корзин
## 2023-07-04 v.6.3.17
- Добавлен функционал передачи примененного купона в заказе Bitrix в пользовательское поле заказа CRM
## 2023-06-30 v.6.3.16
- Добавлена передача НДС товаров
## 2023-06-22 v.6.3.15
- Исправлено зависание агента выгрузки заказов
## 2023-06-12 v.6.3.14
- Исправлена ошибка при изменении торгового предложения в товаре
## 2023-06-09 v.6.3.13
- Правка генерации при работе со значением Без НДС
## 2023-06-08 v.6.3.12
- Исправление критических ошибок при обновлении модуля и php
## 2023-06-07 v.6.3.11
- Исправление критической ошибки при изменении настроек модуля
## 2023-06-02 v.6.3.10
- Добавлено ограничение по магазинам для типов доставок и оплат
## 2023-06-01 v.6.3.9
- Исправление ошибок генерации ICML каталога при установке модуля
## 2023-06-01 v.6.3.8
- Исправлена ошибка с получением настроек при генерации файла каталога
## 2023-06-01 v.6.3.7
- Исправлено получение основного сайта для записи логов модуля
## 2023-05-19 v.6.3.6
- В настройки добавлена опция деактивации модуля
## 2023-05-18 v.6.3.5
- Добавлен функционал обновления номера телефона, адреса и других полей заказа, связанных с курьерской доставкой
## 2023-04-26 v.6.3.4
- Оптимизирован алгоритм получения истории заказов и клиентов
## 2023-04-10 v.6.3.3
- Исправлено некорректное отображение настроек модуля
- Добавлена поддержка PHP 8.1-8.2
## 2023-04-10 v.6.3.2
- Добавлена возможность экспорта неактивных товаров и торговых предложений
## 2023-04-10 v.6.3.1
- Добавлена валидация свойств товаров и торговых предложений в настройках экспорта
## 2023-04-06 v.6.3.0
- Добавлен функционал передачи данных о содержимом корзины в систему
## 2023-03-30 v.6.2.4
- Добавлен функционал слияния дублей пользователей по истории
## 2023-03-29 v.6.2.3
- Исправление ошибок при установке модуля и выгрузке истории заказов для работы с несколькими сайтами
## 2023-03-27 v.6.2.2
- Добавление значения по умолчанию у элемента выбора контрагента
- Добавлена фильтрация полей по активности
## 2023-03-17 v.6.2.1
- Добавлена передача менеджера при изменении заказа по истории
## 2023-03-10 v.6.2.0
- Добавлена поддержка PHP 8.0
## 2023-02-16 v.6.1.16
- Добавление передачи магазина для корпоративных клиентов
## 2023-01-10 v.6.1.15
- Добавлен фильтр активности менеджеров
## 2023-01-24 v.6.1.14
- Исправление обновления и отправки заказа в црм систему
## 2023-01-10 v.6.1.13
- Изменение метода обновления полей программы лояльности в административной панели
## 2022-12-28 v.6.1.12
- Исправление генерации пароля у корпоративного клиента
- Добавлена проверка на существование пользователя в заказе
## 2022-12-13 v.6.1.11
- Добавление фильтрации не активных справочников и статусов
## 2022-12-02 v.6.1.10
- Удаление управления конфигурацией cron
## 2022-12-01 v.6.1.9
- Исправление ошибки создания клиента без email по истории
- Добавление передачи комментария к статусу заказа в CRM
## 2022-09-30 v.6.1.8
- Исправление ошибки в работе модуля при отмене заказа в Bitrix
## 2022-09-09 v.6.1.7
- Корректировка получения истории удалённых товаров
## 2022-09-07 v.6.1.6
- Корректировка редактирования данных пользователя Bitrix при выгрузке истории изменений
## 2022-08-22 v.6.1.5
- Корректировка получения НДС товаров в каталоге
## 2022-07-21 v.6.1.4
- Исправление ошибки при записи товаров в HL блок лояльности
## 2022-07-18 v.6.1.3
- Исправление работы модуля при попытке регистрации в программе лояльности уже существующего в ней клиента
- Исправление тестов
## 2022-07-01 v.6.1.2
- Исправление передачи корпоративных клиентов
## 2022-06-28 v.6.1.1
- Исправлена ошибка при удалении модуля
## 2022-06-28 v.6.1.0
- Исправлены ошибки дублирования скидок при обмене данными
- Скорректирована работа с общей скидкой по заказу, она более не переносится в скидку по товару в CRM
- Скорректирована передача бонусов и персональных скидок
- Исправлены типы полей скидок в HL-блоке программы лояльности
## 2022-06-17 v.6.0.6
- Замена устаревшего jQuery метода
## 2022-06-14 v.6.0.5
- Исправление автозагрузки классов для мультисайта
- Исправление страницы экспорта каталога
## 2022-05-18 v.6.0.4
* Исправление передачи местоположения в адресе доставки по истории
## 2022-05-13 v.6.0.3
* Исправление автозагрузки классов
## 2022-04-18 v.6.0.2
* Исправление конвертирования строк из utf-8
* Исправление редактирования свойств заказа в 1С Битрикс
* Добавлена передача параметра site для метода работы с корпоративными клиентами
* Добавлена передача параметра site для метода получения списка заказов
## 2022-04-08 v.6.0.1
* Исправлены ошибки подключения кастомных классов
## 2021-11-12 v.6.0.0
* Добавлена поддержка программы лояльности
## 2022-02-03 v.5.8.5
* Исправление ошибка восстановления отсутствующей отгрузки во время выгрузки истории из системы
* Исправлена ошибка обработки магазинов с кодами, содержащими ".", в настройках модуля
* Исправлен баг выгрузки заказов, связанный с неверным указанием namespace для LocationTable
* При обмене данными итоговая стоимость доставки теперь указывается принудительно
* Исправлена ошибка генерации icml для проиндексированных каталогов с простыми товарами
* Исправлена ошибка выгрузки клиентов, при которой одни и те же клиенты могли попасть в лист выгрузки повторно
* Исправления в документации
## 2021-10-15 v.5.8.4
* Исправление некорректной генерации каталога при повторных запусках генерации
## 2021-10-09 v.5.8.3
* Исправлено определение пути к файлу ICML-каталога
## 2021-09-08 v.5.8.2
* Оптимизирована работа с памятью в генераторе каталога
* Исправлены ошибки в генераторе каталога
## 2021-09-08 v.5.8.1
* Оптимизирована работа генератора icml каталога
* В генератор каталога добавлена возможность указывать свойства выгрузки одновременно для простых товаров и товаров с торговыми предложениями
* Исправлена ошибка выгрузки заказов из неподключенного к CRM магазина при использовании нескольких сайтов на одной лицензии
* Изменена логика обмена оплатами: для интеграционных оплат дата оплаты больше не передается из Битрикса
## 2021-08-19 v.5.8.0
* Добавлена синхронизация ответственного менеджера в заказе
* Исправлена ошибка выгрузки заказов с корпоративными клиентами, уже присутствующими в системе
* Исправлена ошибка выгрузки остатков при наличии более 100 складов в Битрикс
## 2021-06-28 v.5.7.1
* Исправлена ошибка в методе получения типов интеграционных оплат RetailcrmConfigProvider::getIntegrationPaymentTypes().
## 2021-05-31 v.5.7.0
* Переработан генератор ICML каталога:
- генератор использует потоковую запись в файл через `XMLWriter`;
- по умолчанию опция выгрузки каталога в момент установки модуля отключена;
- код генератора каталога теперь использует автолоадер Битрикса.
* Скидка на позицию больше не учитывается в заказе при установке произвольной цены для позиции.
## 2021-01-14 v.5.6.2
* Исправлено формирование картинок в ICML при включеном CDN
* Убрана некорректная запись внешнего идентификатора платежа для новых платежей по истории
* Добавлена проверка на длину email при отправке в систему
## 2020-12-15 v.5.6.1
* Обновлено наименование бренда
## 2020-11-24 v.5.6.0
* Добавлена возможность активации онлайн-консультанта
* Обновлен список стран
* Улучшена синхронизация ФИО в истории
* Добавлен перевод на английский язык
* Заменены некорректные символы в списке стран
## 2020-10-14 v.5.5.3
* Исправлено затирание полей при создании заказа по агенту
## 2020-10-01 v.5.5.2
* Исправлена ошибка, препятствовавшая обновлению модуля
* Исправлена неверная кодировка в настройках модуля
## 2020-09-28 v.5.5.1
* Исправлена ошибка переноса полей в RetailCRM для заказов с интеграционными доставками
## 2020-09-08 v.5.5.0
* Добавлена возможность ручной выгрузки заказов в CRM
## 2020-09-02 v.5.4.6
* Исправлена ошибка установки модуля при отсутствии заказов в Битрикс
## 2020-09-02 v.5.4.5
* Исправлена ошибка установки статуса оплаты в заказе
## 2020-08-26 v.5.4.4
* Исправлена ошибка при установке модуля
## 2020-08-25 v.5.4.3
* Исправлена ошибка с некорректным ID товара при редактировании заказа
* Исправлены опечатки в API-клиенте RetailCRM
* Добавлена фильтрация изменений истории по текущему API-ключу
## 2020-07-24 v.5.4.2
* Исправлена кодировка
## 2020-07-24 v.5.4.1
* Оптимизирован генератор каталога
* Передача статуса оплаты и статуса отгрузки заказа в Битрикс
* Предупреждение в случае обнаружения несовместимых настроек
* Запрещенные для редактирования поля в заказах с интеграционной доставкой более не передаются при редактировании заказа из Битрикс
## 2020-07-14 v.5.4.0
* Добавлена поддержка функционала смены клиента
## 2020-05-04 v.5.3.2
* Исправлена кодировка в настройках модуля
## 2020-04-27 v.5.3.1
* Добавлена локализация свойств при генерации каталога
## 2020-04-23 v.5.3.0
* Добавлена поддержка корпоративных клиентов
## 2020-01-09 v.5.2.5
* Добавлена передача "externalIds" у позиций товаров в заказе
* Добавлено разделение поля строение/корпус на два отдельных
## 2019-12-20 v.5.2.4
* Добавлена обработка изменения номера заказа по истории
## 2019-11-1 v.2.5.3
* Исправление при обработке полученных изменений о контрагенте
* При обработки истории по клиентам добавлены кастомные поля
* Исправлены мелкие ошибки и недочеты
## 2019-09-17 v.2.5.2
* Поддержка функции добавления одинакового товара в заказ как разные товарные позиции из CRM
## 2019-08-28 v.2.5.1
* Исправление генерации единиц измерения
## 2019-07-26 v.2.5.0
* Исправление создание дублей заказов
## 2019-07-18 v.2.4.9
* Добавлен поиск города по почтовому индексу при выгрузке истории изменений
## 2019-07-01 v.2.4.8
* Исправлена отправка пустого заказа при удалении заказа из СMS
* Изменена логика генерации внешнего идентификатора оплат для сохранения его уникальности в пределах системы
## 2019-03-28 v.2.4.7
* Добавлено удаление в системе типа цены у товара для неактивного типа цены на сайте
## 2019-03-28 v.2.4.6
* Исправление проверки информации о контрагенте при обработке полученных изменений
## 2019-03-28 v.2.4.5
* Обновлен конфигурационный файл для валидатора
## 2019-01-22 v.2.4.4
* Добавлена обработка клиентов с внешним кодом в виде хэша при выгрузке истории изменений
## 2019-01-15 v.2.4.3
* Добавлена выгрузка НДС в ICML каталоге
* Улучшена выгрузка истории изменений заказа
* Улучшена настройка выгрузки типов цен
## 2018-12-26 v.2.4.2
* Добавлена конвертация закупочной цены при выгрузке заказа
* Исправлен файл переводов для выгрузки каталога
* В настройку экспорта каталога добавлена настройка максимального количества торговых предложений у товара
* Исправлен вызов обработчика сохранения оплаты при создании заказа
## 2018-11-02 v.2.4.1
* Исправлены ошибки в файле options.php
## 2018-11-02 v.2.4.0
* Изменена привязка на событие сохранения заказа. Используется привязка к событию "OnSaleOrderSaved"
* Исправлено удаление событий модуля при удалении модуля интеграции из CMS
* Добавлено подключение файла Logger.php при удалении модуля
* Изменен механизм определения протокола, с которым работает сайт. Используется метод isHttps() 1С-Bitrix
* Исправлена передача веса товара при отправке габбаритов заказа
## 2018-10-29 v.2.3.14
* Добавлено подключение файла RCrmActions.php при удалении модуля
## 2018-10-25 v.2.3.13
* Добавлен функционал для активации модуля в маркетплейсе RetailCRM
* Исправлен баг при генерации каталога с подстановкой схемы
## 2018-10-17 v.2.3.12
* Исрпавлена некорректная выгрузка остатков по складам
* Исправлена отправка габаритов товаров в заказах
## 2018-10-04 v.2.3.11
* Добавлен учет настроек часового пояса при создании заказа
* Устранено удаление событий изменения оплат при переводе выгрузки на агент
* Добавлена возможность указать свойство в настройках экспорта, из которого будет подставляться картинка, если отсутствует в "Подробно" и "Анонс"
* Добавлена подстановка домена в ссылках каталога в зависимости от пренадлежности инфоблока к сайту
## 2018-09-26 v.2.3.10
* Исправлена некорректная генерация скрипта UA
* Исправлена выгрузка остатков, если для товара указано более 50 складов
* Добавлен перехват исключений при сохранении заказа в Битрикс
## 2018-08-08 v.2.3.9
* Устранено резервирование товара в отмененном заказе
* Исправлен некорректный расчет скидки на товар
## 2018-07-16 v.2.3.8
* Добавлен рассчет стоимости товара с учетом наценки
* Добавлена выгрузка картинок товара, если отсутствует картинка торгового предложения
* Заменены устаревшие методы в API клиенте
## 2018-06-13 v.2.3.7
* Добавлена выгрузка штрихкодов в ICML
* Добавлена выгрузка картинок торговых предложений в ICML
* Улучшена передача типа доставки в заказе
* Добавлена проверка некоторых настроек при передаче заказа
## 2018-05-23 v.2.3.6
* Улучшена выгрузка свойств товаров типа "справочник"
* Добавлена настройка выгрузки габаритов и веса в заказе
* Добавлена совместимость натройки экспорта для Google Chrome
* Исправлена ошибка при выгрузке истории с пустым городом
* Добавлены проверки на существование модуля Highloadblock
* Исправлен баг с отправкой пустого заказа при удалении в 1С-Битрикс
## 2018-03-22 v.2.3.5
* В настройку экспорта добавлена настройка свойств типа "справочник"(highloadblock)
* Добавлена проверка необходимости резервации товаров при выгрузке заказов из RetailCRM
* Исправлен вызов рекурсивного метода в RCrmActions
* Добавлены недостающие поля retailcrm.json
## 2018-02-27 v.2.3.4
* Добавлена передача веса и габаритов в заказе
* Добавлена проверка существования fuser у корзины товаров перед сохранением
* Добавлено снятие резерва с товаров при отмене заказа в CRM
* Исправлена выборка данных для UA, когда id заказа не совпадает с номером
* Исправлены мелкие баги
## 2018-01-23 v.2.3.3
* Исправлен баг с передачей номера заказа
* Исправлены мелкие ошибки и недочеты
## 2017-12-27 v.2.3.2
* Исправлен баг с рассчетом суммы заказа
* Добавлен перехват исключения при редактировании отгруженной доставки
## 2017-12-27 v.2.3.1
* Исправлены мелкие баги и недочеты
## 2017-12-04 v.2.3.0
* Добавлен выбор валюты в настройках, для выгрузки заказов из CRM
* Исправлена выборка свойств заказа
* Устранен баг в настройках соответствия полей свойств заказа
* Улучшена механика выгрузки заказов из CRM
## 2017-11-20 v.2.2.10
* Устранен баг с созданием чеков
* Улучшен механизм работы с оплатами
## 2017-11-13 v.2.2.9
* Исправлены ошибки подключения кастомных классов
* Улучшена обработка истории
## 2017-11-01 v.2.2.8
* Исправлены баги пакетной выгрузки
* Исправлена ошибка при работе на php7.1
## 2017-10-26 v.2.2.7
* Исправлен баг при работе с одним сайтом
## 2017-10-25 v.2.2.6
* Доработана система синхронизации оплат
* Исправлены ошибки в истории заказов
## 2017-09-22 v.2.2.5
* Теперь учитываются группы доставки
* Изменен алгоритм передачи оплат
* Исправлено задваивание количества товаров в отгрузке
* Небольшие исправления
## 2017-09-07 v.2.2.4
* Исправлена работа истории пользователей
* Убраны события для старого API
## 2017-09-04 v.2.2.3
* Исправлена работа истории
## 2017-09-04 v.2.2.2
* Исправлен инсталлятор
* Изменена передача данных по пользователю
## 2017-09-01 v.2.2.1
* Добавлена встроенная функция retailCrmApiResult
* Добавлен триггерный вариант истории изменений
* Исправлены ошибки
## 2017-08-21 v.2.2.0
* API V5
* Возможность выбора версии API
* Добавлена возможность выгрузки остатков в разрезе складов
* Добавлена возможность выгрузки типов цен
* Добавлена базовая интеграция Daemon Collector
* Добавлена интеграция с Universal Analytics
* Доработана логика работы встроенных функций для модификации данных
* Исправлены ошибки
## 2016-12-09 v.2.1.2
* Добавлены единицы измерения в экспорте каталога
* Исправлены пути в include
* Добавлено время нового формата в валидатор
* Исправлено неверное изменение типа заказа по истории
* Исправлена ошибка с некорректным разбиением ФИО
* Небольшие исправления по коду
## 2016-11-15 v.2.1.1
* Исправлена проблема с отсутствием в настройках доставок
* Небольшие исправления
## 2016-10-31 v.2.1.0
* Добавлена передача адреса из карточки клиента в RetailCRM
* Добавлено больше информации в журнале битрикса и дополнительное логирование
* Небольшие исправления
## 2016-10-25 v.2.0.9
* Исправлена ошибка с неверной кодировкой ФИО
* Исправлена ошибка с отсутствием местоположения
## 2016-10-20 v.2.0.8
* Исправлена ошибка с отсутствием LID
* Изменены методы для совместимости с ранними версиями sale 16 версии
## 2016-10-20 v.2.0.7
* Исправлена ошибка с недобавлением товара в заказ по истории
* Исправлена ошибка с недобавлением сервиса доставки в црм
## 2016-10-14 v.2.0.6
* Оптимизация History
* Исправлены ошибки
## 2016-10-11 v.2.0.5
* Исправлена ошибка при обработке Ф.И.О.
* Исправлена ошибка с неверной кодировкой свойств
* Исправлена ошибка формирования списка статусов
## 2016-10-06 v.2.0.4
* Оптимизация History
* Исправлена ошибка выгрузки доставок при установке
## 2016-10-04 v.2.0.3
* fix состава отгрузки
## 2016-10-04 v.2.0.2
* Исправлены ошибки
## 2016-10-03 v.2.0.1
* Исправлены ошибки
## 2016-09-12 v.2.0.0
* API V4
* Переход на ядро d7
* История изменений по клиентам
* Множественный флаг отмены заказа
## 2015-11-09 v.1.1.3
* Добавлено логгирование в файл для приходящей из црм и уходящей в црм информации
* Изменен механизм добавления товара в заказ
* Возможность добавить товар в заказ, который есть в црм, но нет на сайте
* Изменил логику выбора товаров для выгрузки в xml
* Появилась возможность перевести History на триггер
* Исправлены ошибки
## 2015-05-18 v.1.1.2
* Добавлена возможность изменять файлы основных классов(ICMLLoader и ICrmOrderActions) и экспорт каталога без потери обновлений
* Исправлены мелкие ошибки
## 2015-03-19 v.1.1.1
* Исправлена ошибка, связанная с версионностью PHP в History.
* Добавлена выгрузка закупочной цены вместе с заказом
* Добавлены индивидуальные настройки для профилей выгрузки
* Исправлены мелкие ошибки
## 2015-02-20 v.1.1.0
* Модуль переведен на новую версию API
* Добавлена поддержка реквизитов юр. лиц
* Добавлена многосайтовость
* Добавлена выборочная загрузка заказов из настроек модуля
* Оптимизирована загрузка старых заказов
* Исправлена ошибка с удалением id товара в заказе
* Исправлена ошибка пустого $_SERVER['SERVER_NAME'] при экспорте каталога
* Исправлена ошибка с неправильной скидкой у товара при наличии копеек
* Исправлена ошибка с пропаданием автоматических служб доставок из настроек модуля
* Исправлена неправильная выгрузка сервисов для служб доставок
* Исправлено не правильное определение местоположения
* Рефакторинг модуля
## 2015-02-13 v.1.0.16
* Все действия агента происходят от имени retailcrm
## 2015-02-12 v.1.0.16
* Исправлен агент
* Исправлены ошибки с запоминанием пользователя
* Исправлена ошибка с выходом пользователя из системы
* Исправлена ошибка хождения пользователя под другим логином
* Исправлены проблема с fix-external-ids
* Добавлена возможность получения скидки из CRM в Битрикс

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 RetailDriver LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

51
Makefile Executable file
View file

@ -0,0 +1,51 @@
ROOT_DIR=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
test: prepare_module
composer tests
prepare_module:
composer pre-module-install
deps:
ifneq ($(NOT_USE_VENDOR),1)
composer install
endif
install_bitrix: download_bitrix
@echo "===== Installing Bitrix..."
@php bin/bitrix-install db_type
@php bin/bitrix-install requirement
@php bin/bitrix-install db_create
@php bin/bitrix-install main_module
@php bin/bitrix-install module
@php bin/bitrix-install admin
@php bin/bitrix-install load_module
@php bin/bitrix-install load_module_action
@php bin/bitrix-install finish
download_bitrix:
ifeq ("$(wildcard $(BITRIX_PATH)/bitrix/php_interface/dbconn.php)","")
wget --progress=dot -e dotbytes=10M -O /tmp/$(BITRIX_EDITION).tar.gz https://www.1c-bitrix.ru/download/$(BITRIX_EDITION).tar.gz
mkdir -p $(BITRIX_PATH)
chmod -R 777 $(BITRIX_PATH)
tar -xf /tmp/$(BITRIX_EDITION).tar.gz -C $(BITRIX_PATH)
rm /tmp/$(BITRIX_EDITION).tar.gz
endif
build_release:
ifneq ($(LAST_TAG),$(RELEASE_TAG))
git diff --name-status $(LAST_TAG) HEAD > $(ROOT_DIR)/release/diff
php bin/build-release
bash bin/build $(CURRENT_VERSION) $(ROOT_DIR)/release/
else
@exit 0
endif
cleanup:
@rm -rf $(ROOT_DIR)/release/$(CURRENT_VERSION)
@rm $(ROOT_DIR)/release/$(CURRENT_VERSION).tar.gz
run_local_tests:
docker-compose up -d --build
docker exec app_test make install_bitrix deps test
docker-compose down

View file

@ -1,15 +1,22 @@
[![Build Status](https://github.com/retailcrm/bitrix-module/workflows/ci/badge.svg)](https://github.com/retailcrm/bitrix-module/actions)
[![GitHub release](https://img.shields.io/github/release/retailcrm/bitrix-module.svg?logo=github)](https://github.com/retailcrm/bitrix-module/releases)
[![Coverage](https://img.shields.io/codecov/c/gh/retailcrm/bitrix-module/master.svg?logo=codecov)](https://codecov.io/gh/retailcrm/bitrix-module)
[![PHP version](https://img.shields.io/badge/PHP->=8.0-blue.svg?logo=php)](https://php.net/)
Bitrix module
=============
Bitrix module for interaction with [IntaroCRM](http://www.intarocrm.com) through [REST API](http://docs.intarocrm.ru/rest-api/).
Bitrix module for interaction with [RetailCRM](https://www.retailcrm.ru)
Module allows:
* Send to IntaroCRM new orders
* Configure relations between dictionaries of IntaroCRM and Bitrix (statuses, payments, delivery types and etc)
* Generate [ICML](http://docs.intarocrm.ru/index.php?n=Пользователи.ФорматICML) (IntaroCRM Markup Language) for catalog loading by IntaroCRM
* Exchange the orders with RetailCRM
* Configure relations between dictionaries of RetailCRM and Bitrix (statuses, payments, delivery types and etc)
* Generate [ICML](https://docs.retailcrm.ru/ru/Developers/modules/ICML) (Intaro Markup Language) for catalog loading by RetailCRM
Installation
-------------
You should install module through [Bitrix.Marketplace](http://marketplace.1c-bitrix.ru).
You should install module through [Bitrix.Marketplace](http://marketplace.1c-bitrix.ru/solutions/intaro.retailcrm/).
[Setup guide](https://docs.retailcrm.ru/Users/Integration/SiteModules/1CBitrix)

58
bin/bitrix-install Executable file
View file

@ -0,0 +1,58 @@
#!/usr/bin/env php
<?php
set_time_limit(0);
if (ini_get('memory_limit') > 0 && (int)ini_get('memory_limit') < 784) {
ini_set('memory_limit', '784M');
}
$_SERVER['DOCUMENT_ROOT'] = getenv('BITRIX_PATH') ? getenv('BITRIX_PATH') : '/var/www/html';
define("B_PROLOG_INCLUDED", true);
define("DEBUG_MODE", true);
if (!file_exists($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/install/wizard/wizard.php')) {
throw new \RuntimeException('Bitrix`s install files is not exists');
}
ob_start();
require_once $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/install/wizard/wizard.php';
ob_clean();
require_once __DIR__ . '/../helpers/installation/ExtendedCreateModulesStep.php';
require_once __DIR__ . '/../helpers/installation/Installer.php';
$installer = new Installer();
$step = $argv[1];
switch ($step) {
case 'db_type':
$installer->dbTypeStep();
exit(0);
case 'requirement':
$installer->requirementStep();
exit(0);
case 'db_create':
$installer->createDBStep();
exit(0);
case 'main_module':
$installer->createModulesStep(true);
exit(0);
case 'module':
$installer->createModulesStep();
exit(0);
case 'admin':
$installer->createAdminStep();
exit(0);
case 'load_module':
$installer->createLoadModuleStep();
exit(0);
case 'load_module_action':
$installer->createLoadModuleActionStep();
exit(0);
case 'finish':
$installer->createFinishStep();
exit(0);
}

13
bin/bitrix-version Normal file
View file

@ -0,0 +1,13 @@
#!/usr/bin/env php
<?php
set_time_limit(0);
if (ini_get('memory_limit') > 0 && (int) ini_get('memory_limit') < 784) {
ini_set('memory_limit', '784M');
}
require_once __DIR__ . '/../intaro.retailcrm/install/version.php';
echo $arModuleVersion['VERSION'];
exit(0);

46
bin/build Normal file
View file

@ -0,0 +1,46 @@
#!/bin/bash
# $1 -- folder name to pack;
version=$1
dir=${2-$PWD}
cd $dir
date=`date +"%Y-%m-%d %H:%M:%S"`
if [ ! -d "$version/install" ]; then
mkdir -p "./$version/install"
echo "Created a folder \"install\""
fi
if [ ! -f "$version/install/version.php" ]; then
touch "./$version/install/version.php"
echo "Created a file \"version.php\""
fi
echo "
<?
\$arModuleVersion = array(
\"VERSION\" => \"$version\",
\"VERSION_DATE\" => \"$date\"
);
" > "./$version/install/version.php"
echo "Update version and date in the file \"version.php\""
for i in `find ./"$version" -type f -name '*.*'`; do
encoding=`file -b --mime-encoding "$i"`
if [ "$encoding" != "iso-8859-1" ] && [ "$encoding" != "us-ascii" ] && [ "$encoding" != "binary" ]; then
echo "$i: converting from $encoding to cp1251"
result=$(iconv -f $encoding -t "cp1251" $i -o $i.cp1251 2>&1 > /dev/null)
if [ ! -z "$result" ]; then
echo "Errors in file $i"
echo $result
exit 255
fi
mv $i.cp1251 $i
fi
done
echo "Encoding the file has changed"
tar -czf $version.tar.gz $version
echo "Update has been successfully packaged"

38
bin/build-release Normal file
View file

@ -0,0 +1,38 @@
#!/usr/bin/env php
<?php
error_reporting(E_ALL ^ E_DEPRECATED);
require_once __DIR__ . '/../helpers/release/ReleaseBuilder.php';
require_once __DIR__ . '/../helpers/release/ModifiedFile.php';
require_once __DIR__ . '/../intaro.retailcrm/install/version.php';
define('RELEASE_DIR', __DIR__ . '/../release/');
define('ORIGINAL', __DIR__ . '/../intaro.retailcrm/');
if (!file_exists(RELEASE_DIR . 'diff')) {
print('Diff file does not exists');
exit(255);
}
$handle = fopen(RELEASE_DIR . 'diff', 'r');
if (!$handle) {
exit(255);
}
$modifiedFiles = [];
while (($buffer = fgets($handle)) !== false) {
$modifiedFiles[] = new ModifiedFile($buffer);
}
try {
$builder = new ReleaseBuilder($modifiedFiles, $arModuleVersion['VERSION']);
$builder->build();
} catch(\Exception $exception) {
print($exception->getMessage());
exit(255);
}
exit(0);

6
bin/enable_debugging Normal file
View file

@ -0,0 +1,6 @@
#!/usr/bin/env php
<?php
$file = $argv[1] . '/bitrix/.settings.php';
$params = include $file;
$params['exception_handling']['value']['debug'] = true;
file_put_contents($file, "<?php\nreturn " . var_export($params, true) . ';', LOCK_EX);

28
composer.json Executable file
View file

@ -0,0 +1,28 @@
{
"name": "retailcrm/bitrix-module",
"scripts": {
"pre-module-install": "cp -R intaro.retailcrm $BITRIX_PATH/bitrix/modules",
"tests": "vendor/bin/phpunit -c phpunit.xml.dist --whitelist=$BITRIX_PATH/bitrix/modules/intaro.retailcrm"
},
"description": "Integration module for Bitrix & RetailCRM",
"license": "MIT",
"type": "bitrix-module",
"authors": [
{
"name": "RetailDriver LLC",
"email": "integration@retailcrm.ru"
}
],
"require": {
"ext-json": "*",
"ext-mbstring": "*",
"ext-tokenizer": "*",
"ext-xmlwriter": "*"
},
"require-dev": {
"phpunit/phpunit": "^8.5",
"vlucas/phpdotenv": "^3.3",
"mockery/mockery" : "^1.0",
"fakerphp/faker": "^1.21"
}
}

1982
composer.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,41 @@
### Кастомизация модуля
В модуле доступна кастомизация классов, без потери модифицированного кода при обновлении.
Для этого требуется создать копию необходимого для кастомизации файла и расположить его директории
`bitrix/php_inteface/retailcrm`
Имеется возможность кастомизации следующих файлов:
* RestNormalizer.php
* Logger.php
* Client.php
* RCrmActions.php
* RetailCrmUser.php
* RetailCrmICML.php
* RetailCrmInventories.php
* RetailCrmPrices.php
* RetailCrmCollector.php
* RetailCrmUa.php
* RetailCrmEvent.php
* RetailCrmHistory_v5.php
* RetailCrmOrder_v5.php
* ApiClient_v5.php
С версии 6.3.19 доступна кастомизация ICML, файлы которого расположены в модуле по пути `lib/icml`:
* xmlofferbuilder.php
* xmlofferdirector.php
* icmlwriter.php
* queryparamsmolder.php
* settingsservice.php
* xmlcategorydirector.php
* xmlcategoryfactory.php
* icmldirector.php
Кастомизированные файлы каталога также должны быть расположены в директории `bitrix/php_inteface/retailcrm`
Например, кастом оригинального файла `lib/icml/xmlofferbuilder.php` будет иметь путь `bitrix/php_interface/retailcrm/xmlofferbuilder.php`
Для кастомизации файлов, в названии которых есть используемая версия API,
создаются файлы с названием без указания версии, например - `RetailCrmHistory.php`.
После создания копии файла с классом в директории `bitrix/php_interface/retailcrm`
модуль будет использовать кастомизированный класс, в котором можно вносить изменения в его методы.

View file

@ -0,0 +1,11 @@
### Настройки активности модуля
В версии 6.3.6 в настройки модуля добавлена опция деактивации модуля.
Для деактивации модуля в настройках необходимо выбрать опцию ***Деактивировать модуль***
Данная опция необходима для кейсов:
* проверка работоспособности Bitrix в целом, с исключением внешних факторов;
* при некорректной передачи данных из CMS в CRM и обратно.
При деактивации модуля, данные передаваться не будут, но все пользовательские настройки будут сохранены.

1
doc/README.md Normal file
View file

@ -0,0 +1 @@
# Developers documentation

34
docker-compose.yml Executable file
View file

@ -0,0 +1,34 @@
version: '3'
services:
bitrix:
container_name: app_test
build: ./.docker
env_file:
- .env
environment:
- MYSQL_SERVER=${DB_BITRIX_HOST}
- MYSQL_DATABASE=${DB_BITRIX_NAME}
- MYSQL_USER=${DB_BITRIX_LOGIN}
- MYSQL_PASSWORD=${DB_BITRIX_PASS}
- BITRIX_PATH=${BITRIX_PATH}
depends_on:
- mysql
ports:
- '8080:80'
links:
- mysql
volumes:
- ./:/bitrix-module
- ./.docker/php.ini:/usr/local/etc/php/conf.d/z-bitrix.ini
- ./tmp:/tmp
mysql:
env_file:
- .env
image: mysql:5.6
ports:
- '3306:3306'
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=${DB_BITRIX_NAME}
- MYSQL_USER=${DB_BITRIX_LOGIN}
- MYSQL_PASSWORD=${DB_BITRIX_PASS}

View file

@ -0,0 +1,15 @@
<?php
/**
* Class ExtendedCreateModulesStep
*/
class ExtendedCreateModulesStep extends CreateModulesStep
{
/**
* @param string $str
*/
public function SendResponse($str)
{
return;
}
}

View file

@ -0,0 +1,345 @@
<?php
ob_start();
require_once $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/install/wizard/wizard.php';
ob_clean();
/**
* Class Installer
*/
class Installer
{
private $dbName;
private $dbHost;
private $dbUser;
private $dbPass;
/**
* Installer constructor.
*/
public function __construct()
{
$this->deleteDefaultInstallation();
$this->dbHost = getenv('DB_BITRIX_HOST') ? getenv('DB_BITRIX_HOST') : 'localhost';
$this->dbName = getenv('DB_BITRIX_NAME') ? getenv('DB_BITRIX_NAME') : 'bitrix';
$this->dbUser = getenv('DB_BITRIX_LOGIN') ? getenv('DB_BITRIX_LOGIN') : 'bitrix';
$this->dbPass = getenv('DB_BITRIX_PASS') ? getenv('DB_BITRIX_PASS') : 'bitrix';
}
/**
* @param string $value
*/
private function setCurrentStepID($value)
{
$this->setRequestParam('CurrentStepID', $value);
}
/**
* @param string $value
*/
private function setNextStepID($value)
{
$this->setRequestParam('NextStepID', $value);
}
/**
* @param string $value
*/
private function setPreviousStepID($value)
{
$this->setRequestParam('PreviousStepID', $value);
}
/**
* @param string $key
* @param mixed $value
* @return self
*/
private function setRequestParam($key, $value)
{
$_REQUEST[$key] = $value;
$_POST[$key] = $value;
return $this;
}
/**
* Execute installation step
* @return void
*/
protected function request()
{
$this->setParams();
$steps = array(
CheckLicenseKey::class,
DBTypeStep::class,
RequirementStep::class,
CreateDBStep::class,
ExtendedCreateModulesStep::class,
CreateAdminStep::class,
SelectWizardStep::class,
LoadModuleStep::class,
LoadModuleActionStep::class,
SelectWizard1Step::class
);
$wizard = new CWizardBase(
str_replace("#VERS#", SM_VERSION, InstallGetMessage("INS_TITLE")),
$package = null
);
$wizard->AddSteps($steps);
$wizard->SetReturnOutput(true);
$wizard->Display();
foreach ($wizard->GetWizardSteps() as $step) {
if ($step->GetErrors()) {
foreach ($step->GetErrors() as $error) {
$this->println(sprintf('error: %s', mb_convert_encoding($error[0], 'UTF-8', 'windows-1251')));
}
}
}
}
/**
* Set request params for installation steps
* @return void
*/
private function setParams()
{
$params = array(
'__wiz_agree_license' => 'Y',
'__wiz_dbType' => 'mysql',
'__wiz_lic_key_variant' => '',
'__wiz_utf8' => 'Y',
'__wiz_create_user' => 'N',
'__wiz_host' => $this->dbHost,
'__wiz_user' => $this->dbUser,
'__wiz_password' => $this->dbPass,
'__wiz_database' => $this->dbName,
'__wiz_create_database' => 'N',
'__wiz_create_database_type' => 'innodb',
'__wiz_root_user' => '',
'__wiz_root_password' => '',
'__wiz_file_access_perms' => '0644',
'__wiz_folder_access_perms' => '0755',
'__wiz_login' => 'admin',
'__wiz_admin_password' => 'admin123',
'__wiz_admin_password_confirm' => 'admin123',
'__wiz_email' => 'admin@mail.com',
'__wiz_user_name' => 'FirstName',
'__wiz_user_surname' => 'LastName',
'__wiz_selected_wizard' => 'bitrix.eshop:bitrix:eshop',
);
foreach ($params as $code => $param) {
$this->setRequestParam($code, $param);
}
}
/**
* Step of select database type
* @return self
*/
public function dbTypeStep()
{
$this->setCurrentStepID('select_database');
$this->setNextStepID('requirements');
ob_start();
$this->request();
ob_clean();
$this->println('Selected database type');
return $this;
}
/**
* Requirements step
* @return self
*/
public function requirementStep()
{
$this->setCurrentStepID('requirements');
$this->setNextStepID('create_database');
$this->request();
$this->println('Requirements step');
return $this;
}
/**
* Create database step
* @return self
*/
public function createDBStep()
{
$this->setCurrentStepID('create_database');
$this->setNextStepID('create_modules');
$this->request();
$this->println('Database setup');
return $this;
}
/**
* Installation modules step
* @param bool $isMain
* @return self
*/
public function createModulesStep($isMain = false)
{
$threeSteps = array(
'utf8',
'database',
'files'
);
if ($isMain) {
$modules = array(
'main' => $threeSteps
);
} else {
$modules = array(
'abtest' => $threeSteps,
'bitrix.eshop' => $threeSteps,
'catalog' => $threeSteps,
'compression' => $threeSteps,
'conversion' => $threeSteps,
'currency' => $threeSteps,
'fileman' => $threeSteps,
'form' => $threeSteps,
'highloadblock' => $threeSteps,
'iblock' => $threeSteps,
'pull' => $threeSteps,
'rest' => $threeSteps,
'sale' => $threeSteps,
'scale' => $threeSteps,
'search' => $threeSteps,
'security' => $threeSteps,
'sender' => $threeSteps,
'storeassist' => $threeSteps,
'translate' => $threeSteps,
'ui' => $threeSteps,
'remove_mysql' => array(
array('single')
),
'remove_mssql' => array(
array('single')
),
'remove_oracle' => array(
array('single')
),
'remove_misc' => array(
array('single')
),
'__finish' => array(
array('single')
)
);
}
$this->setCurrentStepID('create_modules');
foreach ($modules as $module => $steps) {
foreach ($steps as $step) {
$this->setRequestParam('__wiz_nextStep', $module);
$this->setRequestParam('__wiz_nextStepStage', $step);
$this->request();
$this->println(sprintf('%s module install, step %s', $module, $step));
}
}
return $this;
}
/**
* Create admin interface step
* @return self
*/
public function createAdminStep()
{
$this->setCurrentStepID('create_admin');
$this->request();
$this->println('Setup admin');
return $this;
}
/**
* Load modules step
* @return self
*/
public function createLoadModuleStep()
{
$this->setCurrentStepID('load_module');
$this->request();
$this->println('Load modules');
return $this;
}
/**
* Load modules action step
* @return self
*/
public function createLoadModuleActionStep()
{
$this->setCurrentStepID('load_module_action');
$this->request();
$this->println('Load modules action');
return $this;
}
/**
* Finish install step
* @return self
*/
public function createFinishStep()
{
$this->setCurrentStepID('finish');
$this->request();
$this->println('Installation finish');
return $this;
}
/**
* Remove code for web install
* @return void
*/
private function deleteDefaultInstallation()
{
$data = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/install/wizard/wizard.php');
$newData = preg_replace('/\$wizard= new CWizardBase.+$/', '', $data);
file_put_contents($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/install/wizard/wizard.php', $newData);
}
/**
* @param string $string
* @return void
*/
private function println($string)
{
print($string);
print(PHP_EOL);
}
}

View file

@ -0,0 +1,125 @@
<?php
/**
* Class ModifiedFile
*/
class ModifiedFile
{
/** @var string */
const ADDED = 'A';
/** @var string */
const DELETED = 'D';
/** @var string */
const MODIFIED = 'M';
/** @var string */
const RENAMED = 'R';
/** @var string */
const MODULE_ID = 'intaro.retailcrm';
/** @var string */
const DESCRIPTION = 'description.ru';
/** @var string */
const VERSION = 'install/version.php';
/** @var string */
protected $filename;
/** @var string */
protected $oldFilename;
/** @var string */
protected $modificator;
/** @var int */
protected $percent;
/**
* ModifiedFile constructor.
* @param string $source
*/
public function __construct($source)
{
$params = explode("\t", trim($source));
$this->filename = $params[1];
$this->modificator = $params[0][0];
if (strlen($params[0]) > 1) {
$this->percent = (int) substr($params[0], 1);
}
if (count($params) >= 3) {
$this->filename = $params[2];
$this->oldFilename = $params[1];
}
}
/**
* @return bool
*/
public function isAdded()
{
return $this->modificator === static::ADDED;
}
/**
* @return bool
*/
public function isDeleted()
{
return $this->modificator === static::DELETED;
}
/**
* @return bool
*/
public function isModified()
{
return $this->modificator === static::MODIFIED;
}
/**
* @return bool
*/
public function isRenamed()
{
return $this->modificator === static::RENAMED;
}
/**
* @return bool
*/
public function isModuleFile()
{
return strpos($this->filename, static::MODULE_ID) === 0;
}
/**
* @return string
*/
public function getFilename()
{
return $this->filename;
}
/**
* @return string
*/
public function getOldFilename()
{
return $this->oldFilename;
}
/**
* @return int
*/
public function getPercent()
{
return $this->percent;
}
}

View file

@ -0,0 +1,113 @@
<?php
require_once 'ModifiedFile.php';
/**
* Class ReleaseBuilder
*/
class ReleaseBuilder
{
/** @var ModifiedFile[] */
protected $files;
/** @var string */
protected $releaseDir;
/**
* ReleaseBuilder constructor.
* @param ModifiedFile[] $files
* @param string $releaseVersion
* @throws \RuntimeException
*/
public function __construct($files, $releaseVersion)
{
$this->files = $files;
if (!defined('RELEASE_DIR') || !defined('ORIGINAL')) {
throw new \RuntimeException('`RELEASE_DIR` or `ORIGINAL` not defined');
}
$this->releaseDir = RELEASE_DIR . $releaseVersion . '/';
}
/**
* @return void
*/
public function build()
{
$this->createReleaseDir();
$modifiedFiles = [];
foreach ($this->files as $file) {
if (!$file->isModuleFile() || $file->isDeleted()) {
continue;
}
$modifiedFiles[] = $this->getRealFilename($file->getFilename());
}
if (!in_array(ModifiedFile::DESCRIPTION, $modifiedFiles) || !in_array(ModifiedFile::VERSION, $modifiedFiles)) {
throw new \UnexpectedValueException('Version or description file does not exists');
}
if (empty($modifiedFiles)) {
throw new \LogicException('Not found modified files for release');
}
$this->createDirNodes($modifiedFiles);
$this->copyFiles($modifiedFiles);
}
/**
* @param string[] $files
*/
private function copyFiles($files)
{
foreach ($files as $file) {
copy(ORIGINAL . $file, $this->releaseDir . $file);
}
}
/**
* @param string[] $files
*/
private function createDirNodes($files)
{
$paths = [];
foreach ($files as $file) {
$dirs = explode('/', $file, -1);
$path = $this->releaseDir;
foreach ($dirs as $dir) {
$path .= $dir . '/';
$paths[] = $path;
}
}
foreach ($paths as $path) {
if (!file_exists($path)) {
mkdir($path, 0755);
}
}
}
/**
* @return void
*/
private function createReleaseDir()
{
if (!file_exists($this->releaseDir)) {
mkdir($this->releaseDir, 0755);
}
}
/**
* @param string $filename
* @return string
*/
private function getRealFilename($filename)
{
return str_replace(ModifiedFile::MODULE_ID . '/', '', $filename);
}
}

View file

@ -1,376 +0,0 @@
<?php
class ICrmOrderActions
{
protected static $MODULE_ID = 'intaro.intarocrm';
protected static $CRM_API_HOST_OPTION = 'api_host';
protected static $CRM_API_KEY_OPTION = 'api_key';
protected static $CRM_ORDER_TYPES_ARR = 'order_types_arr';
protected static $CRM_DELIVERY_TYPES_ARR = 'deliv_types_arr';
protected static $CRM_PAYMENT_TYPES = 'pay_types_arr';
protected static $CRM_PAYMENT_STATUSES = 'pay_statuses_arr';
protected static $CRM_PAYMENT = 'payment_arr'; //order payment Y/N
protected static $CRM_ORDER_LAST_ID = 'order_last_id';
/**
* Mass order uploading, without repeating; always returns true, but writes error log
* @return boolean
*/
public static function uploadOrders($steps = false, $pSize = 50) {
//COption::SetOptionString(self::$MODULE_ID, self::$CRM_ORDER_LAST_ID, 0); // -- for test
if (!CModule::IncludeModule("iblock")) {
//handle err
self::eventLog('ICrmOrderActions::uploadOrders', 'iblock', 'module not found');
return true;
}
if (!CModule::IncludeModule("sale")) {
//handle err
self::eventLog('ICrmOrderActions::uploadOrders', 'sale', 'module not found');
return true;
}
if (!CModule::IncludeModule("catalog")) {
//handle err
self::eventLog('ICrmOrderActions::uploadOrders', 'catalog', 'module not found');
return true;
}
$resOrders = array();
$lastUpOrderId = COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_LAST_ID, 0);
$lastOrderId = 0;
$dbOrder = CSaleOrder::GetList(array("ID" => "ASC"), array('>ID' => $lastUpOrderId));
$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);
//saved cat params
$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));
$api = new IntaroCrm\RestApi($api_host, $api_key);
$arParams = array(
'optionsOrderTypes' => $optionsOrderTypes,
'optionsDelivTypes' => $optionsDelivTypes,
'optionsPayTypes' => $optionsPayTypes,
'optionsPayStatuses' => $optionsPayStatuses,
'optionsPayment' => $optionsPayment
);
// pack mode enable / disable
// can send data evry 500 rows
if (!$steps) {
while ($arOrder = $dbOrder->GetNext()) { //here orders by id asc; with offset
$order = self::orderCreate($arOrder, $api, $arParams);
if (!$order)
continue;
$resOrders[] = $order;
$lastOrderId = $arOrder['ID'];
}
if (!empty($resOrders)) {
$orders = $api->orderUpload($resOrders);
// error pushing orders
if ($api->getStatusCode() != 201) {
//handle err
self::eventLog('ICrmOrderActions::uploadOrders', 'IntaroCrm\RestApi::orderUpload', $api->getLastError());
if ($api->getStatusCode() != 460) // some orders were sent
return true;
}
}
} else { // package mode (by default runs after install)
$orderCount = 0;
while ($arOrder = $dbOrder->GetNext()) { // here orders by id asc
$order = self::orderCreate($arOrder, $api, $arParams);
if (!$order)
continue;
$orderCount++;
$resOrders[] = $order;
$lastOrderId = $arOrder['ID'];
if($orderCount >= $pSize) {
$orders = $api->orderUpload($resOrders);
// error pushing orders
if ($api->getStatusCode() != 201) {
//handle err
self::eventLog('ICrmOrderActions::uploadOrders', 'IntaroCrm\RestApi::orderUpload', $api->getLastError());
if($api->getStatusCode() != 460) // some orders were sent
return false; // in pack mode return errors
}
if($lastOrderId)
COption::SetOptionString(self::$MODULE_ID, self::$CRM_ORDER_LAST_ID, $lastOrderId);
return true; // end of pack
}
}
if (!empty($resOrders)) {
$orders = $api->orderUpload($resOrders);
// error pushing orders
if ($api->getStatusCode() != 201) {
//handle err
self::eventLog('ICrmOrderActions::uploadOrders', 'IntaroCrm\RestApi::orderUpload', $api->getLastError());
if ($api->getStatusCode() != 460) // some orders were sent
return false; // in pack mode return errors
}
}
}
if($lastOrderId)
COption::SetOptionString(self::$MODULE_ID, self::$CRM_ORDER_LAST_ID, $lastOrderId);
return true; //all ok!
}
/**
*
* w+ event in bitrix log
*/
public static function eventLog($auditType, $itemId, $description) {
CEventLog::Add(array(
"SEVERITY" => "SECURITY",
"AUDIT_TYPE_ID" => $auditType,
"MODULE_ID" => self::$MODULE_ID,
"ITEM_ID" => $itemId,
"DESCRIPTION" => $description,
));
}
/**
*
* Agent function
*
* @return self name
*/
public static function uploadOrdersAgent() {
if(self::uploadOrders())
return 'ICrmOrderActions::uploadOrdersAgent();';
else return;
}
public static function orderCreate($arFields, $api, $arParams, $send = false) {
if(!$api || empty($arParams)) { // add cond to check $arParams
return false;
}
if (empty($arFields)) {
//handle err
self::eventLog('ICrmOrderActions::orderCreate', 'empty($arFields)', 'incorrect order');
return false;
}
$rsUser = CUser::GetByID($arFields['USER_ID']);
$arUser = $rsUser->Fetch();
$createdAt = new \DateTime($arUser['DATE_REGISTER']);
$createdAt = $createdAt->format('Y-m-d H:i:s');
// push customer (for crm)
$firstName = self::toJSON($arUser['NAME']);
$lastName = self::toJSON($arUser['LAST_NAME']);
$patronymic = self::toJSON($arUser['SECOND_NAME']);
$phonePersonal = array(
'number' => self::toJSON($arUser['PERSONAL_PHONE']),
'type' => 'mobile'
);
$phones[] = $phonePersonal;
$phoneWork = array(
'number' => self::toJSON($arUser['WORK_PHONE']),
'type' => 'work'
);
$phones[] = $phoneWork;
$result = self::clearArr(array(
'externalId' => $arFields['USER_ID'],
'lastName' => $lastName,
'firstName' => $firstName,
'patronymic' => $patronymic,
'phones' => $phones,
'createdAt' => $createdAt
));
$customer = $api->customerEdit($result);
// error pushing customer
if (!$customer) {
//handle err
self::eventLog('ICrmOrderActions::orderCreate', 'IntaroCrm\RestApi::customerEdit', $api->getLastError());
return false;
}
// delivery types
$arId = array();
if (strpos($arFields['DELIVERY_ID'], ":") !== false)
$arId = explode(":", $arFields["DELIVERY_ID"]);
if ($arId)
$resultDeliveryTypeId = $arId[0];
else
$resultDeliveryTypeId = $arFields['DELIVERY_ID'];
$resOrder = array();
$resOrderDeliveryAddress = array();
$rsOrderProps = CSaleOrderPropsValue::GetList(array(), array('ORDER_ID' => $arFields['ID']));
while ($ar = $rsOrderProps->Fetch()) {
switch ($ar['CODE']) {
case 'ZIP': $resOrderDeliveryAddress['index'] = self::toJSON($ar['VALUE']);
break;
case 'CITY': $resOrderDeliveryAddress['city'] = self::toJSON($ar['VALUE']);
break;
case 'ADDRESS': $resOrderDeliveryAddress['text'] = self::toJSON($ar['VALUE']);
break;
case 'LOCATION': if(!isset($resOrderDeliveryAddress['city']) && !$resOrderDeliveryAddress['city']) {
$resOrderDeliveryAddress['city'] = CSaleLocation::GetByID($ar['VALUE']);
$resOrderDeliveryAddress['city'] = self::toJSON($resOrderDeliveryAddress['city']['CITY_NAME_LANG']);
}
break;
case 'FIO': $resOrder['contactName'] = explode(" ", self::toJSON($ar['VALUE']));
break;
case 'PHONE': $resOrder['phone'] = $ar['VALUE'];
break;
case 'EMAIL': $resOrder['email'] = $ar['VALUE'];
break;
}
}
$items = array();
$rsOrderBasket = CSaleBasket::GetList(array('PRODUCT_ID' => 'ASC'), array('ORDER_ID' => $arFields['ID']));
while ($p = $rsOrderBasket->Fetch()) {
$pr = CCatalogProduct::GetList(array('ID' => $p['PRODUCT_ID']))->Fetch();
if ($pr)
$pr = $pr['PURCHASING_PRICE'];
else
$pr = '';
if($p['DISCOUNT_VALUE'])
$p['DISCOUNT_PRICE'] = null;
$items[] = array(
'initialPrice' => (double) $p['PRICE'] + (double) $p['DISCOUNT_PRICE'],
'purchasePrice' => $pr,
'discount' => $p['DISCOUNT_PRICE'],
'discountPercent' => $p['DISCOUNT_VALUE'],
'quantity' => $p['QUANTITY'],
'productId' => $p['PRODUCT_ID'],
'productName' => self::toJSON($p['NAME'])
);
}
if($arFields['CANCELED'] == 'Y')
$arFields['STATUS_ID'] = $arFields['CANCELED'];
$createdAt = new \DateTime($arFields['DATE_INSERT']);
$createdAt = $createdAt->format('Y-m-d H:i:s');
$resOrder = self::clearArr(array(
'lastName' => $resOrder['contactName'][0],
'firstName' => $resOrder['contactName'][1],
'patronymic' => $resOrder['contactName'][2],
'phone' => $resOrder['phone'],
'email' => $resOrder['email'],
'deliveryCost' => $arFields['PRICE_DELIVERY'],
'summ' => $arFields['PRICE'],
'markDateTime' => $arFields['DATE_MARKED'],
'externalId' => $arFields['ID'],
'customerId' => $arFields['USER_ID'],
'paymentType' => $arParams['optionsPayTypes'][$arFields['PAY_SYSTEM_ID']],
'paymentStatus' => $arParams['optionsPayment'][$arFields['PAYED']],
'orderType' => $arParams['optionsOrderTypes'][$arFields['PERSON_TYPE_ID']],
'deliveryType' => $arParams['optionsDelivTypes'][$resultDeliveryTypeId],
'status' => $arParams['optionsPayStatuses'][$arFields['STATUS_ID']],
'statusComment' => $arFields['REASON_CANCELED'],
'createdAt' => $createdAt,
'deliveryAddress' => $resOrderDeliveryAddress,
'items' => $items
));
if($send)
return $api->createOrder($resOrder);
return $resOrder;
}
/**
* removes all empty fields from arrays
* working with nested arrs
*
* @param type $arr
* @return boolean
*/
public static function clearArr($arr) {
if(!$arr || !is_array($arr))
return false;
foreach($arr as $key => $value) {
if(!$value || (is_array($value) && empty($value)))
unset($arr[$key]);
if(is_array($value) && !empty($value))
$arr[$key] = self::clearArr($value);
}
return $arr;
}
/**
*
* @global type $APPLICATION
* @param type $str in SITE_CHARSET
* @return type $str in utf-8
*/
public static function toJSON($str) {
global $APPLICATION;
return $APPLICATION->ConvertCharset($str, SITE_CHARSET, 'utf-8');
}
/**
*
* @global type $APPLICATION
* @param type $str in utf-8
* @return type $str in SITE_CHARSET
*/
public static function fromJSON($str) {
global $APPLICATION;
return $APPLICATION->ConvertCharset($str, 'utf-8', SITE_CHARSET);
}
}

View file

@ -1,501 +0,0 @@
<?php
namespace IntaroCrm;
class RestApi
{
protected $apiUrl;
protected $apiKey;
protected $apiVersion = '1';
protected $response;
protected $statusCode;
protected $parameters;
/**
* @param string $crmUrl - адрес CRM
* @param string $apiKey - ключ для работы с api
*/
public function __construct($crmUrl, $apiKey)
{
$this->apiUrl = $crmUrl.'/api/v'.$this->apiVersion.'/';
$this->apiKey = $apiKey;
$this->parameters = array('apiKey' => $this->apiKey);
}
public function getStatusCode()
{
return $this->statusCode;
}
/* Получение кода статуса и сообщения об ошибке */
public function getLastError()
{
if (isset($this->response['errorMsg']) && isset($this->response['errors']))
{
$result = $this->statusCode . ' ' . $this->response['errorMsg'];
foreach ($this->response['errors'] as $error)
$result .= ' ' . $error;
}
elseif (isset($this->response['errorMsg']))
$result = $this->statusCode . ' ' . $this->response['errorMsg'];
else
$result = null;
return $result;
}
/* Псообщения об ошибке */
public function getLastErrorMessage()
{
return $this->response['errorMsg'];
}
/* Методы для работы с заказами */
/**
* Получение заказа по id
*
* @param string $id - идентификатор заказа
* @param string $by - поиск заказа по id или externalId
* @return array - информация о заказе
*/
public function orderGet($id, $by = 'externalId')
{
$url = $this->apiUrl.'orders/'.$id;
if ($by != 'externalId')
$this->parameters['by'] = $by;
$result = $this->curlRequest($url);
return $result;
}
/**
* Создание заказа
*
* @param array $order- информация о заказе
* @return array
*/
public function orderCreate($order)
{
$dataJson = json_encode($order);
$this->parameters['order'] = $dataJson;
$url = $this->apiUrl.'orders/create';
$result = $this->curlRequest($url, 'POST');
return $result;
}
/**
* Изменение заказа
*
* @param array $order- информация о заказе
* @return array
*/
public function orderEdit($order)
{
$dataJson = json_encode($order);
$this->parameters['order'] = $dataJson;
$url = $this->apiUrl.'orders/'.$order['externalId'].'/edit';
$result = $this->curlRequest($url, 'POST');
return $result;
}
/**
* Пакетная загрузка заказов
*
* @param array $orders - массив заказов
* @return array
*/
public function orderUpload($orders)
{
$dataJson = json_encode($orders);
$this->parameters['orders'] = $dataJson;
$url = $this->apiUrl.'orders/upload';
$result = $this->curlRequest($url, 'POST');
if (is_null($result) && isset($result['uploadedOrders']))
return $result['uploadedOrders'];
return $result;
}
/**
* Обновление externalId у заказов с переданными id
*
* @param array $orders- массив, содержащий id и externalId заказа
* @return array
*/
public function orderFixExternalIds($order)
{
$dataJson = json_encode($order);
$this->parameters['orders'] = $dataJson;
$url = $this->apiUrl.'orders/fix-external-ids';
$result = $this->curlRequest($url, 'POST');
return $result;
}
/**
* Удаление заказа
*
* @param string $id - идентификатор заказа
* @param string $by - поиск заказа по id или externalId
* @return array
*/
/*
public function orderDelete($id, $by = 'externalId')
{
$url = $this->apiUrl.'orders/'.$id.'/delete';
if ($by != 'externalId')
$this->parameters['by'] = $by;
$result = $this->curlRequest($url, 'POST');
return $result;
}*/
/**
* Получение последних измененных заказов
*
* @param DateTime $startDate - начальная дата выборки
* @param DateTime $endDate - конечная дата
* @param int $limit - ограничение на размер выборки
* @param int $offset - сдвиг
* @return array - массив заказов
*/
public function orderHistory($startDate = null, $endDate = null, $limit = 100, $offset = 0)
{
$url = $this->apiUrl.'orders/history';
$this->parameters['startDate'] = $startDate;
$this->parameters['endDate'] = $endDate;
$this->parameters['limit'] = $limit;
$this->parameters['offset'] = $offset;
$result = $this->curlRequest($url);
return $result;
}
/* Методы для работы с клиентами */
/**
* Получение клиента по id
*
* @param string $id - идентификатор
* @param string $by - поиск заказа по id или externalId
* @return array - информация о клиенте
*/
public function customerGet($id, $by = 'externalId')
{
$url = $this->apiUrl.'customers/'.$id;
if ($by != 'externalId')
$this->parameters['by'] = $by;
$result = $this->curlRequest($url);
return $result;
}
/**
* Создание клиента
*
* @param array $customer - информация о клиенте
* @return array
*/
public function customerCreate($customer)
{
$dataJson = json_encode($customer);
$this->parameters['customer'] = $dataJson;
$url = $this->apiUrl.'customers/create';
$result = $this->curlRequest($url, 'POST');
return $result;
}
/**
* Редактирование клиента
*
* @param array $customer - информация о клиенте
* @return array
*/
public function customerEdit($customer)
{
$dataJson = json_encode($customer);
$this->parameters['customer'] = $dataJson;
$url = $this->apiUrl.'customers/'.$customer['externalId'].'/edit';
$result = $this->curlRequest($url, 'POST');
return $result;
}
/**
* Пакетная загрузка клиентов
*
* @param array $customers - массив клиентов
* @return array
*/
public function customerUpload($customers)
{
$dataJson = json_encode($customers);
$dataJson = str_replace(self::$jsonReplaceSource, self::$jsonReplaceTarget,
$dataJson);
$this->parameters['customers'] = $dataJson;
$url = $this->apiUrl.'customers/upload';
$result = $this->curlRequest($url, 'POST');
if (is_null($result) && isset($result['uploaded']))
return $result['uploaded'];
return $result;
}
/**
* Удаление клиента
*
* @param string $id - идентификатор
* @param string $by - поиск заказа по id или externalId
* @return array
*/
/*
public function customerDelete($id, $by = 'externalId')
{
$url = $this->apiUrl.'customers/'.$id.'/delete';
if ($by != 'externalId')
$this->parameters['by'] = $by;
$result = $this->curlRequest($url, 'POST');
return $result;
}*/
/**
* Получение списка заказов клиента
*
* @param string $id - идентификатор клиента
* @param string $by - поиск заказа по id или externalId
* @param DateTime $startDate - начальная дата выборки
* @param DateTime $endDate - конечная дата
* @param int $limit - ограничение на размер выборки
* @param int $offset - сдвиг
* @return array - массив заказов
*/
public function customerOrdersList($id, $startDate = null, $endDate = null,
$limit = 100, $offset = 0, $by = 'externalId')
{
$url = $this->apiUrl.'customers/'.$id.'/orders';
if ($by != 'externalId')
$this->parameters['by'] = $by;
$this->parameters['startDate'] = $startDate;
$this->parameters['endDate'] = $endDate;
$this->parameters['limit'] = $limit;
$this->parameters['offset'] = $offset;
$result = $this->curlRequest($url);
return $result;
}
/* Методы для работы со справочниками */
/**
* Получение списка типов доставки
*
* @return array - массив типов доставки
*/
public function deliveryTypesList()
{
$url = $this->apiUrl.'reference/delivery-types';
$result = $this->curlRequest($url);
return $result;
}
/**
* Редактирование типа доставки
*
* @param array $deliveryType - информация о типе доставки
* @return array
*/
public function deliveryTypeEdit($deliveryType)
{
$dataJson = json_encode($deliveryType);
$this->parameters['deliveryType'] = $dataJson;
$url = $this->apiUrl.'delivery-types/'.$deliveryType['code'].'/edit';
$result = $this->curlRequest($url, 'POST');
return $result;
}
/**
* Получение списка типов оплаты
*
* @return array - массив типов оплаты
*/
public function paymentTypesList()
{
$url = $this->apiUrl.'reference/payment-types';
$result = $this->curlRequest($url);
return $result;
}
/**
* Редактирование типа оплаты
*
* @param array $paymentType - информация о типе оплаты
* @return array
*/
public function paymentTypesEdit($paymentType)
{
$dataJson = json_encode($paymentType);
$this->parameters['paymentType'] = $dataJson;
$url = $this->apiUrl.'payment-types/'.$paymentType['code'].'/edit';
$result = $this->curlRequest($url, 'POST');
return $result;
}
/**
* Получение списка статусов оплаты
*
* @return array - массив статусов оплаты
*/
public function paymentStatusesList()
{
$url = $this->apiUrl.'reference/payment-statuses';
$result = $this->curlRequest($url);
return $result;
}
/**
* Редактирование статуса оплаты
*
* @param array $paymentStatus - информация о статусе оплаты
* @return array
*/
public function paymentStatusesEdit($paymentStatus)
{
$dataJson = json_encode($paymentStatus);
$this->parameters['paymentStatus'] = $dataJson;
$url = $this->apiUrl.'payment-statuses/'.$paymentStatus['code'].'/edit';
$result = $this->curlRequest($url, 'POST');
return $result;
}
/**
* Получение списка типов заказа
*
* @return array - массив типов заказа
*/
public function orderTypesList()
{
$url = $this->apiUrl.'reference/order-types';
$result = $this->curlRequest($url);
return $result;
}
/**
* Редактирование типа заказа
*
* @param array $orderType - информация о типе заказа
* @return array
*/
public function orderTypesEdit($orderType)
{
$dataJson = json_encode($orderType);
$this->parameters['orderType'] = $dataJson;
$url = $this->apiUrl.'order-types/'.$orderType['code'].'/edit';
$result = $this->curlRequest($url, 'POST');
return $result;
}
/**
* Получение списка статусов заказа
*
* @return array - массив статусов заказа
*/
public function orderStatusesList()
{
$url = $this->apiUrl.'reference/statuses';
$result = $this->curlRequest($url);
return $result;
}
/**
* Редактирование статуса заказа
*
* @param array $status - информация о статусе заказа
* @return array
*/
public function orderStatusEdit($status)
{
$dataJson = json_encode($status);
$this->parameters['status'] = $dataJson;
$url = $this->apiUrl.'statuses/'.$status['code'].'/edit';
$result = $this->curlRequest($url, 'POST');
return $result;
}
/**
* Получение списка групп статусов заказа
*
* @return array - массив групп статусов заказа
*/
public function orderStatusGroupsList()
{
$url = $this->apiUrl.'reference/status-groups';
$result = $this->curlRequest($url);
return $result;
}
/**
* Обновление статистики
*
* @return array - статус вып обновления
*/
public function statisticUpdate()
{
$url = $this->apiUrl.'statistic/update';
$result = $this->curlRequest($url);
return $result;
}
protected function curlRequest($url, $method = 'GET', $format = 'json')
{
if ($method == 'GET' && !is_null($this->parameters))
$url .= '?'.http_build_query($this->parameters);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FAILONERROR, FALSE);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// allow redirects
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // return into a variable
curl_setopt($ch, CURLOPT_TIMEOUT, 30); // times out after 30s
if ($method == 'POST')
{
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->parameters);
}
$response = curl_exec($ch);
$this->statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
unset($this->parameters);
/* Сброс массива с параметрами */
$this->parameters = array('apiKey' => $this->apiKey);
if (curl_errno($ch))
{
$this->response = array('errorMsg' => 'Curl error: ' . curl_error($ch));
return null;
}
curl_close($ch);
$result = (array)json_decode($response, true);
$this->response = $result;
if ($result['success'] == false)
return null;
unset($result['success']);
if (count($result) == 0)
return true;
return reset($result);
}
}
?>

View file

@ -1,195 +0,0 @@
<?php
/**
* OrderEvent
*/
class ICrmOrderEvent {
protected static $MODULE_ID = 'intaro.intarocrm';
protected static $CRM_API_HOST_OPTION = 'api_host';
protected static $CRM_API_KEY_OPTION = 'api_key';
protected static $CRM_ORDER_TYPES_ARR = 'order_types_arr';
protected static $CRM_DELIVERY_TYPES_ARR = 'deliv_types_arr';
protected static $CRM_PAYMENT_TYPES = 'pay_types_arr';
protected static $CRM_PAYMENT_STATUSES = 'pay_statuses_arr';
protected static $CRM_PAYMENT = 'payment_arr'; //order payment Y/N
protected static $CRM_ORDER_LAST_ID = 'order_last_id';
/**
* onUpdateOrder
*
* @param mixed $ID - Order id
* @param mixed $arFields - Order arFields
*/
function onUpdateOrder($ID, $arFields = array()) {
//self::writeDataOnOrderCreate($ID);
}
/**
* onSendOrderMail
* in: sale.order.ajax, sale.order.full
*
* @param mixed $ID - Order id
* @param mixed $eventName - Event type
* @param mixed $arFields - Order arFields for sending template
*/
function onSendOrderMail($ID, &$eventName, &$arFields) {
self::writeDataOnOrderCreate($ID);
}
/**
* writeDataOnOrderCreate via api
*
* @param integer $ID - Order Id
*/
function writeDataOnOrderCreate($ID) {
if (!CModule::IncludeModule('iblock')) {
//handle err
ICrmOrderActions::eventLog('ICrmOrderEvent::writeDataOnOrderCreate', 'iblock', 'module not found');
return true;
}
if (!CModule::IncludeModule("sale")) {
//handle err
ICrmOrderActions::eventLog('ICrmOrderEvent::writeDataOnOrderCreate', 'sale', 'module not found');
return true;
}
if (!CModule::IncludeModule("catalog")) {
//handle err
ICrmOrderActions::eventLog('ICrmOrderEvent::writeDataOnOrderCreate', 'catalog', 'module not found');
return true;
}
$api_host = COption::GetOptionString(self::$MODULE_ID, self::$CRM_API_HOST_OPTION, 0);
$api_key = COption::GetOptionString(Iself::$MODULE_ID, self::$CRM_API_KEY_OPTION, 0);
//saved cat params
$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));
$api = new IntaroCrm\RestApi($api_host, $api_key);
$arParams = array(
'optionsOrderTypes' => $optionsOrderTypes,
'optionsDelivTypes' => $optionsDelivTypes,
'optionsPayTypes' => $optionsPayTypes,
'optionsPayStatuses' => $optionsPayStatuses,
'optionsPayment' => $optionsPayment
);
$arOrder = CSaleOrder::GetById($ID);
$result = ICrmOrderActions::orderCreate($arOrder, $api, $arParams, true);
if(!$result) {
ICrmOrderActions::eventLog('ICrmOrderEvent::writeDataOnOrderCreate', 'ICrmOrderActions::orderCreate', 'error during creating order');
return true;
}
return true;
}
/**
*
* @param type $ID -- orderId
* @param type $cancel -- Y / N - cancel order status
* @param type $reason -- cancel reason
* @return boolean
*/
function onSaleCancelOrder($ID, $cancel, $reason) {
if(!$ID || !$cancel || ($cancel != 'Y'))
return true;
if (!CModule::IncludeModule('iblock')) {
//handle err
ICrmOrderActions::eventLog('ICrmOrderEvent::onSaleCancelOrder', 'iblock', 'module not found');
return true;
}
if (!CModule::IncludeModule("sale")) {
//handle err
ICrmOrderActions::eventLog('ICrmOrderEvent::onSaleCancelOrder', 'sale', 'module not found');
return true;
}
if (!CModule::IncludeModule("catalog")) {
//handle err
ICrmOrderActions::eventLog('ICrmOrderEvent::onSaleCancelOrder', 'catalog', 'module not found');
return true;
}
$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);
//saved cat params
$optionsPayStatuses = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_PAYMENT_STATUSES, 0)); // --statuses
$api = new IntaroCrm\RestApi($api_host, $api_key);
$order = array(
'externalId' => (int) $ID,
'status' => $optionsPayStatuses[$cancel],
'statusComment' => ICrmOrderActions::toJSON($reason)
);
$api->orderEdit($order);
// error pushing order
if ($api->getStatusCode() != 201)
ICrmOrderActions::eventLog('ICrmOrderEvent::onSaleCancelOrder', 'IntaroCrm\RestApi::orderEdit', $api->getLastError());
return true;
}
/**
*
* @param type $ID -- orderId
* @param type $payed -- Y / N - pay order status
* @return boolean
*/
function onSalePayOrder($ID, $payed) {
if(!$ID || !$payed || ($payed != 'Y'))
return true;
if (!CModule::IncludeModule('iblock')) {
//handle err
ICrmOrderActions::eventLog('ICrmOrderEvent::onSalePayOrder', 'iblock', 'module not found');
return true;
}
if (!CModule::IncludeModule("sale")) {
//handle err
ICrmOrderActions::eventLog('ICrmOrderEvent::onSalePayOrder', 'sale', 'module not found');
return true;
}
if (!CModule::IncludeModule("catalog")) {
//handle err
ICrmOrderActions::eventLog('ICrmOrderEvent::onSalePayOrder', 'catalog', 'module not found');
return true;
}
$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);
//saved cat params
$optionsPayment = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_PAYMENT, 0));
$api = new IntaroCrm\RestApi($api_host, $api_key);
$order = array(
'externalId' => (int) $ID,
'paymentStatus' => $optionsPayment[$payed]
);
$api->orderEdit($order);
// error pushing order
if ($api->getStatusCode() != 201)
ICrmOrderActions::eventLog('ICrmOrderEvent::onSalePayOrder', 'IntaroCrm\RestApi::orderEdit', $api->getLastError());
return true;
}
}

View file

@ -1,9 +0,0 @@
<?php
CModule::AddAutoloadClasses(
'intaro.intarocrm', // module name
array (
'IntaroCrm\RestApi' => 'classes/general/RestApi.php',
'ICrmOrderActions' => 'classes/general/ICrmOrderActions.php',
'ICrmOrderEvent' => 'classes/general/events/ICrmOrderEvent.php'
)
);

File diff suppressed because it is too large Load diff

View file

@ -1,173 +0,0 @@
<?
//<title>IntaroCRM</title>
__IncludeLang(GetLangFileName($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/intaro.intarocrm/lang/", "/export_setup_templ.php"));
global $APPLICATION;
$arSetupErrors = array();
if (($ACTION == 'EXPORT_EDIT' || $ACTION == 'EXPORT_COPY') && $STEP == 1)
{
if (isset($arOldSetupVars['YANDEX_EXPORT']))
$YANDEX_EXPORT = $arOldSetupVars['YANDEX_EXPORT'];
if (isset($arOldSetupVars['SETUP_FILE_NAME']))
$SETUP_FILE_NAME = $arOldSetupVars['SETUP_FILE_NAME'];
if (isset($arOldSetupVars['SETUP_PROFILE_NAME']))
$SETUP_PROFILE_NAME = $arOldSetupVars['SETUP_PROFILE_NAME'];
if (isset($arOldSetupVars['SETUP_SERVER_NAME']))
$SETUP_SERVER_NAME = $arOldSetupVars['SETUP_SERVER_NAME'];
}
if ($STEP>1)
{
if (!is_array($YANDEX_EXPORT) || count($YANDEX_EXPORT)<=0)
{
$arSetupErrors[] = GetMessage("CET_ERROR_NO_IBLOCKS");
}
if (strlen($SETUP_FILE_NAME)<=0)
{
$arSetupErrors[] = GetMessage("CET_ERROR_NO_FILENAME");
}
elseif (preg_match(BX_CATALOG_FILENAME_REG,$SETUP_FILE_NAME))
{
$arSetupErrors[] = GetMessage("CES_ERROR_BAD_EXPORT_FILENAME");
}
elseif ($APPLICATION->GetFileAccessPermission($SETUP_FILE_NAME) < "W")
{
$arSetupErrors[] = str_replace("#FILE#", $SETUP_FILE_NAME, GetMessage('CET_YAND_RUN_ERR_SETUP_FILE_ACCESS_DENIED'));
}
if (($ACTION=="EXPORT_SETUP" || $ACTION == 'EXPORT_EDIT' || $ACTION == 'EXPORT_COPY') && strlen($SETUP_PROFILE_NAME)<=0)
{
$arSetupErrors[] = GetMessage("CET_ERROR_NO_PROFILE_NAME");
}
if (!empty($arSetupErrors))
{
$STEP = 1;
}
}
if (!empty($arSetupErrors))
echo ShowError(implode('<br />', $arSetupErrors));
if ($STEP==1)
{
if (CModule::IncludeModule("iblock"))
{
// Get IBlock list
?>
<form method="POST" action="<? echo $APPLICATION->GetCurPage(); ?>" enctype="multipart/form-data" name="dataload">
<? echo bitrix_sessid_post(); ?>
<?if ($ACTION == 'EXPORT_EDIT' || $ACTION == 'EXPORT_COPY')
{
?><input type="hidden" name="PROFILE_ID" value="<? echo intval($PROFILE_ID); ?>"><?
}
?>
<table width="100%">
<tr>
<td valign="top">
<?
if (!isset($YANDEX_EXPORT) || !is_array($YANDEX_EXPORT))
{
$YANDEX_EXPORT = array();
}
$boolAll = false;
$intCountChecked = 0;
$intCountAvailIBlock = 0;
$arIBlockList = array();
$db_res = CIBlock::GetList(Array("IBLOCK_TYPE"=>"ASC", "NAME"=>"ASC"),array('CHECK_PERMISSIONS' => 'Y','MIN_PERMISSION' => 'W'));
while ($res = $db_res->Fetch())
{
if ($ar_res1 = CCatalog::GetByID($res["ID"]))
{
$arSiteList = array();
$rsSites = CIBlock::GetSite($res["ID"]);
while ($arSite = $rsSites->Fetch())
{
$arSiteList[] = $arSite["SITE_ID"];
}
$boolYandex = (in_array($res['ID'],$YANDEX_EXPORT));
$arIBlockList[] = array(
'ID' => $res['ID'],
'NAME' => $res['NAME'],
'IBLOCK_TYPE_ID' => $res['IBLOCK_TYPE_ID'],
'YANDEX_EXPORT' => $boolYandex,
'SITE_LIST' => '('.implode(' ',$arSiteList).')',
);
if ($boolYandex)
$intCountChecked++;
$intCountAvailIBlock++;
}
}
if ($intCountChecked == $intCountAvailIBlock)
$boolAll = true;
?>
<?
foreach ($arIBlockList as $key => $arIBlock)
{
?>
<input type="hidden" name="YANDEX_EXPORT[<? echo $key; ?>]" id="YANDEX_EXPORT_<? echo $key; ?>" value="<? echo $arIBlock["ID"]; ?>" checked>
<?
}
?>
<input type="hidden" name="count_checked" id="count_checked" value="<? echo $intCountChecked; ?>">
</td>
</tr>
<tr>
<td width="0%" valign="top"></td>
<td width="100%" valign="top">
<font class="text">
<?echo GetMessage("CET_SAVE_FILENAME");?> <input type="text" name="SETUP_FILE_NAME" value="<?echo htmlspecialcharsbx(strlen($SETUP_FILE_NAME)>0 ? $SETUP_FILE_NAME : (COption::GetOptionString("catalog", "export_default_path", "/bitrix/catalog_export/"))."intarocrm"/* .mt_rand(0, 999999) */.".php"); ?>" size="50">
</font>
<br><br>
</td>
</tr>
<?if ($ACTION=="EXPORT_SETUP" || $ACTION == 'EXPORT_EDIT' || $ACTION == 'EXPORT_COPY'):?>
<tr>
<td width="0%" valign="top">
<font class="text" style="font-size: 20px;">4.&nbsp;&nbsp;&nbsp;</font>
</td>
<td width="100%" valign="top">
<font class="text">
<?echo GetMessage("CET_PROFILE_NAME");?> <input type="text" name="SETUP_PROFILE_NAME" value="<?echo htmlspecialcharsbx($SETUP_PROFILE_NAME)?>" size="30">
</font>
<br><br>
</td>
</tr>
<?endif;?>
<tr>
<td width="0%" valign="top">
&nbsp;
</td>
<td width="100%" valign="top">
<input type="hidden" name="lang" value="<?echo LANGUAGE_ID ?>">
<input type="hidden" name="ACT_FILE" value="<?echo htmlspecialchars($_REQUEST["ACT_FILE"]) ?>">
<input type="hidden" name="ACTION" value="<?echo htmlspecialchars($ACTION) ?>">
<input type="hidden" name="STEP" value="<?echo intval($STEP) + 1 ?>">
<input type="hidden" name="SETUP_FIELDS_LIST" value="YANDEX_EXPORT,SETUP_SERVER_NAME,SETUP_FILE_NAME">
<input type="submit" value="<?echo ($ACTION=="EXPORT")?GetMessage("CET_EXPORT"):GetMessage("CET_SAVE")?>">
</td>
</tr>
</table>
</form>
<?
}
}
elseif ($STEP==2)
{
$SETUP_SERVER_NAME = htmlspecialcharsbx($SETUP_SERVER_NAME);
$_POST['SETUP_SERVER_NAME'] = htmlspecialcharsbx($_POST['SETUP_SERVER_NAME']);
$_REQUEST['SETUP_SERVER_NAME'] = htmlspecialcharsbx($_REQUEST['SETUP_SERVER_NAME']);
$FINITE = true;
}
?>

View file

@ -1,450 +0,0 @@
<?php
/**
* Module Install/Uninstall script
* Module name: intaro.intarocrm
* Class name: intaro_intarocrm
*/
global $MESS;
IncludeModuleLangFile(__FILE__);
if (class_exists('intaro_intarocrm'))
return;
class intaro_intarocrm extends CModule
{
var $MODULE_ID = 'intaro.intarocrm';
var $MODULE_VERSION;
var $MODULE_VERSION_DATE;
var $MODULE_NAME;
var $MODULE_DESCRIPTION;
var $MODULE_GROUP_RIGHTS = 'N';
var $PARTNER_NAME;
var $PARTNER_URI;
var $INTARO_CRM_API;
var $CRM_API_HOST_OPTION = 'api_host';
var $CRM_API_KEY_OPTION = 'api_key';
var $CRM_ORDER_TYPES_ARR = 'order_types_arr';
var $CRM_DELIVERY_TYPES_ARR = 'deliv_types_arr';
var $CRM_PAYMENT_TYPES = 'pay_types_arr';
var $CRM_PAYMENT_STATUSES = 'pay_statuses_arr';
var $CRM_PAYMENT = 'payment_arr'; //order payment Y/N
var $CRM_ORDER_LAST_ID = 'order_last_id';
var $INSTALL_PATH;
function intaro_intarocrm()
{
$arModuleVersion = array();
$path = str_replace("\\", "/", __FILE__);
$path = substr($path, 0, strlen($path) - strlen("/index.php"));
$this->INSTALL_PATH = $path;
include($path."/version.php");
$this->MODULE_VERSION = $arModuleVersion["VERSION"];
$this->MODULE_VERSION_DATE = $arModuleVersion["VERSION_DATE"];
$this->MODULE_NAME = GetMessage('MODULE_NAME');
$this->MODULE_DESCRIPTION = GetMessage('MODULE_DESCRIPTION');
$this->PARTNER_NAME = GetMessage('MODULE_PARTNER_NAME');
$this->PARTNER_URI = GetMessage('MODULE_PARTNER_URI');
}
/**
* Functions DoInstall and DoUninstall are
* All other functions are optional
*/
function DoInstall()
{
global $APPLICATION, $step, $arResult;
if (!in_array('curl', get_loaded_extensions())) {
$APPLICATION->ThrowException(GetMessage("INTAROCRM_CURL_ERR"));
return false;
}
include($this->INSTALL_PATH . '/../classes/general/RestApi.php');
include($this->INSTALL_PATH . '/../classes/general/ICrmOrderActions.php');
$step = intval($_REQUEST['step']);
if ($step <= 1) {
if(!CModule::IncludeModule("sale")) {
$arResult['errCode'] = 'ERR_SALE';
}
if(!CModule::IncludeModule("iblock")) {
$arResult['errCode'] = 'ERR_IBLOCK';
}
if(!CModule::IncludeModule("catalog")) {
$arResult['errCode'] = 'ERR_CATALOG';
}
$APPLICATION->IncludeAdminFile(
GetMessage('MODULE_INSTALL_TITLE'),
$_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/' . $this->MODULE_ID . '/install/step1.php'
);
} else if ($step == 2) {
if(!CModule::IncludeModule("sale")) {
$arResult['errCode'] = 'ERR_SALE';
}
if(!CModule::IncludeModule("iblock")) {
$arResult['errCode'] = 'ERR_IBLOCK';
}
if(!CModule::IncludeModule("catalog")) {
$arResult['errCode'] = 'ERR_CATALOG';
}
if(isset($arResult['errCode']) && $arResult['errCode']) {
$APPLICATION->IncludeAdminFile(
GetMessage('MODULE_INSTALL_TITLE'),
$_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/' . $this->MODULE_ID . '/install/step1.php'
);
return;
}
$api_host = htmlspecialchars(trim($_POST[$this->CRM_API_HOST_OPTION]));
$api_key = htmlspecialchars(trim($_POST[$this->CRM_API_KEY_OPTION]));
// form correct url
$api_host = parse_url($api_host);
$api_host = $api_host['scheme'] . '://' . $api_host['host'];
if(!$api_host || !$api_key) {
$arResult['errCode'] = 'ERR_FIELDS_API_HOST';
$APPLICATION->IncludeAdminFile(
GetMessage('MODULE_INSTALL_TITLE'),
$_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/' . $this->MODULE_ID . '/install/step1.php'
);
return;
}
$this->INTARO_CRM_API = new \IntaroCrm\RestApi($api_host, $api_key);
$this->INTARO_CRM_API->paymentStatusesList();
//check connection & apiKey valid
if((int) $this->INTARO_CRM_API->getStatusCode() != 200) {
$arResult['errCode'] = 'ERR_' . $this->INTARO_CRM_API->getStatusCode();
$APPLICATION->IncludeAdminFile(
GetMessage('MODULE_INSTALL_TITLE'),
$_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/' . $this->MODULE_ID . '/install/step1.php'
);
return;
}
COption::SetOptionString($this->MODULE_ID, $this->CRM_API_HOST_OPTION, $api_host);
COption::SetOptionString($this->MODULE_ID, $this->CRM_API_KEY_OPTION, $api_key);
//prepare crm lists
$arResult['orderTypesList'] = $this->INTARO_CRM_API->orderTypesList();
$arResult['deliveryTypesList'] = $this->INTARO_CRM_API->deliveryTypesList();
$arResult['paymentTypesList'] = $this->INTARO_CRM_API->paymentTypesList();
$arResult['paymentStatusesList'] = $this->INTARO_CRM_API->paymentStatusesList(); // --statuses
$arResult['paymentList'] = $this->INTARO_CRM_API->orderStatusesList();
$arResult['paymentGroupList'] = $this->INTARO_CRM_API->orderStatusGroupsList(); // -- statuses groups
//bitrix orderTypesList -- personTypes
$dbOrderTypesList = CSalePersonType::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y",
),
false,
false,
array()
);
if ($arOrderTypesList = $dbOrderTypesList->Fetch()) {
do {
$arResult['bitrixOrderTypesList'][] = $arOrderTypesList;
} while ($arOrderTypesList = $dbOrderTypesList->Fetch());
}
//bitrix deliveryTypesList
$dbDeliveryTypesList = CSaleDelivery::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y",
),
false,
false,
array()
);
if ($arDeliveryTypesList = $dbDeliveryTypesList->Fetch()) {
do {
$arResult['bitrixDeliveryTypesList'][] = $arDeliveryTypesList;
} while ($arDeliveryTypesList = $dbDeliveryTypesList->Fetch());
}
//bitrix paymentTypesList
$dbPaymentTypesList = CSalePaySystem::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y"
)
);
if ($arPaymentTypesList = $dbPaymentTypesList->Fetch()) {
do {
$arResult['bitrixPaymentTypesList'][] = $arPaymentTypesList;
} while ($arPaymentTypesList = $dbPaymentTypesList->Fetch());
}
//bitrix paymentStatusesList --statuses
$dbPaymentStatusesList = CSaleStatus::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"LID" => "ru", //ru
"ACTIVE" => "Y"
)
);
if ($arPaymentStatusesList = $dbPaymentStatusesList->Fetch()) {
do {
$arResult['bitrixPaymentStatusesList'][] = $arPaymentStatusesList;
} while ($arPaymentStatusesList = $dbPaymentStatusesList->Fetch());
}
$arResult['bitrixPaymentStatusesList'][] = array(
'ID' => 'Y',
'NAME' => GetMessage('CANCELED')
);
$APPLICATION->IncludeAdminFile(
GetMessage('MODULE_INSTALL_TITLE'),
$_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/' . $this->MODULE_ID . '/install/step2.php'
);
} else if ($step == 3) {
if(!CModule::IncludeModule("sale")) {
//handler
}
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
&& isset($_POST['ajax']) && ($_POST['ajax'] == 1)) {
ICrmOrderActions::uploadOrders(true); // each 50
$lastUpOrderId = COption::GetOptionString($this->MODULE_ID, $this->CRM_ORDER_LAST_ID, 0);
$countLeft = (int) CSaleOrder::GetList(array("ID" => "ASC"), array('>ID' => $lastUpOrderId), array());
$countAll = (int) CSaleOrder::GetList(array("ID" => "ASC"), array(), array());
if(!isset($_POST['finish']))
$finish = 0;
else
$finish = (int) $_POST['finish'];
$percent = 100 - round(($countLeft * 100 / $countAll), 1);
if(!$countLeft)
$finish = 1;
$APPLICATION->RestartBuffer();
header('Content-Type: application/x-javascript; charset='.LANG_CHARSET);
die(json_encode(array("finish" => $finish, "percent" => $percent)));
}
if (isset($_POST['back']) && $_POST['back']) {
$APPLICATION->IncludeAdminFile(
GetMessage('MODULE_INSTALL_TITLE'),
$_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/' . $this->MODULE_ID . '/install/step1.php'
);
}
//bitrix orderTypesList -- personTypes
$dbOrderTypesList = CSalePersonType::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y",
),
false,
false,
array()
);
//form order types ids arr
$orderTypesArr = array();
if ($arOrderTypesList = $dbOrderTypesList->Fetch()) {
do {
$orderTypesArr[$arOrderTypesList['ID']] = htmlspecialchars(trim($_POST['order-type-' . $arOrderTypesList['ID']]));
} while ($arOrderTypesList = $dbOrderTypesList->Fetch());
}
//bitrix deliveryTypesList
$dbDeliveryTypesList = CSaleDelivery::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y",
),
false,
false,
array()
);
//form delivery types ids arr
$deliveryTypesArr = array();
if ($arDeliveryTypesList = $dbDeliveryTypesList->Fetch()) {
do {
$deliveryTypesArr[$arDeliveryTypesList['ID']] = htmlspecialchars(trim($_POST['delivery-type-' . $arDeliveryTypesList['ID']]));
} while ($arDeliveryTypesList = $dbDeliveryTypesList->Fetch());
}
//bitrix paymentTypesList
$dbPaymentTypesList = CSalePaySystem::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y"
)
);
//form payment types ids arr
$paymentTypesArr = array();
if ($arPaymentTypesList = $dbPaymentTypesList->Fetch()) {
do {
$paymentTypesArr[$arPaymentTypesList['ID']] = htmlspecialchars(trim($_POST['payment-type-' . $arPaymentTypesList['ID']]));
} while ($arPaymentTypesList = $dbPaymentTypesList->Fetch());
}
//bitrix paymentStatusesList
$dbPaymentStatusesList = CSaleStatus::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"LID" => "ru", //ru
"ACTIVE" => "Y"
)
);
//form payment statuses ids arr
$paymentStatusesArr['Y'] = htmlspecialchars(trim($_POST['payment-status-Y']));
if ($arPaymentStatusesList = $dbPaymentStatusesList->Fetch()) {
do {
$paymentStatusesArr[$arPaymentStatusesList['ID']] = htmlspecialchars(trim($_POST['payment-status-' . $arPaymentStatusesList['ID']]));
} while ($arPaymentStatusesList = $dbPaymentStatusesList->Fetch());
}
//form payment ids arr
$paymentArr = array();
$paymentArr['Y'] = htmlspecialchars(trim($_POST['payment-Y']));
$paymentArr['N'] = htmlspecialchars(trim($_POST['payment-N']));
COption::SetOptionString($this->MODULE_ID, $this->CRM_ORDER_TYPES_ARR, serialize($orderTypesArr));
COption::SetOptionString($this->MODULE_ID, $this->CRM_DELIVERY_TYPES_ARR, serialize($deliveryTypesArr));
COption::SetOptionString($this->MODULE_ID, $this->CRM_PAYMENT_TYPES, serialize($paymentTypesArr));
COption::SetOptionString($this->MODULE_ID, $this->CRM_PAYMENT_STATUSES, serialize($paymentStatusesArr));
COption::SetOptionString($this->MODULE_ID, $this->CRM_PAYMENT, serialize($paymentArr));
COption::SetOptionString($this->MODULE_ID, $this->CRM_ORDER_LAST_ID, 0);
$APPLICATION->IncludeAdminFile(
GetMessage('MODULE_INSTALL_TITLE'),
$_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/' . $this->MODULE_ID . '/install/step3.php'
);
} else if ($step == 4) {
RegisterModule($this->MODULE_ID);
RegisterModuleDependences("sale", "OnSaleCancelOrder", $this->MODULE_ID, "ICrmOrderEvent", "onSaleCancelOrder");
RegisterModuleDependences("sale", "OnSalePayOrder", $this->MODULE_ID, "ICrmOrderEvent", "onSalePayOrder");
//agent
$dateAgent = new DateTime();
$intAgent = new DateInterval('PT60S'); // PT60S - 60 sec;
$dateAgent->add($intAgent);
CAgent::AddAgent(
"ICrmOrderActions::uploadOrdersAgent();",
$this->MODULE_ID,
"N",
600, // interval - 10 mins
$dateAgent->format('d.m.Y H:i:s'), // date of first check
"Y", // агент активен
$dateAgent->format('d.m.Y H:i:s'), // date of first start
30
);
$this->CopyFiles();
// statistic update
$api_host = COption::GetOptionString($this->MODULE_ID, $this->CRM_API_HOST_OPTION, 0);
$api_key = COption::GetOptionString($this->MODULE_ID, $this->CRM_API_KEY_OPTION, 0);
$this->INTARO_CRM_API = new \IntaroCrm\RestApi($api_host, $api_key);
$this->INTARO_CRM_API->statisticUpdate();
$APPLICATION->IncludeAdminFile(
GetMessage('MODULE_INSTALL_TITLE'),
$_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/' . $this->MODULE_ID . '/install/step4.php'
);
}
}
function DoUninstall() {
global $APPLICATION;
CAgent::RemoveAgent("ICrmOrderActions::uploadOrdersAgent();", $this->MODULE_ID);
COption::RemoveOption($this->MODULE_ID, $this->CRM_API_HOST_OPTION);
COption::RemoveOption($this->MODULE_ID, $this->CRM_API_KEY_OPTION);
COption::RemoveOption($this->MODULE_ID, $this->CRM_DELIVERY_TYPES_ARR);
COption::RemoveOption($this->MODULE_ID, $this->CRM_PAYMENT_TYPES);
COption::RemoveOption($this->MODULE_ID, $this->CRM_PAYMENT_STATUSES);
COption::RemoveOption($this->MODULE_ID, $this->CRM_PAYMENT);
COption::RemoveOption($this->MODULE_ID, $this->CRM_ORDER_LAST_ID);
UnRegisterModuleDependences("sale", "OnSalePayOrder", $this->MODULE_ID, "ICrmOrderEvent", "onSalePayOrder");
UnRegisterModuleDependences("sale", "OnSaleCancelOrder", $this->MODULE_ID, "ICrmOrderEvent", "onSaleCancelOrder");
$this->DeleteFiles();
UnRegisterModule($this->MODULE_ID);
$APPLICATION->IncludeAdminFile(
GetMessage('MODULE_UNINSTALL_TITLE'),
$_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/' . $this->MODULE_ID . '/install/unstep1.php'
);
}
function CopyFiles() {
CopyDirFiles(
$_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/' . $this->MODULE_ID . '/install/export/',
$_SERVER['DOCUMENT_ROOT'] . '/bitrix/php_interface/include/catalog_export/',
true, true
);
}
function DeleteFiles() {
unlink($_SERVER['DOCUMENT_ROOT'] . '/bitrix/php_interface/include/catalog_export/intarocrm_run.php');
unlink($_SERVER['DOCUMENT_ROOT'] . '/bitrix/php_interface/include/catalog_export/intarocrm_setup.php');
}
}

View file

@ -1,177 +0,0 @@
<?php
IncludeModuleLangFile(__FILE__);
//bitrix pyament Y/N
$arResult['bitrixPaymentList'][0]['NAME'] = GetMessage('PAYMENT_Y');
$arResult['bitrixPaymentList'][0]['ID'] = 'Y';
$arResult['bitrixPaymentList'][1]['NAME'] = GetMessage('PAYMENT_N');
$arResult['bitrixPaymentList'][1]['ID'] = 'N';
$defaultOrderTypes = array (
1 => 'eshop-individual',
2 => 'eshop-legal'
);
$defaultDelivTypes = array (
1 => 'courier',
2 => 'self-delivery'
);
$defaultPayTypes = array (
1 => 'cash',
5 => 'bank-transfer',
6 => 'bank-transfer'
);
$defaultPayStatuses = array (
'N' => 'new',
'P' => 'approval',
'F' => 'complete',
'Y' => 'cancel-other'
);
$defaultPayment = array(
'Y' => 'paid',
'N' => 'not-paid'
);
?>
<div class="adm-detail-content-item-block">
<form action="<?php echo $APPLICATION->GetCurPage() ?>" method="POST">
<?php echo bitrix_sessid_post(); ?>
<input type="hidden" name="lang" value="<?php echo LANGUAGE_ID ?>">
<input type="hidden" name="id" value="intaro.intarocrm">
<input type="hidden" name="install" value="Y">
<input type="hidden" name="step" value="3">
<table class="adm-detail-content-table edit-table" id="edit1_edit_table">
<tbody>
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('STEP_NAME'); ?></b></td>
</tr>
<tr align="center">
<td colspan="2"><b><?php echo GetMessage('INFO_1'); ?></b></td>
</tr>
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('DELIVERY_TYPES_LIST'); ?></b></td>
</tr>
<?php foreach($arResult['bitrixDeliveryTypesList'] as $bitrixDeliveryType): ?>
<tr>
<td width="50%" class="adm-detail-content-cell-l" name="<?php echo $bitrixDeliveryType['ID']; ?>">
<?php echo $bitrixDeliveryType['NAME']; ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="delivery-type-<?php echo $bitrixDeliveryType['ID']; ?>" class="typeselect">
<option value=""></option>
<?php foreach($arResult['deliveryTypesList'] as $deliveryType): ?>
<option value="<?php echo $deliveryType['code']; ?>"
<?php if($defaultDelivTypes[$bitrixDeliveryType['ID']] == $deliveryType['code']) echo 'selected'; ?>>
<?php echo $APPLICATION->ConvertCharset($deliveryType['name'], 'utf-8', SITE_CHARSET); ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('PAYMENT_TYPES_LIST'); ?></b></td>
</tr>
<?php foreach($arResult['bitrixPaymentTypesList'] as $bitrixPaymentType): ?>
<tr>
<td width="50%" class="adm-detail-content-cell-l" name="<?php echo $bitrixPaymentType['ID']; ?>">
<?php echo $bitrixPaymentType['NAME']; ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="payment-type-<?php echo $bitrixPaymentType['ID']; ?>" class="typeselect">
<option value=""></option>
<?php foreach($arResult['paymentTypesList'] as $paymentType): ?>
<option value="<?php echo $paymentType['code']; ?>"
<?php if($defaultPayTypes[$bitrixPaymentType['ID']] == $paymentType['code']) echo 'selected'; ?>>
<?php echo $APPLICATION->ConvertCharset($paymentType['name'], 'utf-8', SITE_CHARSET); ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('PAYMENT_STATUS_LIST'); ?></b></td>
</tr>
<?php foreach($arResult['bitrixPaymentStatusesList'] as $bitrixPaymentStatus): ?>
<tr>
<td width="50%" class="adm-detail-content-cell-l" name="<?php echo $bitrixPaymentStatus['ID']; ?>">
<?php echo $bitrixPaymentStatus['NAME']; ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="payment-status-<?php echo $bitrixPaymentStatus['ID']; ?>" class="typeselect">
<option value="" selected=""></option>
<?php foreach($arResult['paymentGroupList'] as $orderStatusGroup): if(!empty($orderStatusGroup['statuses'])) : ?>
<optgroup label="<?php echo $orderStatusGroup['name']; ?>">
<?php foreach($orderStatusGroup['statuses'] as $payment): ?>
<option value="<?php echo $arResult['paymentList'][$payment]['code']; ?>"
<?php if ($defaultPayStatuses[$bitrixPaymentStatus['ID']] == $arResult['paymentList'][$payment]['code']) echo 'selected'; ?>>
<?php echo $APPLICATION->ConvertCharset($arResult['paymentList'][$payment]['name'], 'utf-8', SITE_CHARSET); ?>
</option>
<?php endforeach; ?>
</optgroup>
<?php endif; endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('PAYMENT_LIST'); ?></b></td>
</tr>
<?php foreach($arResult['bitrixPaymentList'] as $bitrixPayment): ?>
<tr>
<td width="50%" class="adm-detail-content-cell-l" name="<?php echo $bitrixPayment['ID']; ?>">
<?php echo $bitrixPayment['NAME']; ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="payment-<?php echo $bitrixPayment['ID']; ?>" class="typeselect">
<option value=""></option>
<?php foreach($arResult['paymentStatusesList'] as $paymentStatus): ?>
<option value="<?php echo $paymentStatus['code']; ?>"
<?php if($defaultPayment[$bitrixPayment['ID']] == $paymentStatus['code']) echo 'selected'; ?>>
<?php echo $APPLICATION->ConvertCharset($paymentStatus['name'], 'utf-8', SITE_CHARSET); ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('ORDER_TYPES_LIST'); ?></b></td>
</tr>
<?php foreach($arResult['bitrixOrderTypesList'] as $bitrixOrderType): ?>
<tr>
<td width="50%" class="adm-detail-content-cell-l" name="<?php echo $bitrixOrderType['ID']; ?>">
<?php echo $bitrixOrderType['NAME']; ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="order-type-<?php echo $bitrixOrderType['ID']; ?>" class="typeselect">
<option value=""></option>
<?php foreach($arResult['orderTypesList'] as $orderType): ?>
<option value="<?php echo $orderType['code']; ?>"
<?php if($defaultOrderTypes[$bitrixOrderType['ID']] == $orderType['code']) echo 'selected'; ?>>
<?php echo $APPLICATION->ConvertCharset($orderType['name'], 'utf-8', SITE_CHARSET); ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<br />
<div style="padding: 1px 13px 2px; height:28px;">
<div align="right" style="float:right; width:50%; position:relative;">
<input type="submit" name="inst" value="<?php echo GetMessage("MOD_NEXT_STEP"); ?>" class="adm-btn-save">
</div>
<div align="left" style="float:right; width:50%; position:relative;">
<input type="submit" name="back" value="<?php echo GetMessage("MOD_PREV_STEP"); ?>" class="adm-btn-save">
</div>
</div>
</form>
</div>

View file

@ -1,5 +0,0 @@
<?
$arModuleVersion = array(
'VERSION' => '0.3.7',
'VERSION_DATE' => '2013-08-06 15:07:00',
);

View file

@ -1,124 +0,0 @@
<?php
$MESS["CET_ERROR_NO_NAME"] = "Введите название профиля выгрузки.";
$MESS["CET_STEP1"] = "Шаг";
$MESS["CET_STEP2"] = "из";
$MESS["CET_SAVE"] = "Сохранить";
$MESS["CET_ERROR_NO_IBLOCK1"] = "Информационный блок";
$MESS["CET_ERROR_NO_IBLOCK2"] = "не найден.";
$MESS["CET_ERROR_NO_FILENAME"] = "Не указано имя файла для экспорта.";
$MESS["CET_ERROR_NO_GROUPS"] = "Не указаны выгружаемые группы.";
$MESS["CET_ERROR_NO_PROFILE_NAME"] = "Введите название профиля выгрузки.";
$MESS["CET_SELECT_IBLOCK"] = "Выберите инфоблок";
$MESS["CET_SELECT_IBLOCK_EXT"] = "Выберите инфоблок для экспорта:";
$MESS["CET_SELECT_GROUP"] = "Выберите группы:";
$MESS["CET_FIRST_SELECT_IBLOCK"] = "Сначала выберите информационный блок";
$MESS["CET_ALL_GROUPS"] = "Все группы";
$MESS["CET_SERVER_NAME"] = "Доменное имя:";
$MESS["CET_SERVER_NAME_SET_CURRENT"] = "текущее";
$MESS["CET_SAVE_FILENAME"] = "Сохранить в файл:";
$MESS["CET_PROFILE_NAME"] = "Имя профиля:";
$MESS["CET_EXPORT"] = "Экспортировать";
$MESS["CET_ERROR_NO_IBLOCKS"] = "Не указаны выгружаемые информационные блоки.";
$MESS["CET_EXPORT_CATALOGS"] = "Каталоги для экспорта:";
$MESS["CET_CATALOG"] = "Каталог";
$MESS["CET_EXPORT2YANDEX"] = "Экспортировать в Яндекс.Товары";
$MESS["CATI_DATA_EXPORT"] = "Экспорт данных";
$MESS["CATI_NO_IBLOCK"] = "Информационный блок не выбран. Выгрузка невозможна.";
$MESS["CATI_NO_FORMAT"] = "Укажите формат файла данных и его свойства.";
$MESS["CATI_NO_DELIMITER"] = "Укажите символ-разделитель полей.";
$MESS["CATI_NO_SAVE_FILE"] = "Укажите файл для сохранения результата.";
$MESS["CATI_CANNOT_CREATE_FILE"] = "Ошибка создания файла данных.";
$MESS["CATI_NO_FIELDS"] = "Не заданы поля для экспорта.";
$MESS["CATI_SCHEME_EXISTS"] = "Схема с таким именем уже существует.";
$MESS["CATI_PAGE_TITLE"] = "Выгрузка каталога: шаг";
$MESS["CATI_NEXT_STEP"] = "Далее";
$MESS["CATI_INFOBLOCK"] = "Информационный блок для экспорта:";
$MESS["CATI_SCHEME_NAME"] = "Схема выгрузки:";
$MESS["CATI_NOT"] = "Нет";
$MESS["CATI_DELETE"] = "удалить";
$MESS["CATI_FIELDS"] = "Задайте соответствие полей в файле полям в базе";
$MESS["CATI_FI_ID"] = "Идентификатор";
$MESS["CATI_FI_NAME"] = "Название";
$MESS["CATI_FI_ACTIV"] = "Активность";
$MESS["CATI_FI_ACTIVFROM"] = "Активность с";
$MESS["CATI_FI_ACTIVTO"] = "Активность до";
$MESS["CATI_FI_CATIMG"] = "Картинка для списка";
$MESS["CATI_FI_CATDESCR"] = "Описание для списка";
$MESS["CATI_FI_DETIMG"] = "Картинка";
$MESS["CATI_FI_DETDESCR"] = "Описание";
$MESS["CATI_FI_UNIXML"] = "Уникальный идентификатор";
$MESS["CATI_FI_QUANT"] = "Количество";
$MESS["CATI_FI_WEIGHT"] = "Вес";
$MESS["CATI_FI_PROPS"] = "Свойство";
$MESS["CATI_FI_GROUP_LEV"] = "Группа уровня";
$MESS["CATI_FI_PRICE_TYPE"] = "Цена типа";
$MESS["CATI_FIELD"] = "поле";
$MESS["CATI_FORMAT_PROPS"] = "Задайте свойства формата файла";
$MESS["CATI_DELIMITERS"] = "С разделителями";
$MESS["CATI_DELIMITER_TYPE"] = "Разделитель полей";
$MESS["CATI_TAB"] = "табуляция";
$MESS["CATI_TZP"] = "точка с запятой";
$MESS["CATI_ZPT"] = "запятая";
$MESS["CATI_SPS"] = "пробел";
$MESS["CATI_OTR"] = "другой";
$MESS["CATI_SAVE_SCHEME"] = "Сохранить настройки как схему";
$MESS["CATI_SSCHEME_NAME"] = "Имя схемы";
$MESS["CATI_DATA_FILE_NAME"] = "Сохранить файл данных как...";
$MESS["CATI_DATA_FILE_NAME1"] = "Имя файла данных";
$MESS["CATI_SUCCESS"] = "Выгрузка завершена";
$MESS["CATI_SU_ALL"] = "Всего выгружено строк:";
$MESS["CATI_BACK"] = "Назад";
$MESS["CATI_FIRST_LINE_NAMES"] = "Первая строка содержит имена полей";
$MESS["CATI_SU_ALL1"] = "Скачать файл %DATA_URL% на свой компьютер";
$MESS["CATI_FIELDS_NEEDED"] = "Выгружать";
$MESS["CATI_FIELDS_NAMES"] = "Название поля";
$MESS["CATI_FIELDS_SORTING"] = "Порядок";
$MESS["CATI_NEXT_STEP_F"] = "Начать выгрузку";
$MESS["CATI_DATA_FILE_NAME1_DESC"] = "Если такой файл существует, то он будет перезаписан";
$MESS["CATI_TOO_MANY_TABLES"] = "Слишком большое объединение таблиц. Уменьшите количество экспортируемых свойств или типов цен.";
$MESS["EST_QUANTITY_FROM"] = "Покупаемое количество от";
$MESS["EST_QUANTITY_TO"] = "Покупаемое количество до";
$MESS["EST_PRICE_TYPE"] = "Тип цен \"#TYPE#\"";
$MESS["EST_PRICE_TYPE2"] = "Тип цен \"#NAME#\" (#TYPE#)";
$MESS["CAT_DETAIL_PROPS"] = "Детальные настройки";
$MESS["CAT_DETAIL_PROPS_RUN"] = "настроить";
$MESS["CET_IS_SKU"] = "Выбран инфоблок торговых предложений.";
$MESS["CET_USE_PARENT_SECT"] = "Использовать группы инфоблока товаров";
$MESS["CET_YAND_RUN_ERR_IBLOCK_ABSENT"] = "Инфоблок ##IBLOCK_ID# не существует";
$MESS["CET_YAND_RUN_ERR_PRODUCT_IBLOCK_ABSENT"] = "Инфоблок товаров ##IBLOCK_ID# не существует";
$MESS["CET_YAND_RUN_ERR_SECTION_SET_EMPTY"] = "Список групп не задан";
$MESS["CET_YAND_RUN_ERR_SETUP_FILE_ACCESS_DENIED"] = "Недостаточно прав для перезаписи файла #FILE#";
$MESS["CET_YAND_RUN_ERR_SETUP_FILE_OPEN_WRITING"] = "Невозможно открыть файл #FILE# для записи";
$MESS["CET_YAND_RUN_ERR_SETUP_FILE_WRITE"] = "Запись в файл #FILE# невозможна";
$MESS["CET_YAND_SELECT_IBLOCK"] = "Инфоблок для экспорта";
$MESS["CET_SELECT_IBLOCK_TYPE"] = "Выберите тип инфоблока";
$MESS["CET_YAND_GROUP_AND_OFFERS"] = "Группы и товары для импорта";
$MESS["CET_YAND_USE_IBLOCK_SITE"] = "Брать доменное имя из инфоблока";
$MESS["CET_ERROR_IBLOCK_PERM"] = "Недостаточно прав для работы с инфоблоком ##IBLOCK_ID#";
$MESS["YANDEX_ERR_SKU_SETTINGS_ABSENT"] = "Отсутствуют настройки экспорта торговых предложений";
$MESS["CES_ERROR_BAD_EXPORT_FILENAME"] = "Имя файла экспорта содержит запрещенные символы";
$MESS["CES_ERROR_BAD_EXPORT_FILENAME_EXTENTIONS"] = "Имя файла экспорта содержит запрещенное расширение";
$MESS["CES_ERROR_FORBIDDEN_EXPORT_FILENAME"] = "Запрещенное имя файла экспорта";
$MESS["CES_ERROR_PATH_WITHOUT_DEFAUT"] = "Экспорт может быть осуществлён только в папку, указанную в поле <b>Путь по умолчанию для экспортируемых файлов</b> настроек модуля.";
$MESS["CAT_ADM_CSV_EXP_TAB1"] = "Инфоблок";
$MESS["CAT_ADM_CSV_EXP_TAB1_TITLE"] = "Выбор информационного блока для экспорта";
$MESS["CAT_ADM_CSV_EXP_TAB2"] = "Параметры экспорта";
$MESS["CAT_ADM_CSV_EXP_TAB2_TITLE"] = "Настройка параметров экспорта";
$MESS["CAT_ADM_CSV_EXP_TAB3"] = "Результат";
$MESS["CAT_ADM_CSV_EXP_TAB3_TITLE"] = "Результат экспорта";
$MESS["CAT_ADM_CSV_EXP_IBLOCK_ID"] = "Инфоблок";
$MESS["CAT_ADM_CSV_EXP_ADD_SETTINGS"] = "Дополнительные настройки";
$MESS["CAT_ADM_CSV_EXP_EXPORT_FILES"] = "Выгружать файлы";
$MESS["CAT_ADM_CSV_EXP_TIME_STEP"] = "Время выполнения шага";
$MESS["CAT_ADM_CSV_EXP_TIME_STEP_COMMENT"] = "0 - загрузить все сразу<br>положительное значение - число секунд на выполнение одного шага";
$MESS["CAT_ADM_CSV_EXP_SEP_ELEMENTS"] = "Поля и свойства элементов";
$MESS["CAT_ADM_CSV_EXP_SEP_SECTIONS"] = "Поля разделов";
$MESS["CAT_ADM_CSV_EXP_SEP_SECTIONS_EXT"] = "Поля и пользовательские свойства разделов";
$MESS["CAT_ADM_CSV_EXP_SEP_PRODUCT"] = "Свойства товара";
$MESS["CAT_ADM_CSV_EXP_SEP_PRICES"] = "Цены";
$MESS["CAT_ADM_CSV_EXP_SEP_SKU"] = "Поля и свойства торговых предложений";
$MESS["CAT_ADM_CSV_EXP_DESCR_SECT_PROP"] = "Пользовательское свойство";
$MESS["CAT_ADM_CSV_EXP_SECTION_LEVEL"] = "Раздел уровня #LEVEL#";
$MESS["CATI_FI_PRICE_TYPE2"] = "Цена типа \"#TYPE#\"";
$MESS["CATI_FI_PRICE_TYPE3"] = "Цена типа \"#NAME#\" (#TYPE#)";
$MESS["CATI_FI_PRICE_CURRENCY"] = "в валюте #CURRENCY#";

View file

@ -1,13 +0,0 @@
<?php
$MESS ['MODULE_NAME'] = 'IntaroCRM';
$MESS ['MODULE_DESCRIPTION'] = 'Модуль интеграции с IntaroCRM — аналитической CRM для электронной коммерции';
$MESS ['MODULE_PARTNER_NAME'] = 'Интаро Софт';
$MESS ['MODULE_PARTNER_URI'] = 'http://intaro.ru';
$MESS ['MODULE_INSTALL_TITLE'] = 'Установка модуля';
$MESS ['MODULE_UNINSTALL_TITLE'] = 'Удаление модуля';
$MESS ['CANCELED'] = 'Флаг «Отменен»';
$MESS ['ERR_SALE'] = 'Отсутствует модуль sale! Дальнейшая установка невозможна.';
$MESS ['ERR_IBLOCK'] = 'Отсутствует модуль iblock! Дальнейшая установка невозможна.';
$MESS ['ERR_CATALOG'] = 'Отсутствует модуль catalog! Дальнейшая установка невозможна.';
$MESS ['ERR_CATALOG'] = 'Отсутствует модуль catalog! Дальнейшая установка невозможна.';
$MESS ['INTAROCRM_CURL_ERR'] = 'Для работы модуля интеграции с IntaroCRM требуется PHP-расширение CURL.';

View file

@ -1,11 +0,0 @@
<?php
$MESS ['STEP_NAME'] = 'Шаг 1';
$MESS ['MOD_NEXT_STEP'] = 'Следующий шаг';
$MESS ['ICRM_API_HOST'] = 'Адрес IntaroCRM:';
$MESS ['ICRM_API_KEY'] = 'Ключ авторизации:';
$MESS ['ERR_404'] = 'Возможно неверно введен адрес IntaroCRM.';
$MESS ['ERR_403'] = 'Неверный apiKey.';
$MESS ['ERR_0'] = 'Превышено время ожидания ответа от сервера.';
$MESS ['ERR_FIELDS_API_HOST'] = 'Неверно заполнены поля.';
$MESS ['INFO_1'] = 'Введите адрес экземпляра IntaroCRM (например, http://demo.intarocrm.ru) и API-ключ.';
$MESS ['INFO_2'] = 'API-ключ можно сгенерировать при регистрации магазина в IntaroCRM (Администрирование > Магазины).';

View file

@ -1,13 +0,0 @@
<?php
$MESS ['STEP_NAME'] = 'Шаг 2';
$MESS ['MOD_NEXT_STEP'] = 'Следующий шаг';
$MESS ['MOD_PREV_STEP'] = 'Предыдущий шаг';
$MESS ['DELIVERY_TYPES_LIST'] = 'Способы доставки';
$MESS ['PAYMENT_TYPES_LIST'] = 'Способы оплаты';
$MESS ['PAYMENT_STATUS_LIST'] = 'Статусы';
$MESS ['ORDER_TYPES_LIST'] = 'Типы заказа';
$MESS ['PAYMENT_LIST'] = 'Оплата';
$MESS ['PAYMENT_Y'] = 'Оплачен';
$MESS ['PAYMENT_N'] = 'Не оплачен';
$MESS ['CANCELED'] = 'Флаг «Отменен»';
$MESS ['INFO_1'] = ' Задайте соответствие между справочниками 1C-Битрикс и справочниками IntaroCRM.';

View file

@ -1,24 +0,0 @@
<?php
$MESS ['ICRM_OPTIONS_GENERAL_TAB'] = 'Общие настройки';
$MESS ['ICRM_OPTIONS_IMPORT_TAB'] = 'Настройки импората';
$MESS ['ICRM_CONN_SETTINGS'] = 'Настройка соединения';
$MESS ['ICRM_API_HOST'] = 'Адрес Intaro CRM:';
$MESS ['ICRM_API_KEY'] = 'Ключ авторизации:';
$MESS ['ICRM_OPTIONS_CATALOG_TAB'] = 'Настройка справочников';
$MESS ['DELIVERY_TYPES_LIST'] = 'Способы доставки';
$MESS ['PAYMENT_TYPES_LIST'] = 'Способы оплаты';
$MESS ['PAYMENT_STATUS_LIST'] = 'Статусы';
$MESS ['ORDER_TYPES_LIST'] = 'Типы заказа';
$MESS ['PAYMENT_LIST'] = 'Оплата';
$MESS ['PAYMENT_Y'] = 'Оплачен';
$MESS ['PAYMENT_N'] = 'Не оплачен';
$MESS ['ICRM_OPTIONS_SUBMIT_TITLE'] = 'Сохранить настройки';
$MESS ['ICRM_OPTIONS_SUBMIT_VALUE'] = 'Сохранить';
$MESS ['ERR_404'] = 'Возможно не верно введен адрес CRM.';
$MESS ['ERR_403'] = 'Неверный apiKey.';
$MESS ['ERR_0'] = 'Превышено время ожидания ответа от сервера.';
$MESS ['ICRM_OPTIONS_OK'] = 'Изменения успешно сохранены.';
$MESS ['CANCELED'] = 'Флаг «Отменен»';

View file

@ -1,400 +0,0 @@
<?php
IncludeModuleLangFile(__FILE__);
$mid = 'intaro.intarocrm';
$uri = $APPLICATION->GetCurPage() . '?mid=' . htmlspecialchars($mid) . '&lang=' . LANGUAGE_ID;
$CRM_API_HOST_OPTION = 'api_host';
$CRM_API_KEY_OPTION = 'api_key';
$CRM_ORDER_TYPES_ARR = 'order_types_arr';
$CRM_DELIVERY_TYPES_ARR = 'deliv_types_arr';
$CRM_PAYMENT_TYPES = 'pay_types_arr';
$CRM_PAYMENT_STATUSES = 'pay_statuses_arr';
$CRM_PAYMENT = 'payment_arr'; //order payment Y/N
$CRM_ORDER_LAST_ID = 'order_last_id';
if(!CModule::IncludeModule('intaro.intarocrm')
|| !CModule::IncludeModule('sale'))
return;
$_GET['errc'] = htmlspecialchars(trim($_GET['errc']));
$_GET['ok'] = htmlspecialchars(trim($_GET['ok']));
if($_GET['errc']) echo CAdminMessage::ShowMessage(GetMessage($_GET['errc']));
if($_GET['ok'] && $_GET['ok'] == 'Y') echo CAdminMessage::ShowNote(GetMessage('ICRM_OPTIONS_OK'));
$arResult = array();
//update connection settings
if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) {
$api_host = htmlspecialchars(trim($_POST['api_host']));
$api_key = htmlspecialchars(trim($_POST['api_key']));
if($api_host && $api_key) {
$api = new IntaroCrm\RestApi($api_host, $api_key);
$api->paymentStatusesList();
//check connection & apiKey valid
if((int) $api->getStatusCode() != 200) {
$uri .= '&errc=ERR_' . $api->getStatusCode();
LocalRedirect($uri);
} else {
COption::SetOptionString($mid, 'api_host', $api_host);
COption::SetOptionString($mid, 'api_key', $api_key);
}
}
//bitrix orderTypesList -- personTypes
$dbOrderTypesList = CSalePersonType::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y",
),
false,
false,
array()
);
//form order types ids arr
$orderTypesArr = array();
if ($arOrderTypesList = $dbOrderTypesList->Fetch()) {
do {
$orderTypesArr[$arOrderTypesList['ID']] = $_POST['order-type-' . $arOrderTypesList['ID']];
} while ($arOrderTypesList = $dbOrderTypesList->Fetch());
}
//bitrix deliveryTypesList
$dbDeliveryTypesList = CSaleDelivery::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y",
),
false,
false,
array()
);
//form delivery types ids arr
$deliveryTypesArr = array();
if ($arDeliveryTypesList = $dbDeliveryTypesList->Fetch()) {
do {
$deliveryTypesArr[$arDeliveryTypesList['ID']] = htmlspecialchars(trim($_POST['delivery-type-' . $arDeliveryTypesList['ID']]));
} while ($arDeliveryTypesList = $dbDeliveryTypesList->Fetch());
}
//bitrix paymentTypesList
$dbPaymentTypesList = CSalePaySystem::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y"
)
);
//form payment types ids arr
$paymentTypesArr = array();
if ($arPaymentTypesList = $dbPaymentTypesList->Fetch()) {
do {
$paymentTypesArr[$arPaymentTypesList['ID']] = htmlspecialchars(trim($_POST['payment-type-' . $arPaymentTypesList['ID']]));
} while ($arPaymentTypesList = $dbPaymentTypesList->Fetch());
}
//bitrix paymentStatusesList
$dbPaymentStatusesList = CSaleStatus::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"LID" => "ru", //ru
"ACTIVE" => "Y"
)
);
//form payment statuses ids arr
$paymentStatusesArr['Y'] = htmlspecialchars(trim($_POST['payment-status-Y']));
if ($arPaymentStatusesList = $dbPaymentStatusesList->Fetch()) {
do {
$paymentStatusesArr[$arPaymentStatusesList['ID']] = htmlspecialchars(trim($_POST['payment-status-' . $arPaymentStatusesList['ID']]));
} while ($arPaymentStatusesList = $dbPaymentStatusesList->Fetch());
}
//form payment ids arr
$paymentArr = array();
$paymentArr['Y'] = htmlspecialchars(trim($_POST['payment-Y']));
$paymentArr['N'] = htmlspecialchars(trim($_POST['payment-N']));
COption::SetOptionString($mid, $CRM_ORDER_TYPES_ARR, serialize($orderTypesArr));
COption::SetOptionString($mid, $CRM_DELIVERY_TYPES_ARR, serialize($deliveryTypesArr));
COption::SetOptionString($mid, $CRM_PAYMENT_TYPES, serialize($paymentTypesArr));
COption::SetOptionString($mid, $CRM_PAYMENT_STATUSES, serialize($paymentStatusesArr));
COption::SetOptionString($mid, $CRM_PAYMENT, serialize($paymentArr));
$uri .= '&ok=Y';
LocalRedirect($uri);
} else {
$api_host = COption::GetOptionString($mid, $CRM_API_HOST_OPTION, 0);
$api_key = COption::GetOptionString($mid, $CRM_API_KEY_OPTION, 0);
$api = new IntaroCrm\RestApi($api_host, $api_key);
//prepare crm lists
$arResult['orderTypesList'] = $api->orderTypesList();
$arResult['deliveryTypesList'] = $api->deliveryTypesList();
$arResult['paymentTypesList'] = $api->paymentTypesList();
$arResult['paymentStatusesList'] = $api->paymentStatusesList(); // --statuses
$arResult['paymentList'] = $api->orderStatusesList();
$arResult['paymentGroupList'] = $api->orderStatusGroupsList(); // -- statuses groups
//check connection & apiKey valid
if ((int) $api->getStatusCode() != 200)
echo CAdminMessage::ShowMessage(GetMessage('ERR_' . $api->getStatusCode()));
//bitrix orderTypesList -- personTypes
$dbOrderTypesList = CSalePersonType::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y",
),
false,
false,
array()
);
if ($arOrderTypesList = $dbOrderTypesList->Fetch()) {
do {
$arResult['bitrixOrderTypesList'][] = $arOrderTypesList;
} while ($arOrderTypesList = $dbOrderTypesList->Fetch());
}
//bitrix deliveryTypesList
$dbDeliveryTypesList = CSaleDelivery::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y",
),
false,
false,
array()
);
if ($arDeliveryTypesList = $dbDeliveryTypesList->Fetch()) {
do {
$arResult['bitrixDeliveryTypesList'][] = $arDeliveryTypesList;
} while ($arDeliveryTypesList = $dbDeliveryTypesList->Fetch());
}
//bitrix paymentTypesList
$dbPaymentTypesList = CSalePaySystem::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y"
)
);
if ($arPaymentTypesList = $dbPaymentTypesList->Fetch()) {
do {
$arResult['bitrixPaymentTypesList'][] = $arPaymentTypesList;
} while ($arPaymentTypesList = $dbPaymentTypesList->Fetch());
}
//bitrix paymentStatusesList
$dbPaymentStatusesList = CSaleStatus::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"LID" => "ru", //ru
"ACTIVE" => "Y"
)
);
if ($arPaymentStatusesList = $dbPaymentStatusesList->Fetch()) {
do {
$arResult['bitrixPaymentStatusesList'][] = $arPaymentStatusesList;
} while ($arPaymentStatusesList = $dbPaymentStatusesList->Fetch());
}
$arResult['bitrixPaymentStatusesList'][] = array(
'ID' => 'Y',
'NAME' => GetMessage('CANCELED')
);
//bitrix pyament Y/N
$arResult['bitrixPaymentList'][0]['NAME'] = GetMessage('PAYMENT_Y');
$arResult['bitrixPaymentList'][0]['ID'] = 'Y';
$arResult['bitrixPaymentList'][1]['NAME'] = GetMessage('PAYMENT_N');
$arResult['bitrixPaymentList'][1]['ID'] = 'N';
//saved cat params
$optionsOrderTypes = unserialize(COption::GetOptionString($mid, $CRM_ORDER_TYPES_ARR, 0));
$optionsDelivTypes = unserialize(COption::GetOptionString($mid, $CRM_DELIVERY_TYPES_ARR, 0));
$optionsPayTypes = unserialize(COption::GetOptionString($mid, $CRM_PAYMENT_TYPES, 0));
$optionsPayStatuses = unserialize(COption::GetOptionString($mid, $CRM_PAYMENT_STATUSES, 0)); // --statuses
$optionsPayment = unserialize(COption::GetOptionString($mid, $CRM_PAYMENT, 0));
$aTabs = array(
array(
"DIV" => "edit1",
"TAB" => GetMessage('ICRM_OPTIONS_GENERAL_TAB'),
"ICON" => "",
"TITLE" => GetMessage('ICRM_OPTIONS_GENERAL_CAPTION')
),
array(
"DIV" => "edit2",
"TAB" => GetMessage('ICRM_OPTIONS_CATALOG_TAB'),
"ICON" => '',
"TITLE" => GetMessage('ICRM_OPTIONS_CATALOG_CAPTION')
),
);
$tabControl = new CAdminTabControl("tabControl", $aTabs);
$tabControl->Begin();
?>
<form method="POST" action="<?php echo $uri; ?>" id="FORMACTION">
<?php
echo bitrix_sessid_post();
$tabControl->BeginNextTab();
?>
<input type="hidden" name="tab" value="catalog">
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('ICRM_CONN_SETTINGS'); ?></b></td>
</tr>
<tr>
<td width="50%" class="adm-detail-content-cell-l"><?php echo GetMessage('ICRM_API_HOST'); ?></td>
<td width="50%" class="adm-detail-content-cell-r"><input type="text" id="api_host" name="api_host" value="<?php echo $api_host; ?>"></td>
</tr>
<tr>
<td width="50%" class="adm-detail-content-cell-l"><?php echo GetMessage('ICRM_API_KEY'); ?></td>
<td width="50%" class="adm-detail-content-cell-r"><input type="text" id="api_key" name="api_key" value="<?php echo $api_key; ?>"></td>
</tr>
<?php $tabControl->BeginNextTab(); ?>
<input type="hidden" name="tab" value="catalog">
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('DELIVERY_TYPES_LIST'); ?></b></td>
</tr>
<?php foreach($arResult['bitrixDeliveryTypesList'] as $bitrixDeliveryType): ?>
<tr>
<td width="50%" class="adm-detail-content-cell-l" name="<?php echo $bitrixDeliveryType['ID']; ?>">
<?php echo $bitrixDeliveryType['NAME']; ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="delivery-type-<?php echo $bitrixDeliveryType['ID']; ?>" class="typeselect">
<option value=""></option>
<?php foreach($arResult['deliveryTypesList'] as $deliveryType): ?>
<option value="<?php echo $deliveryType['code']; ?>" <?php if ($optionsDelivTypes[$bitrixDeliveryType['ID']] == $deliveryType['code']) echo 'selected'; ?>>
<?php echo $APPLICATION->ConvertCharset($deliveryType['name'], 'utf-8', SITE_CHARSET); ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('PAYMENT_TYPES_LIST'); ?></b></td>
</tr>
<?php foreach($arResult['bitrixPaymentTypesList'] as $bitrixPaymentType): ?>
<tr>
<td width="50%" class="adm-detail-content-cell-l" name="<?php echo $bitrixPaymentType['ID']; ?>">
<?php echo $bitrixPaymentType['NAME']; ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="payment-type-<?php echo $bitrixPaymentType['ID']; ?>" class="typeselect">
<option value="" selected=""></option>
<?php foreach($arResult['paymentTypesList'] as $paymentType): ?>
<option value="<?php echo $paymentType['code']; ?>" <?php if ($optionsPayTypes[$bitrixPaymentType['ID']] == $paymentType['code']) echo 'selected'; ?>>
<?php echo $APPLICATION->ConvertCharset($paymentType['name'], 'utf-8', SITE_CHARSET); ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('PAYMENT_STATUS_LIST'); ?></b></td>
</tr>
<?php foreach($arResult['bitrixPaymentStatusesList'] as $bitrixPaymentStatus): ?>
<tr>
<td width="50%" class="adm-detail-content-cell-l" name="<?php echo $bitrixPaymentStatus['ID']; ?>">
<?php echo $bitrixPaymentStatus['NAME']; ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="payment-status-<?php echo $bitrixPaymentStatus['ID']; ?>" class="typeselect">
<option value=""></option>
<?php foreach($arResult['paymentGroupList'] as $orderStatusGroup): if(!empty($orderStatusGroup['statuses'])) : ?>
<optgroup label="<?php echo $orderStatusGroup['name']; ?>">
<?php foreach($orderStatusGroup['statuses'] as $payment): ?>
<option value="<?php echo $arResult['paymentList'][$payment]['code']; ?>" <?php if ($optionsPayStatuses[$bitrixPaymentStatus['ID']] == $arResult['paymentList'][$payment]['code']) echo 'selected'; ?>>
<?php echo $APPLICATION->ConvertCharset($arResult['paymentList'][$payment]['name'], 'utf-8', SITE_CHARSET); ?>
</option>
<?php endforeach; ?>
</optgroup>
<?php endif; endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('PAYMENT_LIST'); ?></b></td>
</tr>
<?php foreach($arResult['bitrixPaymentList'] as $bitrixPayment): ?>
<tr>
<td width="50%" class="adm-detail-content-cell-l" name="<?php echo $bitrixPayment['ID']; ?>">
<?php echo $bitrixPayment['NAME']; ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="payment-<?php echo $bitrixPayment['ID']; ?>" class="typeselect">
<option value=""></option>
<?php foreach($arResult['paymentStatusesList'] as $paymentStatus): ?>
<option value="<?php echo $paymentStatus['code']; ?>" <?php if ($optionsPayment[$bitrixPayment['ID']] == $paymentStatus['code']) echo 'selected'; ?>>
<?php echo $APPLICATION->ConvertCharset($paymentStatus['name'], 'utf-8', SITE_CHARSET); ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('ORDER_TYPES_LIST'); ?></b></td>
</tr>
<?php foreach($arResult['bitrixOrderTypesList'] as $bitrixOrderType): ?>
<tr>
<td width="50%" class="adm-detail-content-cell-l" name="<?php echo $bitrixOrderType['ID']; ?>">
<?php echo $bitrixOrderType['NAME']; ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="order-type-<?php echo $bitrixOrderType['ID']; ?>" class="typeselect">
<option value=""></option>
<?php foreach($arResult['orderTypesList'] as $orderType): ?>
<option value="<?php echo $orderType['code']; ?>" <?php if ($optionsOrderTypes[$bitrixOrderType['ID']] == $orderType['code']) echo 'selected'; ?>>
<?php echo $APPLICATION->ConvertCharset($orderType['name'], 'utf-8', SITE_CHARSET); ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
<?php $tabControl->BeginNextTab(); ?>
<?php $tabControl->Buttons(); ?>
<input type="hidden" name="Update" value="Y" />
<input type="submit" title="<?php echo GetMessage('ICRM_OPTIONS_SUBMIT_TITLE'); ?>" value="<?php echo GetMessage('ICRM_OPTIONS_SUBMIT_VALUE'); ?>" name="btn-update" class="adm-btn-save" />
<?php $tabControl->End(); ?>
</form>
<?php } ?>

View file

@ -0,0 +1,12 @@
<?php
return [
'controllers' => [
'value' => [
'namespaces' => [
'\\Intaro\\RetailCrm\\Controller' => 'api'
],
],
'readonly' => true,
]
];

View file

@ -0,0 +1,357 @@
<?php
/**
* Class RetailcrmClasspathBuilder.
* Builds classpath for Bitrix autoloader. Contains some hardcoded things, which will go away when everything refactored.
*/
class RetailcrmClasspathBuilder
{
/**
* File extension as a string. Defaults to ".php".
* @var string
*/
protected $fileExt = 'php';
/**
* @var string $moduleId
*/
protected $moduleId = 'intaro.retailcrm';
/**
* @var string
*/
protected $customizedFilesPath = '/bitrix/php_interface/retailcrm/';
/**
* @var string
*/
protected $customizedClassesPath = '../../php_interface/retailcrm/';
/**
* The topmost directory where recursion should begin. Default: `classes/general`. Relative to the __DIR__.
* @var string
*/
protected $path = 'classes/general';
/**
* @var string
*/
protected $bitrixModulesPath = 'bitrix/modules';
/**
* Do not include directory paths as namespaces.
* @var bool
*/
protected $disableNamespaces;
/**
* Bitrix document root
* @var string
*/
protected $documentRoot;
/**
* @var string
*/
protected $version;
/**
* @var array $result
*/
protected $result = [];
/**
* @var array $notIncluded
*/
protected $notIncluded = [];
protected $directories = [];
/**
* These classes can be customized, in which case they would be replaced with files from
* directory <root>/bitrix/php_interface/retailcrm
*
* Array format:
* [
* 'class path with namespace' => 'file name'
* ]
*/
protected static $customizableClasses = [
'classes' => [
'RestNormalizer' => 'RestNormalizer.php',
'Logger' => 'Logger.php',
'RetailCrm\ApiClient' => 'ApiClient_v5.php',
'RetailCrm\Http\Client' => 'Client.php',
'RCrmActions' => 'RCrmActions.php',
'RetailCrmUser' => 'RetailCrmUser.php',
'RetailCrmICML' => 'RetailCrmICML.php',
'RetailCrmInventories' => 'RetailCrmInventories.php',
'RetailCrmPrices' => 'RetailCrmPrices.php',
'RetailCrmCollector' => 'RetailCrmCollector.php',
'RetailCrmUa' => 'RetailCrmUa.php',
'RetailCrmEvent' => 'RetailCrmEvent.php',
'RetailCrmCorporateClient' => 'RetailCrmCorporateClient.php'
],
'lib/icml' => [
'Intaro\RetailCrm\Icml\XmlOfferBuilder' => 'xmlofferbuilder.php',
'Intaro\RetailCrm\Icml\XmlOfferDirector' => 'xmlofferdirector.php',
'Intaro\RetailCrm\Icml\IcmlWriter' => 'icmlwriter.php',
'Intaro\RetailCrm\Icml\QueryParamsMolder' => 'queryparamsmolder.php',
'Intaro\RetailCrm\Icml\SettingsService' => 'settingsservice.php',
'Intaro\RetailCrm\Icml\XmlCategoryDirector' => 'xmlcategorydirector.php',
'Intaro\RetailCrm\Icml\XmlCategoryFactory' => 'xmlcategoryfactory.php',
'Intaro\RetailCrm\Icml\IcmlDirector' => 'icmldirector.php'
]
];
/**
* These classes can be customized, in which case they would be replaced with files from
* directory <root>/bitrix/php_interface/retailcrm
* Customized versions have fixed name, and original versions name depends on API version
*
* Array format:
* [
* 'class path with namespace' => ['customized file name', 'original file name with %s for API version']
* ]
*/
protected static $versionedClasses = [
'classes' => [
'RetailCrm\ApiClient' => ['ApiClient.php', 'ApiClient_%s.php'],
'RetailCrmOrder' => ['RetailCrmOrder.php', 'RetailCrmOrder_%s.php'],
'RetailCrmHistory' => ['RetailCrmHistory.php', 'RetailCrmHistory_%s.php'],
'RetailCrmCart' => ['RetailCrmCart.php', 'RetailCrmCart_%s.php']
],
'lib/icml' => []
];
/**
* These classes will be ignored while loading from original files
*/
protected static $ignoredClasses = [
'classes' => [
'ApiClient_v5.php',
'RetailCrmOrder_v5.php',
'RetailCrmHistory_v5.php',
'RetailCrmCart_v5.php',
],
'lib/icml' => []
];
/**
* These namespaces are hardcoded.
*/
protected static $hardcodedNamespaces = [
'classes' => [
'RetailCrm\Response\ApiResponse' => 'ApiResponse.php',
'RetailCrm\Exception\InvalidJsonException' => 'InvalidJsonException.php',
'RetailCrm\Exception\CurlException' => 'CurlException.php'
],
'lib/icml' => []
];
protected function buildCustomizableClasspath()
{
foreach (static::$customizableClasses[$this->path] as $className => $fileName) {
if (file_exists($this->documentRoot . $this->customizedFilesPath . $fileName)) {
$this->result[$className] = $this->customizedClassesPath . $fileName;
} else {
$this->notIncluded[$className] = $fileName;
}
}
}
protected function buildVersionedClasspath()
{
foreach (static::$versionedClasses[$this->path] as $className => $fileNames) {
if (file_exists($this->documentRoot . $this->customizedFilesPath . $fileNames[0])) {
$this->result[$className] = $this->customizedClassesPath . $fileNames[0];
} else {
$this->notIncluded[$className] = sprintf($fileNames[1], $this->version);
}
}
}
/**
* Traverse through directories, build include paths
* @return $this
*/
public function build(): self
{
foreach ($this->directories as $path) {
$this->path = $path;
$directory = new RecursiveDirectoryIterator(
$this->getSearchPath(),
RecursiveDirectoryIterator::SKIP_DOTS
);
$fileIterator = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::LEAVES_ONLY);
$this->buildCustomizableClasspath();
$this->buildVersionedClasspath();
$notIncludedClasses = array_flip($this->notIncluded);
$hardcodedNamespaces = array_flip(static::$hardcodedNamespaces[$path]);
/** @var \SplFileObject $file */
foreach ($fileIterator as $file) {
$fileNameWithoutExt = str_ireplace('.' . $this->fileExt, '', $file->getFilename());
if ($file->getExtension() !== $this->fileExt) {
continue;
}
if (in_array($file->getFilename(), static::$customizableClasses[$path])
|| in_array($file->getFilename(), static::$ignoredClasses[$path])
) {
if (in_array($file->getFilename(), $this->notIncluded)) {
$this->result[$notIncludedClasses[$file->getFilename()]] = $this->getImportPath($file->getPathname());
}
continue;
}
if (in_array($file->getFilename(), static::$hardcodedNamespaces[$path])) {
$this->result[$hardcodedNamespaces[$file->getFilename()]] = $this->getImportPath($file->getPathname());
} else {
$this->result[$this->getImportClass($fileNameWithoutExt, $file->getPath())] = $this->getImportPath($file->getPathname());
}
}
}
return $this;
}
/**
* Sets the $fileExt property
*
* @param string $fileExt The file extension used for class files. Default is "php".
*
* @return \RetailcrmClasspathBuilder
*/
public function setFileExt($fileExt)
{
$this->fileExt = $fileExt;
return $this;
}
/**
* @param string $documentRoot
*
* @return RetailcrmClasspathBuilder
*/
public function setDocumentRoot(string $documentRoot): RetailcrmClasspathBuilder
{
$this->documentRoot = $documentRoot;
return $this;
}
/**
* Sets the $path property
*
* @param array $path Top path to load files
*
* @return \RetailcrmClasspathBuilder
*/
public function setPath(array $path)
{
$this->path = $path;
return $this;
}
/**
* @param array $directories
* @return \RetailcrmClasspathBuilder
*/
public function setDirectories(array $directories)
{
$this->directories = $directories;
return $this;
}
/**
* @param mixed $disableNamespaces
*
* @return RetailcrmClasspathBuilder
*/
public function setDisableNamespaces($disableNamespaces)
{
$this->disableNamespaces = $disableNamespaces;
return $this;
}
/**
* @param string $moduleId
*
* @return RetailcrmClasspathBuilder
*/
public function setModuleId(string $moduleId): RetailcrmClasspathBuilder
{
$this->moduleId = $moduleId;
return $this;
}
/**
* @param string $version
*
* @return RetailcrmClasspathBuilder
*/
public function setVersion(string $version): RetailcrmClasspathBuilder
{
$this->version = $version;
return $this;
}
/**
* @return array
*/
public function getResult(): array
{
return $this->result;
}
/**
* @return string
*/
protected function getSearchPath(): string
{
return $this->documentRoot . DIRECTORY_SEPARATOR . $this->bitrixModulesPath . DIRECTORY_SEPARATOR
. $this->moduleId. DIRECTORY_SEPARATOR . $this->path;
}
/**
* @param string $filePath
*
* @return string
*/
protected function getImportPath(string $filePath): string
{
return (string) str_ireplace(implode(DIRECTORY_SEPARATOR, [
$this->documentRoot,
$this->bitrixModulesPath,
$this->moduleId
]) . DIRECTORY_SEPARATOR, '', $filePath);
}
/**
* @param string $fileNameWithoutExt
* @param string $filePath
*
* @return string
*/
protected function getImportClass(string $fileNameWithoutExt, string $filePath): string
{
if ($this->disableNamespaces) {
return $fileNameWithoutExt;
}
$importClass = str_ireplace($this->getSearchPath(), '', $filePath). '\\' . $fileNameWithoutExt;
if (strlen($importClass) > 0 && $importClass[0] === '/') {
$importClass = '\\' . substr($importClass, 1);
}
return (string) str_replace(DIRECTORY_SEPARATOR, '\\', $importClass);
}
}

View file

@ -0,0 +1,73 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class AbstractBuilder
*
* @category RetailCRM
* @package RetailCRM
*/
abstract class AbstractBuilder
{
/**
* @param string $key
* @param mixed $default
* @return mixed|null
*/
public function getValue($key, $default = NULL)
{
return isset($this->dataCrm[$key]) && !empty($this->dataCrm[$key]) ? $this->dataCrm[$key] : $default;
}
/**
* @param array $array
* @param string $key
* @param mixed $default
* @return mixed|null
*/
public function getValueArray($array, $key, $default = NULL)
{
return isset($this->dataCrm[$array][$key]) && !empty($this->dataCrm[$array][$key]) ? $this->dataCrm[$array][$key] : $default;
}
/**
* @param array $array
* @param array $symbols
* @return array
*/
public function arrayClear(array $array, array $symbols = array('', 0, null))
{
return array_diff($array, $symbols);
}
/**
* @param $data
* @return array
*/
public function objectToArray($data)
{
return $this->arrayClear(json_decode(json_encode($data), true));
}
/**
*
* @param string|array|\SplFixedArray $str in utf-8
*
* @return array|bool|\SplFixedArray|string $str in SITE_CHARSET
* @global $APPLICATION
*/
public function fromJSON($str)
{
global $APPLICATION;
return $APPLICATION->ConvertCharset($str, 'utf-8', SITE_CHARSET);
}
}

View file

@ -0,0 +1,88 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class AddressBuilder
*
* @category RetailCRM
* @package RetailCRM
*/
class AddressBuilder extends AbstractBuilder implements RetailcrmBuilderInterface
{
/**
* @var CustomerAddress
*/
private $customerAddress;
/** @var array $dataCrm customerHistory */
protected $dataCrm;
/**
* CustomerBuilder constructor.
*/
public function __construct()
{
$this->customerAddress = new CustomerAddress();
}
/**
* @param array $dataCrm
* @return $this|RetailcrmBuilderInterface
*/
public function setDataCrm($dataCrm)
{
$this->dataCrm = $dataCrm;
return $this;
}
/**
* @param $data
* @return $this
*/
public function setCustomerAddress($data)
{
$this->customerAddress = $data;
return $this;
}
/**
* @return CustomerAddress
*/
public function getCustomerAddress()
{
return $this->customerAddress;
}
public function build()
{
$this->customerAddress->setText($this->getValue('text'))
->setNotes($this->getValue('notes'))
->setBuilding($this->getValue('building'))
->setBlock($this->getValue('block'))
->setCity($this->getValue('city'))
->setFlat($this->getValue('flat'))
->setHouse($this->getValue('house'))
->setFloor($this->getValue('floor'))
->setCountry($this->getValue('countryIso'))
->setIndex($this->getValue('index'))
->setIntercomCode($this->getValue('intercomCode'))
->setMetro($this->getValue('metro'))
->setRegion($this->getValue('region'))
->setStreet($this->getValue('street'));
return $this;
}
public function reset(): void
{
$this->customerAddress = new CustomerAddress();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,276 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class CorporateCustomerBuilder
*
* @category RetailCRM
* @package RetailCRM
*/
class CorporateCustomerBuilder extends AbstractBuilder implements RetailcrmBuilderInterface
{
/** @var Customer */
protected $customer;
/**@var CustomerBuilder */
protected $customerBuilder;
/** @var CustomerAddress */
protected $customerAddress;
/** @var array $dataCrm customerHistory */
protected $dataCrm;
/** @var array $corporateContact */
protected $corporateContact;
/** @var int $orderCustomerExtId */
protected $orderCustomerExtId;
/** @var BuyerProfile */
public $buyerProfile;
/** @var bool $registerNewUser */
protected $registerNewUser;
/** @var int $registeredUserID */
protected $registeredUserID;
/**@var AddressBuilder */
protected $addressBuilder;
/**@var array $contragentTypes */
protected $contragentTypes;
/**
* CorporateCustomerBuilder constructor.
*/
public function __construct()
{
$this->customer = new Customer();
$this->customerBuilder = new CustomerBuilder();
$this->customerAddress = new CustomerAddress();
$this->buyerProfile = new BuyerProfile();
$this->addressBuilder = new AddressBuilder();
}
/**
* @param Customer $customer
* @return $this
*/
public function setCustomer($customer)
{
$this->customer = $customer;
return $this;
}
/**
* @return Customer
*/
public function getCustomer()
{
return $this->customer;
}
/**
* @param CustomerBuilder $customerBuilder
* @return $this
*/
public function setCustomerBuilder($customerBuilder)
{
$this->$customerBuilder = $customerBuilder;
return $this;
}
/**
* @return CustomerBuilder
*/
public function getCustomerBuilder()
{
return $this->customerBuilder;
}
/**
* @param CustomerAddress $customerAddress
* @return $this
*/
public function setCustomerAddress($customerAddress)
{
$this->customerAddress = $customerAddress;
return $this;
}
/**
* @return CustomerAddress
*/
public function getCustomerAddress()
{
return $this->customerAddress;
}
/**
* @param array $dataCrm
* @return $this
*/
public function setDataCrm($dataCrm)
{
$this->dataCrm = $dataCrm;
return $this;
}
/**
* @param int $registeredUserID
* @return $this
*/
public function setRegisteredUserID($registeredUserID)
{
$this->registeredUserID = $registeredUserID;
return $this;
}
/**
* @return bool
*/
public function getRegisterNewUser()
{
return $this->registerNewUser;
}
/**
* @return int
*/
public function getRegisteredUserID()
{
return $this->registeredUserID;
}
/**
* @param int $data
* @return $this
*/
public function setOrderCustomerExtId($data)
{
$this->orderCustomerExtId = $data;
return $this;
}
/**
* @return int
*/
public function getOrderCustomerExtId()
{
return $this->orderCustomerExtId;
}
/**
* @param array $data
* @return $this
*/
public function setCorporateContact($data)
{
$this->corporateContact = $data;
return $this;
}
/**
* @return array
*/
public function getCorporateContact()
{
return $this->corporateContact;
}
/**
* @return BuyerProfile
*/
public function getBuyerProfile()
{
return $this->buyerProfile;
}
/**
* @param array $contragentTypes
* @return $this
*/
public function setContragentTypes($contragentTypes)
{
$this->contragentTypes = $contragentTypes;
return $this;
}
public function build()
{
if (isset($this->dataCrm['contact'])) {
$this->customerBuilder->setDataCrm($this->dataCrm['contact'])->build();
$this->corporateContact = $this->customerBuilder->getCustomer();
$this->customer = $this->customerBuilder->getCustomer();
} elseif (isset($this->dataCrm['customer'])) {
$this->customerBuilder->setDataCrm($this->dataCrm['customer'])->build();
$this->corporateContact = $this->customerBuilder->getCustomer();
$this->customer = $this->customerBuilder->getCustomer();
} else {
$this->corporateContact = null;
$this->customer = null;
}
if (isset($this->dataCrm['company']['address'])) {
$this->buildAddress();
}
if (isset($this->dataCrm['company'])) {
$this->buildBuyerProfile();
}
}
public function buildBuyerProfile()
{
if (RetailCrmOrder::isOrderCorporate($this->dataCrm) && !empty($this->dataCrm['company'])) {
$this->buyerProfile->setName($this->dataCrm['company']['name'])
->setUserId($this->dataCrm['contact']['externalId'])
->setPersonTypeId($this->contragentTypes['legal-entity']);
}
}
public function buildAddress()
{
if (isset($this->dataCrm['company']['address'])) {
$this->addressBuilder->setDataCrm($this->dataCrm['company']['address'])->build();
$this->customerAddress = $this->addressBuilder->getCustomerAddress();
} else {
$this->customerAddress = null;
}
}
/**
* @param string $login
* @return $this
*/
public function setLogin($login)
{
$this->customerBuilder->setLogin($login);
return $this;
}
/**
* @param string $email
* @return $this
*/
public function setEmail($email)
{
$this->customerBuilder->setEmail($email);
return $this;
}
}

View file

@ -0,0 +1,303 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class CustomerBuilder
*
* @category RetailCRM
* @package RetailCRM
*/
class CustomerBuilder extends AbstractBuilder implements RetailcrmBuilderInterface
{
/** @var Customer */
protected $customer;
/** @var CustomerAddress */
protected $customerAddress;
/** @var array $dataCrm customerHistory */
protected $dataCrm;
/** @var AddressBuilder */
protected $addressBuilder;
/** @var CUser */
protected $user;
/** @var bool $registerNewUser */
protected $registerNewUser;
/** @var int $registeredUserID */
protected $registeredUserID;
/**
* CustomerBuilder constructor.
*/
public function __construct()
{
$this->customer = new Customer();
$this->customerAddress = new CustomerAddress();
$this->addressBuilder = new AddressBuilder();
}
/**
* @param Customer $customer
* @return $this
*/
public function setCustomer(Customer $customer)
{
$this->customer = $customer;
return $this;
}
/**
* @return Customer
*/
public function getCustomer()
{
return $this->customer;
}
/**
* @param CustomerAddress $customerAddress
* @return $this
*/
public function setCustomerAddress($customerAddress): CustomerBuilder
{
$this->customerAddress = $customerAddress;
return $this;
}
/**
* @return CustomerAddress
*/
public function getCustomerAddress()
{
return $this->customerAddress;
}
/**
* @param array $dataCrm
* @return $this
*/
public function setDataCrm($dataCrm)
{
$this->dataCrm = $dataCrm;
return $this;
}
/**
* @param array $user
* @return $this
*/
public function setUser($user)
{
$this->user = $user;
return $this;
}
/**
* @param int $registeredUserID
* @return $this
*/
public function setRegisteredUserID(int $registeredUserID)
{
$this->registeredUserID = $registeredUserID;
return $this;
}
/**
* @return int
*/
public function getRegisteredUserID()
{
return $this->registeredUserID;
}
/**
* @return bool
*/
public function getRegisterNewUser()
{
return $this->registerNewUser;
}
public function build()
{
if (!empty($this->dataCrm['firstName'])) {
$this->customer->setName($this->fromJSON($this->dataCrm['firstName']));
}
if (!empty($this->dataCrm['lastName'])) {
$this->customer->setLastName($this->fromJSON($this->dataCrm['lastName']));
}
if (!empty($this->dataCrm['patronymic'])) {
$this->customer->setSecondName($this->fromJSON($this->dataCrm['patronymic']));
}
if (isset($this->dataCrm['phones'])) {
foreach ($this->dataCrm['phones'] as $phone) {
if (is_array($this->user) && isset($phone['old_number']) && in_array($phone['old_number'], $this->user)) {
$key = array_search($phone['old_number'], $this->user);
if (isset($phone['number'])) {
$this->user[$key] = $phone['number'];
} else {
$this->user[$key] = '';
}
}
if (isset($phone['number'])) {
if ((!isset($this->user['PERSONAL_PHONE']) || '' == $this->user['PERSONAL_PHONE'])
&& $this->user['PERSONAL_MOBILE'] != $phone['number']
) {
$this->customer->setPersonalPhone($phone['number']);
$this->user['PERSONAL_PHONE'] = $phone['number'];
continue;
}
if ((!isset($this->user['PERSONAL_MOBILE']) || '' == $this->user['PERSONAL_MOBILE'])
&& $this->user['PERSONAL_PHONE'] != $phone['number']
) {
$this->customer->setPersonalMobile($phone['number']);
$this->user['PERSONAL_MOBILE'] = $phone['number'];
continue;
}
}
}
}
if (!empty($this->dataCrm['address']['index'])) {
$this->customer->setPersonalZip($this->fromJSON($this->dataCrm['address']['index']));
}
if (!empty($this->dataCrm['address']['city'])) {
$this->customer->setPersonalCity($this->fromJSON($this->dataCrm['address']['city']));
}
if (!empty($this->dataCrm['birthday'])) {
$this->customer->setPersonalBirthday($this->fromJSON(
date("d.m.Y", strtotime($this->dataCrm['birthday']))
));
}
if (!empty($this->dataCrm['email'])) {
$this->customer->setEmail($this->fromJSON($this->dataCrm['email']));
}
if (!empty($this->dataCrm['sex'])) {
$this->customer->setPersonalGender($this->fromJSON($this->dataCrm['sex']));
}
if ((!isset($this->dataCrm['email']) || $this->dataCrm['email'] == '')
&& (!isset($this->dataCrm['externalId']))
) {
$login = uniqid('user_' . time()) . '@example.com';
$this->customer->setLogin($login)
->setEmail($login);
}
if (isset($this->dataCrm['address'])) {
$this->buildAddress();
}
// клиент считается подписанным при значении равном null
if (array_key_exists('emailMarketingUnsubscribedAt', $this->dataCrm)) {
if (empty($this->dataCrm['emailMarketingUnsubscribedAt'])) {
$this->customer->setSubscribe('Y');
} else {
$this->customer->setSubscribe('N');
}
}
if (empty($this->dataCrm['externalId'])
&& (empty($this->dataCrm['firstName'])
|| empty($this->dataCrm['email']))
) {
$api = new RetailCrm\ApiClient(RetailcrmConfigProvider::getApiUrl(), RetailcrmConfigProvider::getApiKey());
$customerResponse = RCrmActions::apiMethod($api, 'customersGetById', __METHOD__, $this->dataCrm['id']);
if ($customerResponse instanceof RetailCrm\Response\ApiResponse
&& $customerResponse->isSuccessful()
&& !empty($customerResponse['customer'])
) {
$crmCustomer = $customerResponse['customer'];
if (empty($this->dataCrm['email'])
&& !empty($crmCustomer['email'])
) {
$email = $crmCustomer['email'];
$this->customer->setEmail($this->fromJSON($email));
$this->customer->setLogin($email);
}
if (empty($this->dataCrm['firstName'])
&& !empty($crmCustomer['firstName'])
) {
$this->customer->setName($this->fromJSON($crmCustomer['firstName']));
}
}
}
}
public function buildPassword()
{
$userPassword = uniqid("R");
$this->customer->setPassword($userPassword)
->setConfirmPassword($userPassword);
return $this;
}
public function buildAddress()
{
if (isset($this->dataCrm['address'])) {
$this->addressBuilder->setDataCrm($this->dataCrm['address'])->build();
$this->customerAddress = $this->addressBuilder->getCustomerAddress();
} else {
$this->customerAddress = null;
}
}
/**
* @param string $login
* @return $this
*/
public function setLogin(string $login)
{
$this->customer->setLogin($login);
return $this;
}
/**
* @param string $email
* @return $this
*/
public function setEmail(string $email)
{
$this->customer->setEmail($email);
return $this;
}
public function reset(): void
{
$this->customer = new Customer();
$this->customerAddress = new CustomerAddress();
$this->addressBuilder->reset();
}
}

View file

@ -0,0 +1,22 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Exception
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace RetailCrm\Exception;
/**
* Class CurlException
*
* @category RetailCRM
* @package RetailCRM\Exception
*/
class CurlException extends \RuntimeException
{
}

View file

@ -0,0 +1,22 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Exception
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace RetailCrm\Exception;
/**
* Class InvalidJsonException
*
* @category RetailCRM
* @package RetailCRM\Exception
*/
class InvalidJsonException extends \DomainException
{
}

View file

@ -0,0 +1,160 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Http
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace RetailCrm\Http;
use Intaro\RetailCrm\Component\Constants;
use RetailCrm\Exception\CurlException;
use RetailCrm\Exception\InvalidJsonException;
use RetailCrm\Response\ApiResponse;
/**
* Class Client
*
* @category RetailCRM
* @package RetailCRM\Http
*/
class Client
{
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';
protected $url;
protected $defaultParameters;
protected $retry;
/**
* Client constructor.
*
* @param string $url api url
* @param array $defaultParameters array of parameters
*
* @throws \InvalidArgumentException
*/
public function __construct($url, array $defaultParameters = [])
{
if (false === stripos($url, 'https://')) {
throw new \InvalidArgumentException(
'API schema requires HTTPS protocol'
);
}
$this->url = $url;
$this->defaultParameters = $defaultParameters;
$this->retry = 0;
$this->curlErrors = [
CURLE_COULDNT_RESOLVE_PROXY,
CURLE_COULDNT_RESOLVE_HOST,
CURLE_COULDNT_CONNECT,
CURLE_OPERATION_TIMEOUTED,
CURLE_HTTP_POST_ERROR,
CURLE_SSL_CONNECT_ERROR,
CURLE_SEND_ERROR,
CURLE_RECV_ERROR,
];
}
/**
* Make HTTP request
*
* @param string $path request url
* @param string $method (default: 'GET')
* @param array $parameters (default: array())
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*
* @throws \InvalidArgumentException
* @throws CurlException
* @throws InvalidJsonException
*
* @return ApiResponse
*/
public function makeRequest(
$path,
$method,
array $parameters = []
) {
$allowedMethods = [self::METHOD_GET, self::METHOD_POST];
if (!in_array($method, $allowedMethods, false)) {
throw new \InvalidArgumentException(
sprintf(
'Method "%s" is not valid. Allowed methods are %s',
$method,
implode(', ', $allowedMethods)
)
);
}
$parameters = self::METHOD_GET === $method
? array_merge($this->defaultParameters, $parameters, [
'cms_source' => 'Bitrix',
'cms_version' => SM_VERSION,
'php_version' => function_exists('phpversion') ? phpversion() : '',
'module_version' => Constants::MODULE_VERSION,
])
: $parameters = array_merge($this->defaultParameters, $parameters);
$url = $this->url . $path;
if (self::METHOD_GET === $method && count($parameters)) {
$url .= '?' . http_build_query($parameters, '', '&');
}
$curlHandler = curl_init();
curl_setopt($curlHandler, CURLOPT_URL, $url);
curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curlHandler, CURLOPT_FAILONERROR, false);
curl_setopt($curlHandler, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curlHandler, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curlHandler, CURLOPT_TIMEOUT, 30);
curl_setopt($curlHandler, CURLOPT_CONNECTTIMEOUT, 30);
if (self::METHOD_POST === $method) {
curl_setopt($curlHandler, CURLOPT_POST, true);
curl_setopt($curlHandler, CURLOPT_POSTFIELDS, $parameters);
}
$responseBody = curl_exec($curlHandler);
$statusCode = curl_getinfo($curlHandler, CURLINFO_HTTP_CODE);
$errno = curl_errno($curlHandler);
$error = curl_error($curlHandler);
curl_close($curlHandler);
if (
$errno
&& in_array($errno, $this->curlErrors, false)
&& $this->retry < 3
) {
$errno = null;
$error = null;
++$this->retry;
$this->makeRequest($path, $method, $parameters);
}
if ($errno) {
throw new CurlException($error, $errno);
}
return new ApiResponse($statusCode, $responseBody);
}
/**
* Retry connect
*
* @return int
*/
public function getRetry()
{
return $this->retry;
}
}

View file

@ -0,0 +1,122 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class Logger
*
* @category RetailCRM
* @package RetailCRM
*/
class Logger
{
/** @var self $instance */
private static $instance;
/** @var string $logPath */
private $logPath;
/** @var int $files */
private $files;
/**
* Get logger instance or re-initialize it with new parameters
*
* @param string $logPath
* @param int $files
*
* @return \Logger
*/
public static function getInstance($logPath = '/bitrix/modules/intaro.retailcrm/log', $files = 3)
{
if (empty(self::$instance)
|| (self::$instance instanceof self
&& (self::$instance->logPath !== $logPath || self::$instance->files !== $files))
) {
self::$instance = new Logger($logPath, $files);
}
return self::$instance;
}
/**
* Logger constructor.
*
* @param string $logPath
* @param int $files
*/
public function __construct($logPath = '/bitrix/modules/intaro.retailcrm/log', $files = 3)
{
$this->logPath = $logPath;
$this->files = $files;
}
public function write($dump, $file = 'info')
{
$rsSites = CSite::GetList($by, $sort, array('DEFAULT' => 'Y'));
$ar = $rsSites->Fetch();
if (!is_dir($ar['ABS_DOC_ROOT'] . $this->logPath . '/')) {
mkdir($ar['ABS_DOC_ROOT'] . $this->logPath . '/');
}
$file = $ar['ABS_DOC_ROOT'] . $this->logPath . '/' . $file . '.log';
$data['TIME'] = date('Y-m-d H:i:s');
$data['DATA'] = $dump;
$f = fopen($file, "a+");
fwrite($f, print_r($data, true));
fclose($f);
// if filesize more than 5 Mb rotate it
if (filesize($file) > 5242880) {
$this->rotate($file);
}
}
private function rotate($file)
{
$path = pathinfo($file);
$rotate = implode('', array(
$path['dirname'],
'/',
$path['filename'],
'_',
date('Y-m-d_H:i:s'),
'.',
$path['extension']
));
copy($file, $rotate);
$this->clean($file);
$files = glob($path['dirname'] . '/' . $path['filename'] . "*" . ".log");
if (0 === $this->files) {
return;
}
if (count($files) > $this->files) {
natsort($files);
$files = array_reverse($files);
foreach (array_slice($files, $this->files) as $log) {
if (is_writable($log)) {
unlink($log);
}
}
}
}
private function clean($file)
{
file_put_contents($file, '');
}
}

View file

@ -0,0 +1,50 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Model
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class BaseModel
*
* @category RetailCRM
* @package RetailCRM\Model
*/
abstract class BaseModel
{
/**
* @return array
*/
public function getObjectToArray()
{
return $this->arrayClear(call_user_func('get_object_vars', $this));
}
/**
* @param array $array
* @param array $symbols
* @return array
*/
public function arrayClear(array $array, array $symbols = array('', 0, null))
{
return array_diff($array, $symbols);
}
/**
* @param $array
* @return $this
*/
public function getArrayToObject($array)
{
foreach ($array as $key => $value) {
$this->$key = $value;
}
return $this;
}
}

View file

@ -0,0 +1,61 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Model
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class BuyerProfile
*
* @category RetailCRM
* @package RetailCRM\Model
*/
class BuyerProfile extends BaseModel
{
/**@var string $NAME */
protected $NAME;
/**@var string $USER_ID */
protected $USER_ID;
/**@var string $PERSON_TYPE_ID */
protected $PERSON_TYPE_ID;
/**
* @param string $NAME
* @return $this
*/
public function setName($NAME)
{
$this->NAME = $NAME;
return $this;
}
/**
* @param int $USER_ID
* @return $this
*/
public function setUserId($USER_ID)
{
$this->USER_ID = $USER_ID;
return $this;
}
/**
* @param int $PERSON_TYPE_ID
* @return $this
*/
public function setPersonTypeId($PERSON_TYPE_ID)
{
$this->PERSON_TYPE_ID = $PERSON_TYPE_ID;
return $this;
}
}

View file

@ -0,0 +1,229 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Model
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class Customer
*
* @category RetailCRM
* @package RetailCRM\Model
*/
class Customer extends BaseModel
{
/**@var string $EMAIL */
protected $EMAIL;
/**@var string $LOGIN */
protected $LOGIN;
/**@var string $ACTIVE */
protected $ACTIVE;
/**@var string $PASSWORD */
protected $PASSWORD;
/**@var string $CONFIRM_PASSWORD */
protected $CONFIRM_PASSWORD;
/**@var string $NAME */
protected $NAME;
/**@var string $LAST_NAME */
protected $LAST_NAME;
/**@var string $SECOND_NAME */
protected $SECOND_NAME;
/**@var string $PERSONAL_MOBILE */
protected $PERSONAL_MOBILE;
/**@var string $PERSONAL_PHONE */
protected $PERSONAL_PHONE;
/**@var string $PERSONAL_ZIP */
protected $PERSONAL_ZIP;
/**@var string $PERSONAL_CITY */
protected $PERSONAL_CITY;
/**@var string $PERSONAL_BIRTHDAY */
protected $PERSONAL_BIRTHDAY;
/**@var string $PERSONAL_GENDER */
protected $PERSONAL_GENDER;
/**@var string $UF_SUBSCRIBE_USER_EMAIL */
protected $UF_SUBSCRIBE_USER_EMAIL;
/**
* @param string $EMAIL
* @return $this
*/
public function setEmail($EMAIL)
{
$this->EMAIL = $EMAIL;
return $this;
}
/**
* @param string $LOGIN
* @return $this
*/
public function setLogin($LOGIN)
{
$this->LOGIN = $LOGIN;
return $this;
}
/**
* @param string $ACTIVE
* @return $this
*/
public function setActive($ACTIVE)
{
$this->ACTIVE = $ACTIVE;
return $this;
}
/**
* @param string $PASSWORD
* @return $this
*/
public function setPassword($PASSWORD)
{
$this->PASSWORD = $PASSWORD;
return $this;
}
/**
* @param string $CONFIRM_PASSWORD
* @return $this
*/
public function setConfirmPassword($CONFIRM_PASSWORD)
{
$this->CONFIRM_PASSWORD = $CONFIRM_PASSWORD;
return $this;
}
/**
* @param string $NAME
* @return $this
*/
public function setName($NAME)
{
$this->NAME = $NAME;
return $this;
}
/**
* @param string $LAST_NAME
* @return $this
*/
public function setLastName($LAST_NAME)
{
$this->LAST_NAME = $LAST_NAME;
return $this;
}
/**
* @param string $SECOND_NAME
* @return $this
*/
public function setSecondName($SECOND_NAME)
{
$this->SECOND_NAME = $SECOND_NAME;
return $this;
}
/**
* @param string $PERSONAL_MOBILE
* @return $this
*/
public function setPersonalMobile($PERSONAL_MOBILE)
{
$this->PERSONAL_MOBILE = $PERSONAL_MOBILE;
return $this;
}
/**
* @param string $PERSONAL_PHONE
* @return $this
*/
public function setPersonalPhone($PERSONAL_PHONE)
{
$this->PERSONAL_PHONE = $PERSONAL_PHONE;
return $this;
}
/**
* @param string $PERSONAL_ZIP
* @return $this
*/
public function setPersonalZip($PERSONAL_ZIP)
{
$this->PERSONAL_ZIP = $PERSONAL_ZIP;
return $this;
}
/**
* @param string $PERSONAL_CITY
* @return $this
*/
public function setPersonalCity($PERSONAL_CITY)
{
$this->PERSONAL_CITY = $PERSONAL_CITY;
return $this;
}
/**
* @param string $PERSONAL_BIRTHDAY
* @return $this
*/
public function setPersonalBirthday($PERSONAL_BIRTHDAY)
{
$this->PERSONAL_BIRTHDAY = $PERSONAL_BIRTHDAY;
return $this;
}
/**
* @param string $PERSONAL_GENDER
* @return $this
*/
public function setPersonalGender($PERSONAL_GENDER)
{
$this->PERSONAL_GENDER = $PERSONAL_GENDER;
return $this;
}
/**
* @param string $UF_SUBSCRIBE_USER_EMAIL
* @return $this
*/
public function setSubscribe($UF_SUBSCRIBE_USER_EMAIL)
{
$this->UF_SUBSCRIBE_USER_EMAIL = $UF_SUBSCRIBE_USER_EMAIL;
return $this;
}
}

View file

@ -0,0 +1,216 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Model
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class CustomerAddress
*
* @category RetailCRM
* @package RetailCRM\Model
*/
class CustomerAddress extends BaseModel
{
/**@var string $index */
protected $index;
/**@var string $country */
protected $country;
/**@var string $region */
protected $region;
/**@var string $city */
protected $city;
/**@var string $street */
protected $street;
/**@var string $building */
protected $building;
/**@var string $house */
protected $house;
/**@var string $block */
protected $block;
/**@var string $flat */
protected $flat;
/**@var string $floor */
protected $floor;
/**@var string $intercomCode */
protected $intercomCode;
/**@var string $metro */
protected $metro;
/**@var string $notes */
protected $notes;
/**@var string $text */
protected $text;
/**
* @param string $index
* @return $this
*/
public function setIndex($index)
{
$this->index = $index;
return $this;
}
/**
* @param string $country
* @return $this
*/
public function setCountry($country)
{
$this->country = $country;
return $this;
}
/**
* @param string $region
* @return $this
*/
public function setRegion($region)
{
$this->region = $region;
return $this;
}
/**
* @param string $city
* @return $this
*/
public function setCity($city)
{
$this->city = $city;
return $this;
}
/**
* @param string $street
* @return $this
*/
public function setStreet($street)
{
$this->street = $street;
return $this;
}
/**
* @param string $building
* @return $this
*/
public function setBuilding($building)
{
$this->building = $building;
return $this;
}
/**
* @param string $house
* @return $this
*/
public function setHouse($house)
{
$this->house = $house;
return $this;
}
/**
* @param string $block
* @return $this
*/
public function setBlock($block)
{
$this->block = $block;
return $this;
}
/**
* @param string $flat
* @return $this
*/
public function setFlat($flat)
{
$this->flat = $flat;
return $this;
}
/**
* @param string|null $floor
*
* @return $this
*/
public function setFloor(?string $floor): CustomerAddress
{
$this->floor = $floor;
return $this;
}
/**
* @param string $intercomCode
* @return $this
*/
public function setIntercomCode($intercomCode)
{
$this->intercomCode = $intercomCode;
return $this;
}
/**
* @param string $metro
* @return $this
*/
public function setMetro($metro)
{
$this->metro = $metro;
return $this;
}
/**
* @param string $notes
* @return $this
*/
public function setNotes($notes)
{
$this->notes = $notes;
return $this;
}
/**
* @param string $text
* @return $this
*/
public function setText($text)
{
$this->text = $text;
return $this;
}
}

View file

@ -0,0 +1,145 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Model
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class CustomerContragent
*
* @category RetailCRM
* @package RetailCRM\Model
*/
class CustomerContragent extends BaseModel
{
/**@var string $contragentType */
protected $contragentType;
/**@var string $legalName */
protected $legalName;
/**@var string $legalAddress */
protected $legalAddress;
/**@var string $certificateNumber */
protected $certificateNumber;
/**@var string $certificateDate */
protected $certificateDate;
/**@var string $bank */
protected $bank;
/**@var string $bankAddress */
protected $bankAddress;
/**@var string $corrAccount */
protected $corrAccount;
/**@var string $bankAccount */
protected $bankAccount;
/**
* @param string $contragentType
* @return $this
*/
public function setContragentType($contragentType)
{
$this->contragentType = $contragentType;
return $this;
}
/**
* @param string $legalName
* @return $this
*/
public function setLegalName($legalName)
{
$this->legalName = $legalName;
return $this;
}
/**
* @param string $legalAddress
* @return $this
*/
public function setLegalAddress($legalAddress)
{
$this->legalAddress = $legalAddress;
return $this;
}
/**
* @param string $certificateNumber
* @return $this
*/
public function setCertificateNumber($certificateNumber)
{
$this->certificateNumber = $certificateNumber;
return $this;
}
/**
* @param string $certificateDate
* @return $this
*/
public function setCertificateDate($certificateDate)
{
$this->certificateDate = $certificateDate;
return $this;
}
/**
* @param string $bank
* @return $this
*/
public function setBank($bank)
{
$this->bank = $bank;
return $this;
}
/**
* @param string $bankAddress
* @return $this
*/
public function setBankAddress($bankAddress)
{
$this->bankAddress = $bankAddress;
return $this;
}
/**
* @param string $corrAccount
* @return $this
*/
public function setCorrAccount($corrAccount)
{
$this->corrAccount = $corrAccount;
return $this;
}
/**
* @param string $bankAccount
* @return $this
*/
public function setBankAccount($bankAccount)
{
$this->bankAccount = $bankAccount;
return $this;
}
}

View file

@ -0,0 +1,894 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
use Bitrix\Sale\PersonType;
use Intaro\RetailCrm\Component\ServiceLocator;
use Bitrix\Sale\Delivery\Services\EmptyDeliveryService;
use Bitrix\Sale\Internals\OrderPropsTable;
use Bitrix\Sale\Internals\StatusTable;
use Bitrix\Sale\PaySystem\Manager;
use Intaro\RetailCrm\Service\Utils;
use RetailCrm\Exception\CurlException;
use RetailCrm\Exception\InvalidJsonException;
use Intaro\RetailCrm\Service\ManagerService;
use Bitrix\Main\UserFieldTable;
use Bitrix\Main\UserFieldLangTable;
use Bitrix\Sale\Internals\SiteCurrencyTable;
IncludeModuleLangFile(__FILE__);
require_once __DIR__ . '/../../lib/component/servicelocator.php';
require_once __DIR__ . '/../../lib/service/utils.php';
/**
* class RCrmActions
*
* @category RetailCRM
* @package RetailCRM
*/
class RCrmActions
{
public static $MODULE_ID = 'intaro.retailcrm';
public static $CRM_ORDER_FAILED_IDS = 'order_failed_ids';
public static $CRM_API_VERSION = 'api_version';
public static function getCurrencySites(): array
{
$sites = self::getSitesList();
$baseCurrency = CCurrency::GetBaseCurrency();
$sitesCurrency = [];
foreach ($sites as $site) {
$siteCurrency = SiteCurrencyTable::getCurrency($site['LID']);
$sitesCurrency[$site['LID']] = !empty($siteCurrency['CURRENCY'])
? $siteCurrency['CURRENCY']
: $baseCurrency;
}
return $sitesCurrency;
}
/**
* @return array
*/
public static function getSitesList(): array
{
$arSites = [];
$rsSites = CSite::GetList($by, $sort, ['ACTIVE' => 'Y']);
while ($ar = $rsSites->Fetch()) {
$arSites[] = $ar;
}
return $arSites;
}
public static function OrderTypesList($arSites)
{
$orderTypesList = [];
foreach ($arSites as $site) {
$personTypes = PersonType::load($site['LID']);
$bitrixOrderTypesList = [];
foreach ($personTypes as $personType) {
if (!array_key_exists($personType['ID'], $orderTypesList)) {
$bitrixOrderTypesList[$personType['ID']] = $personType;
}
asort($bitrixOrderTypesList);
}
$orderTypesList += $bitrixOrderTypesList;
}
return $orderTypesList;
}
public static function DeliveryList()
{
$bitrixDeliveryTypesList = [];
$arDeliveryServiceAll = \Bitrix\Sale\Delivery\Services\Manager::getActiveList();
$noOrderId = EmptyDeliveryService::getEmptyDeliveryServiceId();
$groups = [];
foreach ($arDeliveryServiceAll as $arDeliveryService) {
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') {
if (in_array($arDeliveryService['PARENT_ID'], $groups)) {
$arDeliveryService['PARENT_ID'] = 0;
}
$bitrixDeliveryTypesList[] = $arDeliveryService;
}
}
return $bitrixDeliveryTypesList;
}
public static function PaymentList()
{
$bitrixPaymentTypesList = [];
$dbPaymentAll = Manager::getList(['select' => ['ID', 'NAME'], 'filter' => ['ACTIVE' => 'Y']]);
while ($payment = $dbPaymentAll->fetch()) {
$bitrixPaymentTypesList[] = $payment;
}
return $bitrixPaymentTypesList;
}
public static function StatusesList()
{
$bitrixPaymentStatusesList = [];
$obStatuses = StatusTable::getList([
'filter' => ['TYPE' => 'O', '=Bitrix\Sale\Internals\StatusLangTable:STATUS.LID' => LANGUAGE_ID],
'select' => ['ID', 'NAME' => 'Bitrix\Sale\Internals\StatusLangTable:STATUS.NAME'],
]);
while ($arStatus = $obStatuses->fetch()) {
$bitrixPaymentStatusesList[$arStatus['ID']] = ['ID' => $arStatus['ID'], 'NAME' => $arStatus['NAME']];
}
return $bitrixPaymentStatusesList;
}
public static function OrderPropsList()
{
$bitrixPropsList = [];
$arPropsAll = OrderPropsTable::getList([
'select' => ['*'],
'filter' => [
['CODE' => '_%'],
['!=TYPE' => 'LOCATION']
]
]);
while ($prop = $arPropsAll->Fetch()) {
$bitrixPropsList[$prop['PERSON_TYPE_ID']][] = $prop;
}
return $bitrixPropsList;
}
public static function getLocationProps()
{
$bitrixPropsList = [];
$arPropsAll = OrderPropsTable::getList([
'select' => ['*'],
'filter' => [
['CODE' => '_%'],
['TYPE' => 'LOCATION']
]
]);
while ($prop = $arPropsAll->Fetch()) {
$bitrixPropsList[$prop['PERSON_TYPE_ID']][] = $prop;
}
return $bitrixPropsList;
}
public static function PricesExportList()
{
$catalogExportPrices = [];
$dbPriceType = CCatalogGroup::GetList([], [], false, false, ['ID', 'NAME', 'NAME_LANG']);
while ($arPriceType = $dbPriceType->Fetch())
{
$catalogExportPrices[$arPriceType['ID']] = $arPriceType;
}
return $catalogExportPrices;
}
public static function StoresExportList()
{
$catalogExportStores = [];
$dbStores = CCatalogStore::GetList([], ['ACTIVE' => 'Y'], false, false, ['ID', 'TITLE']);
while ($stores = $dbStores->Fetch()) {
$catalogExportStores[] = $stores;
}
return $catalogExportStores;
}
public static function IblocksExportList()
{
$catalogExportIblocks = [];
$dbIblocks = CIBlock::GetList(['IBLOCK_TYPE' => 'ASC', 'NAME' => 'ASC'], ['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']] = [
'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
*/
public static function eventLog($auditType, $itemId, $description)
{
CEventLog::Add([
'SEVERITY' => 'SECURITY',
'AUDIT_TYPE_ID' => $auditType,
'MODULE_ID' => self::$MODULE_ID,
'ITEM_ID' => $itemId,
'DESCRIPTION' => $description,
]);
}
/**
*
* Agent function
*
* @return self name
*/
public static function uploadOrdersAgent()
{
RetailCrmOrder::uploadOrders();
$failedIds = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_FAILED_IDS, 0));
if (is_array($failedIds) && !empty($failedIds)) {
RetailCrmOrder::uploadOrders(50, true);
}
return 'RCrmActions::uploadOrdersAgent();';
}
/**
*
* Agent function
*
* @return self name
*
* @throws \Throwable
*/
public static function orderAgent()
{
if (COption::GetOptionString('main', 'agents_use_crontab', 'N') !== 'N') {
define('NO_AGENT_CHECK', true);
}
try {
$service = ManagerService::getInstance();
$service->synchronizeManagers();
RetailCrmHistory::customerHistory();
RetailCrmHistory::orderHistory();
} catch (\Throwable $exception) {
Logger::getInstance()->write(
'Fail orderAgent:' . PHP_EOL .
$exception->getMessage() . PHP_EOL .
'File: ' . $exception->getFile() . PHP_EOL .
'Line: ' . $exception->getLine() . PHP_EOL,
'orderAgent'
);
}
return 'RCrmActions::orderAgent();';
}
/**
* removes all empty fields from arrays
* working with nested arrs
*
* @param array $arr
*
* @return array
*/
public static function clearArr(array $arr): array
{
/** @var Utils $utils */
$utils = ServiceLocator::getOrCreate(Utils::class);
return $utils->clearArray($arr);
}
/**
*
* @param array|bool|\SplFixedArray|string $str in SITE_CHARSET
*
* @return array|bool|\SplFixedArray|string $str in utf-8
*/
public static function toJSON($str)
{
/** @var Utils $utils */
$utils = ServiceLocator::getOrCreate(Utils::class);
return $utils->toUTF8($str);
}
/**
*
* @param string|array|\SplFixedArray $str in utf-8
*
* @return array|bool|\SplFixedArray|string $str in SITE_CHARSET
*/
public static function fromJSON($str)
{
if ($str === null) {
return '';
}
/** @var Utils $utils */
$utils = ServiceLocator::getOrCreate(Utils::class);
return $utils->fromUTF8($str);
}
/**
* Extracts payment ID or client ID from payment externalId
* Payment ID - pass nothing or 'id' as second argument
* Client ID - pass 'client_id' as second argument
*
* @param $externalId
* @param string $data
* @return bool|string
*/
public static function getFromPaymentExternalId($externalId, $data = 'id')
{
switch ($data) {
case 'id':
if (false === strpos($externalId, '_')) {
return $externalId;
} else {
return substr($externalId, 0, strpos($externalId, '_'));
}
break;
case 'client_id':
if (false === strpos($externalId, '_')) {
return '';
} else {
return substr($externalId, strpos($externalId, '_'), count($externalId));
}
break;
}
return '';
}
/**
* Returns true if provided externalId in new format (id_clientId)
*
* @param $externalId
* @return bool
*/
public static function isNewExternalId($externalId)
{
return !(false === strpos($externalId, '_'));
}
/**
* Generates payment external ID
*
* @param $id
*
* @return string
*/
public static function generatePaymentExternalId($id)
{
return sprintf(
'%s_%s',
$id,
COption::GetOptionString(self::$MODULE_ID, 'client_id', 0)
);
}
/**
* Unserialize array
*
* @param string $string
*
* @return mixed
*/
public static function unserializeArrayRecursive($string)
{
if ($string === false || empty($string)) {
return false;
}
if (is_string($string)) {
$string = unserialize($string);
}
if (!is_array($string)) {
$string = self::unserializeArrayRecursive($string);
}
return $string;
}
/**
* @param string|null $fio
*
* @return array
*/
public static function explodeFio(?string $fio): array
{
$result = [];
$fio = preg_replace('|[\s]+|s', ' ', trim($fio));
if (empty($fio)) {
return $result;
} else {
$newFio = explode(' ', $fio, 3);
}
switch (count($newFio)) {
default:
case 0:
$result['firstName'] = $fio;
break;
case 1:
$result['firstName'] = $newFio[0];
break;
case 2:
$result = [
'lastName' => $newFio[0],
'firstName' => $newFio[1],
];
break;
case 3:
$result = [
'lastName' => $newFio[0],
'firstName' => $newFio[1],
'patronymic' => $newFio[2],
];
break;
}
return $result;
}
public static function customOrderPropList()
{
$typeMatched = [
'STRING' => 'STRING',
'NUMBER' => 'NUMERIC',
'Y/N' => 'BOOLEAN',
'DATE' => 'DATE'
];
//Базовые свойства заказа и используемые свойства в функционале модуля
$bannedCodeList = [
'FIO',
'EMAIL',
'PHONE',
'ZIP',
'CITY',
'LOCATION',
'ADDRESS',
'COMPANY',
'COMPANY_ADR',
'INN',
'KPP',
'CONTACT_PERSON',
'FAX',
'LP_BONUS_INFO',
'LP_DISCOUNT_INFO',
''
];
$listPersons = PersonType::getList([
'select' => ['ID', 'NAME'],
'filter' => ['ENTITY_REGISTRY_TYPE' => 'ORDER']
])->fetchAll();
$persons = [];
foreach ($listPersons as $person) {
$persons[$person['ID']] = $person['NAME'];
}
$propsList = OrderPropsTable::getList([
'select' => ['ID', 'CODE', 'NAME', 'PERSON_TYPE_ID', 'TYPE'],
'filter' => [
['!=CODE' => $bannedCodeList],
['?TYPE' => 'STRING | NUMBER | Y/N | DATE'],
['MULTIPLE' => 'N'],
['ACTIVE' => 'Y']
]
])->fetchAll();
$resultList = [];
foreach ($propsList as $prop) {
$type = $typeMatched[$prop['TYPE']] ?? $prop['TYPE'];
$key = $prop['ID'] . '#' . $prop['CODE'];
$resultList[$type . '_TYPE'][$key] = $prop['NAME'] . ' (' . $persons[$prop['PERSON_TYPE_ID']] . ')';
}
ksort($resultList);
return $resultList;
}
public static function customUserFieldList()
{
$typeMatched = [
'string' => 'STRING',
'double' => 'NUMERIC',
'boolean' => 'BOOLEAN',
'date' => 'DATE',
'integer' => 'INTEGER'
];
$userFields = UserFieldTable::getList([
'select' => ['ID', 'FIELD_NAME', 'USER_TYPE_ID'],
'filter' => [
['ENTITY_ID' => 'USER'],
['?FIELD_NAME' => '~%INTARO%'],
['!=FIELD_NAME' => 'UF_SUBSCRIBE_USER_EMAIL'],
['!=USER_TYPE_ID' => 'datetime'],
['?USER_TYPE_ID' => 'string | date | integer | double | boolean'],
['MULTIPLE' => 'N'],
]
])->fetchAll();
$resultList = [];
foreach ($userFields as $userField) {
$label = UserFieldLangTable::getList([
'select' => ['EDIT_FORM_LABEL'],
'filter' => [
["USER_FIELD_ID" => $userField['ID']],
['LANGUAGE_ID' => LANGUAGE_ID]
]
])->fetch();
$type = $typeMatched[$userField['USER_TYPE_ID']] ?? $userField['USER_TYPE_ID'];
$resultList[$type . '_TYPE'][$userField['FIELD_NAME']] = $label['EDIT_FORM_LABEL'];
}
ksort($resultList);
return $resultList;
}
public static function getTypeUserField()
{
$userFields = UserFieldTable::getList([
'select' => ['FIELD_NAME', 'USER_TYPE_ID'],
'filter' => [
['ENTITY_ID' => 'USER'],
['?FIELD_NAME' => '~%INTARO%'],
['!=FIELD_NAME' => 'UF_SUBSCRIBE_USER_EMAIL'],
['?USER_TYPE_ID' => 'string | date | datetime | integer | double | boolean'],
['MULTIPLE' => 'N'],
]
])->fetchAll();
$result = [];
foreach ($userFields as $userField) {
$result[$userField['FIELD_NAME']] = $userField['USER_TYPE_ID'];
}
return $result;
}
public static function convertCmsFieldToCrmValue($value, $type)
{
$result = $value;
switch ($type) {
case 'boolean':
$result = $value === '1' ? 1 : 0;
break;
case 'Y/N':
$result = $result === 'Y' ? 1 : 0;
break;
case 'STRING':
case 'string':
$result = strlen($value) <= 500 ? $value : '';
break;
case 'datetime':
$result = date('Y-m-d', strtotime($value));
break;
}
return $result;
}
public static function convertCrmValueToCmsField($crmValue, $type)
{
$result = $crmValue;
switch ($type) {
case 'Y/N':
case 'boolean':
$result = $crmValue == 1 ? 'Y' : 'N';
break;
case 'DATE':
case 'date':
if (empty($crmValue)) {
return '';
}
try {
$result = date('d.m.Y', strtotime($crmValue));
} catch (\Exception $exception) {
$result = '';
}
break;
case 'STRING':
case 'string':
case 'text':
$result = strlen($crmValue) <= 500 ? $crmValue : '';
break;
}
return $result;
}
public static function sendConfiguration($api, $active = true)
{
$scheme = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
$baseUrl = $scheme . $_SERVER['HTTP_HOST'];
$integrationCode = 'bitrix';
$logo = 'https://s3.eu-central-1.amazonaws.com/retailcrm-billing/images/5af47fe682bf2-1c-bitrix-logo.svg';
$accountUrl = $baseUrl . '/bitrix/admin';
$clientId = COption::GetOptionString(self::$MODULE_ID, 'client_id', 0);
if (!$clientId) {
$clientId = uniqid();
COption::SetOptionString(self::$MODULE_ID, 'client_id', $clientId);
}
$code = $integrationCode . '-' . $clientId;
$configuration = [
'clientId' => $clientId,
'code' => $code,
'integrationCode' => $integrationCode,
'active' => $active,
'name' => GetMessage('API_MODULE_NAME'),
'logo' => $logo,
'baseUrl' => $baseUrl,
'accountUrl' => $accountUrl
];
self::apiMethod($api, 'integrationModulesEdit', __METHOD__, $configuration);
}
public static function apiMethod($api, $methodApi, $method, $params, $site = null)
{
switch ($methodApi) {
case 'ordersPaymentDelete':
case 'ordersHistory':
case 'customerHistory':
case 'ordersFixExternalIds':
case 'customersFixExternalIds':
case 'customersCorporateContacts':
case 'customersList':
case 'customersCorporateList':
return self::proxy($api, $methodApi, $method, [$params]);
case 'orderGet':
return self::proxy($api, 'ordersGet', $method, [$params, 'id', $site]);
case 'ordersGet':
case 'ordersEdit':
case 'customersGet':
case 'customersEdit':
case 'customersCorporateGet':
return self::proxy($api, $methodApi, $method, [$params, 'externalId', $site]);
case 'customersCorporateGetById':
return self::proxy($api, 'customersCorporateGet', $method, [$params, 'id', $site]);
case 'customersGetById':
return self::proxy($api, 'customersGet', $method, [$params, 'id', $site]);
case 'paymentEditById':
return self::proxy($api, 'ordersPaymentEdit', $method, [$params, 'id', $site]);
case 'paymentEditByExternalId':
return self::proxy($api, 'ordersPaymentEdit', $method, [$params, 'externalId', $site]);
case 'customersCorporateEdit':
return self::proxy($api, 'customersCorporateEdit', $method, [$params, 'externalId', $site]);
case 'cartGet':
return self::proxy($api, $methodApi, $method, [$params, $site, 'externalId']);
case 'cartSet':
case 'cartClear':
return self::proxy($api, $methodApi, $method, [$params, $site]);
default:
return self::proxy($api, $methodApi, $method, [$params, $site]);
}
}
private static function proxy($api, $methodApi, $method, $params) {
$version = COption::GetOptionString(self::$MODULE_ID, self::$CRM_API_VERSION, 0);
try {
$result = call_user_func_array([$api, $methodApi], $params);
if (!$result) {
$err = new RuntimeException(
$methodApi . ': Got null instead of valid result!'
);
Logger::getInstance()->write(sprintf(
'%s%s%s',
$err->getMessage(),
PHP_EOL,
$err->getTraceAsString()
), 'apiErrors');
return false;
}
if ($result->getStatusCode() !== 200 && $result->getStatusCode() !== 201) {
if ($methodApi == 'ordersGet'
|| $methodApi == 'customersGet'
|| $methodApi == 'customersCorporateGet'
) {
Logger::getInstance()->write([
'api' => $version,
'methodApi' => $methodApi,
'errorMsg' => !empty($result['errorMsg']) ? $result['errorMsg'] : '',
'errors' => !empty($result['errors']) ? $result['errors'] : '',
'params' => $params
], 'apiErrors');
} elseif ($methodApi == 'customersUpload' || $methodApi == 'ordersUpload') {
Logger::getInstance()->write([
'api' => $version,
'methodApi' => $methodApi,
'errorMsg' => !empty($result['errorMsg']) ? $result['errorMsg'] : '',
'errors' => !empty($result['errors']) ? $result['errors'] : '',
'params' => $params
], 'uploadApiErrors');
} elseif ($methodApi == 'cartGet') {
Logger::getInstance()->write(
[
'api' => $version,
'methodApi' => $methodApi,
'errorMsg' => !empty($result['errorMsg']) ? $result['errorMsg'] : '',
'errors' => !empty($result['errors']) ? $result['errors'] : '',
'params' => $params,
],
'apiErrors'
);
} else {
self::eventLog(
__CLASS__ . '::' . $method,
'RetailCrm\ApiClient::' . $methodApi,
!empty($result['errorMsg']) ? $result['errorMsg'] : ''
);
Logger::getInstance()->write([
'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 (CurlException $e) {
static::logException(
$method,
$methodApi,
'CurlException',
'CurlException',
$e,
$version,
$params
);
return false;
} catch (InvalidArgumentException $e) {
static::logException(
$method,
$methodApi,
'InvalidArgumentException',
'ArgumentException',
$e,
$version,
$params
);
return false;
} catch (InvalidJsonException $e) {
static::logException(
$method,
$methodApi,
'InvalidJsonException',
'ArgumentException',
$e,
$version,
$params
);
}
if (function_exists('retailCrmApiResult')) {
retailCrmApiResult($methodApi, true, isset($result) ? $result->getStatusCode() : 0);
}
return isset($result) ? $result : false;
}
/**
* Log exception into log file and event log
*
* @param string $method
* @param string $methodApi
* @param string $exceptionName
* @param string $apiResultExceptionName
* @param \Exception|\Error|\Throwable $exception
* @param string $version
* @param array $params
*/
protected static function logException(
$method,
$methodApi,
$exceptionName,
$apiResultExceptionName,
$exception,
$version,
$params
) {
self::eventLog(
__CLASS__ . '::' . $method, 'RetailCrm\ApiClient::' . $methodApi . '::' . $exceptionName,
$exception->getCode() . ': ' . $exception->getMessage()
);
Logger::getInstance()->write([
'api' => $version,
'methodApi' => $methodApi,
'errorMsg' => $exception->getMessage(),
'errors' => $exception->getCode(),
'params' => $params
], 'apiErrors');
if (function_exists('retailCrmApiResult')) {
retailCrmApiResult($methodApi, false, $apiResultExceptionName);
}
}
}

View file

@ -0,0 +1,181 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Response
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace RetailCrm\Response;
use InvalidArgumentException;
use RetailCrm\Exception\InvalidJsonException;
/**
* Class ApiResponse
*
* @category RetailCRM
* @package RetailCRM\Response
*/
class ApiResponse implements \ArrayAccess
{
// HTTP response status code
protected $statusCode;
// response assoc array
protected $response;
/**
* ApiResponse constructor.
*
* @param int $statusCode HTTP status code
* @param mixed $responseBody HTTP body
*
* @throws InvalidJsonException
*/
public function __construct($statusCode, $responseBody = null)
{
$this->statusCode = (int) $statusCode;
if (!empty($responseBody)) {
$response = json_decode($responseBody, true);
if (!$response && JSON_ERROR_NONE !== ($error = json_last_error())) {
throw new InvalidJsonException(
"Invalid JSON in the API response body. Error code #$error",
$error
);
}
$this->response = $response;
}
}
/**
* Return HTTP response status code
*
* @return int
*/
public function getStatusCode()
{
return $this->statusCode;
}
/**
* HTTP request was successful
*
* @return bool
*/
public function isSuccessful()
{
return $this->statusCode < 400;
}
/**
* Allow to access for the property throw class method
*
* @param string $name method name
* @param mixed $arguments method parameters
*
* @throws \InvalidArgumentException
*
* @return mixed
*/
public function __call($name, $arguments)
{
// convert getSomeProperty to someProperty
$propertyName = strtolower(substr($name, 3, 1)) . substr($name, 4);
if (!isset($this->response[$propertyName])) {
throw new \InvalidArgumentException("Method \"$name\" not found");
}
return $this->response[$propertyName];
}
/**
* Allow to access for the property throw object property
*
* @param string $name property name
*
* @throws \InvalidArgumentException
*
* @return mixed
*/
public function __get($name)
{
if (!isset($this->response[$name])) {
throw new \InvalidArgumentException("Property \"$name\" not found");
}
return $this->response[$name];
}
/**
* Offset set
*
* @param mixed $offset offset
* @param mixed $value value
*
* @throws \BadMethodCallException
* @return void
*/
public function offsetSet($offset, $value)
{
throw new \BadMethodCallException('This activity not allowed');
}
/**
* Offset unset
*
* @param mixed $offset offset
*
* @throws \BadMethodCallException
* @return void
*/
public function offsetUnset($offset)
{
throw new \BadMethodCallException('This call not allowed');
}
/**
* Check offset
*
* @param mixed $offset offset
*
* @return bool
*/
public function offsetExists($offset)
{
return isset($this->response[$offset]);
}
/**
* Get offset
*
* @param mixed $offset offset
*
* @throws \InvalidArgumentException
*
* @return mixed
*/
public function offsetGet($offset)
{
if (!isset($this->response[$offset])) {
throw new InvalidArgumentException("Property \"$offset\" not found");
}
return $this->response[$offset];
}
/**
* @return array
*/
public function getResponseBody()
{
return $this->response;
}
}

View file

@ -0,0 +1,364 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* RestNormalizer - The main class
*
* @category RetailCRM
* @package RetailCRM
*/
class RestNormalizer
{
public $clear = true;
private $validation = [];
private $originalValidation = [];
private $server;
/**
* Class constructor
* @return void
* @access public
* @final
*/
final public function __construct()
{
if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) {
date_default_timezone_set(@date_default_timezone_get());
}
$this->server = \Bitrix\Main\Context::getCurrent()->getServer()->getDocumentRoot();
}
/**
* Parsing the file validation
* @param string $file The path to the file validation
* @return boolean
* @access private
* @final
*/
final private function parseConfig($file)
{
if (json_decode(file_get_contents($file)) !== null) {
$this->originalValidation = json_decode(file_get_contents($file), true);
return true;
} else {
return false;
}
}
/**
* Starting the process of normalization of the data
* @param array $data The key is to sort the data validation
* @param string $key Data normalization
* @return array
* @access public
* @final
*/
final public function normalize($data, $key = false, $file = '/bitrix/modules/intaro.retailcrm/classes/general/config/retailcrm.json')
{
$server = \Bitrix\Main\Context::getCurrent()->getServer()->getDocumentRoot();
$file = $server . $file;
if (is_null($file) || is_file($file) === false
|| json_decode(file_get_contents($file)) === null
|| $this->parseConfig($file) === false
) {
RCrmActions::eventLog('RestNormalizer', 'intaro.retailcrm', 'Incorrect file normalize.');
return false;
}
if (is_string($data)) {
$data = json_decode($data, true);
}
if (is_string($key) && isset($this->originalValidation[ $key ])) {
$this->validation = $this->originalValidation[ $key ];
} else {
$this->validation = $this->originalValidation;
}
if (!is_array($data) || count($data) < 1) {
RCrmActions::eventLog('RestNormalizer', 'intaro.retailcrm', 'Incorrect data array.');
return false;
}
return $this->formatting($data);
}
/**
* Data formatting
* @param array $data The key is to sort the data validation
* @param boolean $skip Skip perform methods intended for the first run
* @return array
* @access private
* @final
*/
final private function formatting($data, $skip = false)
{
$formatted = [];
foreach ($data as $code => $value) {
if (isset($this->validation[ $code ]) && $this->validation[ $code ]['type'] == 'skip') {
$formatted[ $code ] = $value;
} elseif (isset($this->validation[ $code ]) && is_array($value) === false) {
$formatted[ $code ] = $this->setFormat($value, $this->validation[ $code ]);
} elseif (is_array($value)) {
$formatted[ $code ] = $this->formatting($value, true);
}
//Удаление пустых переменных, кроме значений равных 0
if (empty($formatted[$code]) && $formatted[$code] !== 0 && $formatted[$code] !== 0.0) {
if ($this->clear === true) {
unset($formatted[ $code ]);
}
if (isset($this->validation[ $code ]['required']) && $this->validation[ $code ]['required'] === true) {
$formatted = [];
break;
}
}
}
if ($skip === false) {
foreach ($this->validation as $code => $valid) {
if (isset($valid['required']) && $valid['required'] === true && isset($formatted[ $code ]) === false) {
RCrmActions::eventLog('RestNormalizer', 'intaro.retailcrm', "NOT VALID: $code");
}
}
$formatted = $this->multiConvert($formatted);
}
return count($formatted) < 1 ? false : $formatted;
}
/**
* Formatting data depending on the type
* @param mixed $data The value to be formatted
* @param array $validation The data for the current data type validation
* @return mixed
* @access private
* @final
*/
final private function setFormat($data, $validation)
{
$format = null;
switch ($validation['type']) {
case 'string':
$format = $this->setString($data, $validation);
break;
case 'int':
$format = $this->setInt($data, $validation);
break;
case 'double':
$format = $this->setDouble($data, $validation);
break;
case 'bool':
$format = $this->setBool($data, $validation);
break;
case 'datetime':
$format = $this->setDateTime($data, $validation);
break;
case 'enum':
$format = $this->setEnum($data, $validation);
break;
}
return $format;
}
/**
* Formatting data for strings
* @param string $data String to formatting
* @param array $validation The data for the current data type validation
* @return string
* @access private
* @final
*/
final private function setString($data, $validation)
{
$data = trim((string) $data);
if (isset($validation['default']) && is_string($validation['default']) && trim($validation['default']) != ''
&& ($data == '' || is_string($data) === false)
) {
$data = trim($validation['default']);
} elseif ($data == '' || is_string($data) === false) {
return null;
} elseif (isset($validation['min']) && mb_strlen($data) < $validation['min']) {
$pad = isset($validation['pad']) && mb_strlen($validation['pad']) == 1 ? $validation['pad'] : ' ';
$data .= str_repeat($pad, $validation['min'] - mb_strlen($data));
} elseif (isset($validation['max']) && mb_strlen($data) > $validation['max']) {
$data = mb_substr($data, 0, $validation['max']);
}
return (string) $data;
}
/**
* Formatting data for integers
* @param integer $data Integer to formatting
* @param array $validation The data for the current data type validation
* @return integer
* @access private
* @final
*/
final private function setInt($data, $validation)
{
if (isset($validation['default']) && is_numeric($validation['default']) && is_numeric($data) === false) {
$data = $validation['default'];
} elseif (is_numeric($data) === false) {
return null;
} elseif (isset($validation['min']) && $data < $validation['min']) {
$data += $validation['min'] - $data;
} elseif (isset($validation['max']) && $data > $validation['max']) {
$data -= $data - $validation['max'];
}
return (int) $data;
}
/**
* Formatting data for floating-point numbers
* @param float $data Floating-point number to formatting
* @param array $validation The data for the current data type validation
* @return float
* @access private
* @final
*/
final private function setDouble($data, $validation)
{
if (isset($validation['default']) && is_numeric($validation['default']) && is_numeric($data) === false) {
$data = $validation['default'];
} elseif (is_numeric($data) === false) {
return null;
} elseif (isset($validation['min']) && $data < $validation['min']) {
$data += $validation['min'] - $data;
} elseif (isset($validation['max']) && $data > $validation['max']) {
$data -= $data - $validation['max'];
}
if (isset($validation['decimals'])) {
$data = number_format($data, $validation['decimals'], '.', '');
}
return (double) $data;
}
/**
* Formatting data for logical values
* @param boolean $data Boolean value to formatting
* @param array $validation The data for the current data type validation
* @return boolean
* @access private
* @final
*/
final private function setBool($data, $validation)
{
if (isset($validation['default']) && is_bool($validation['default']) && is_bool($data) === false) {
$data = $validation['default'];
} elseif (is_bool($data) === false) {
return null;
}
return (bool) $data;
}
/**
* Formatting data for date and time
* @param mixed $data Date and time of to formatting
* @param array $validation The data for the current data type validation
* @param boolean $skip Skip perform methods intended for the first run
* @return mixed
* @access private
* @final
*/
final private function setDateTime($data, $validation, $skip = false)
{
if (is_a($data, 'DateTime') && isset($validation['format'])) {
$data = (string) $data->format($validation['format']);
} elseif (is_string($data) && isset($validation['format']) && strtotime($data) !== false) {
$data = (string) date($validation['format'], strtotime($data));
} elseif (is_numeric($data) && isset($validation['format'])) {
$data = (string) date($validation['format'], (int) $data);
} elseif (is_numeric($data)) {
$data = (int) $data;
} elseif (isset($validation['format'])) {
$data = (string) date($validation['format']);
} elseif (isset($validation['default']) && $skip === false) {
$data = $this->setDateTime(time(), $validation, true);
} else {
return null;
}
return $data;
}
/**
* Formatting data for enum
* @param string $data Enum to formatting
* @param array $validation The data for the current data type validation
* @return string
* @access private
* @final
*/
final private function setEnum($data, $validation)
{
if (isset($validation['values']) === false || count($validation['values']) < 1) {
return null;
} elseif (isset($validation['default']) && in_array($validation['default'], $validation['values']) === false) {
return null;
} elseif (in_array($data, $validation['values']) === false
&& isset($validation['default']) && in_array($validation['default'], $validation['values'])
) {
$data = $validation['default'];
} elseif (in_array($data, $validation['values']) === false) {
return null;
}
return $data;
}
/**
* Installing the specified encoding
* @param array $data The original dataset
* @return array
* @access private
* @final
*/
final private function multiConvert($data)
{
global $APPLICATION;
if (is_array($data)) {
foreach ($data as $code => $value) {
if (is_array($value)) {
$value = array_diff($value, array('', NULL));
}
$data[$APPLICATION->ConvertCharset($code, SITE_CHARSET, 'utf-8')] = is_array($value)
? $this->multiConvert($value)
: $APPLICATION->ConvertCharset($value, SITE_CHARSET, 'utf-8')
;
}
return $data;
} else {
return $APPLICATION->ConvertCharset($data, SITE_CHARSET, 'utf-8');
}
return $data;
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
IncludeModuleLangFile(__FILE__);
/**
* Interface RetailcrmBuilderInterface
*
* @category RetailCRM
* @package RetailCRM
*/
interface RetailcrmBuilderInterface
{
/**
* Set data array customerHistory
*
* @param array $dataCrm
*
* @return RetailcrmBuilderInterface
*/
public function setDataCrm($dataCrm);
/**
* Build result
*/
public function build();
}

View file

@ -0,0 +1,35 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* RetailcrmConfigProvider class
*
* @category RetailCRM
* @package RetailCRM
*/
use Intaro\RetailCrm\Component\ConfigProvider;
IncludeModuleLangFile(__FILE__);
require_once __DIR__ . '/../../lib/component/configprovider.php';
/**
* PHP version 5.3
*
* RetailcrmConfigProvider class
*
* @category RetailCRM
* @package RetailCRM
*/
class RetailcrmConfigProvider extends ConfigProvider
{
}

View file

@ -0,0 +1,35 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* RetailcrmConstants
*
* @category RetailCRM
* @package RetailCRM
*/
use Intaro\RetailCrm\Component\Constants;
IncludeModuleLangFile(__FILE__);
require_once __DIR__ . '/../../lib/component/constants.php';
/**
* PHP version 5.3
*
* RetailcrmConstants
*
* @category RetailCRM
* @package RetailCRM
*/
class RetailcrmConstants extends Constants
{
}

View file

@ -0,0 +1,33 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* RetailcrmDependencyLoader class
*
* @category RetailCRM
* @package RetailCRM
*/
IncludeModuleLangFile(__FILE__);
require_once __DIR__ . '/../../lib/component/dependencyloader.php';
/**
* PHP version 5.3
*
* RetailcrmDependencyLoader class
*
* @category RetailCRM
* @package RetailCRM
*/
class RetailcrmDependencyLoader extends \Intaro\RetailCrm\Component\DependencyLoader
{
}

View file

@ -0,0 +1,168 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Cart
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
use Bitrix\Main\Context\Culture;
use Bitrix\Sale\Basket;
use Bitrix\Sale\Discount\Context\Fuser;
use Bitrix\Sale\Discount;
IncludeModuleLangFile(__FILE__);
/**
* Class RetailCrmCart
*
* @category RetailCRM
* @package RetailCRM\Cart
*/
class RetailCrmCart
{
private static string $dateFormat = "Y-m-d H:i:sP";
/**
* @param array $arBasket
* @throws \Bitrix\Main\ArgumentException
* @throws \Bitrix\Main\ObjectPropertyException
* @throws \Bitrix\Main\SystemException
*
* @return array|null
*/
public static function handlerCart(array $arBasket)
{
$api = new RetailCrm\ApiClient(RetailcrmConfigProvider::getApiUrl(), RetailcrmConfigProvider::getApiKey());
$optionsSitesList = RetailcrmConfigProvider::getSitesList();
if ($optionsSitesList) {
if (array_key_exists($arBasket['LID'], $optionsSitesList) && $optionsSitesList[$arBasket['LID']] !== null) {
$site = $optionsSitesList[$arBasket['LID']];
$api->setSite($site);
} else {
RCrmActions::eventLog(
'RetailCrmCart::handlerCart',
'RetailcrmConfigProvider::getSitesList',
'Error set site'
);
return null;
}
} else {
$site = RetailcrmConfigProvider::getSitesAvailable();
}
$crmBasket = RCrmActions::apiMethod($api, 'cartGet', __METHOD__, $arBasket['USER_ID'], $site);
if (empty($arBasket['BASKET'])) {
if (!empty($crmBasket['cart']['items'])) {
return RCrmActions::apiMethod(
$api,
'cartClear',
__METHOD__,
[
'clearedAt' => date(self::$dateFormat),
'customer' => [
'externalId' => $arBasket['USER_ID']
]
],
$site
);
}
return null;
}
$date = 'createdAt';
$items = [];
foreach ($arBasket['BASKET'] as $itemBitrix) {
$item['quantity'] = $itemBitrix['QUANTITY'];
$item['price'] = $itemBitrix['PRICE'];
$item['createdAt'] = $itemBitrix['DATE_INSERT']->format(self::$dateFormat);
$item['updateAt'] = $itemBitrix['DATE_UPDATE']->format(self::$dateFormat);
$item['offer']['externalId'] = $itemBitrix['PRODUCT_ID'];
$items[] = $item;
}
if (!empty($crmBasket['cart']['items'])) {
$date = 'updatedAt';
}
return RCrmActions::apiMethod(
$api,
'cartSet',
__METHOD__,
[
'customer' => [
'externalId' => $arBasket['USER_ID'],
'site' => $site,
],
$date => date(self::$dateFormat),
'droppedAt' => date(self::$dateFormat),
'items' => $items,
'link' => static::generateCartLink(),
],
$site
);
}
/**
* @throws \Bitrix\Main\SystemException
*
* @return array|null
*/
public static function getBasketArray($event): ?array
{
if ($event instanceof Basket) {
$obBasket = $event;
} elseif ($event instanceof Event) {
$obBasket = $event->getParameter('ENTITY');
} else {
RCrmActions::eventLog('RetailCrmEvent::onChangeBasket', 'getBasketArray', 'event error');
return null;
}
$items = $obBasket->getBasket();
$arBasket = ['LID' => $obBasket->getSiteId()];
if (count($items) !== 0) {
$fUser = new Fuser($obBasket->getFUserId());
$discounts = Discount::buildFromBasket($obBasket, $fUser);
$discounts->calculate();
$resultBasket = $discounts->getApplyResult(true);
$basketItems = $resultBasket['PRICES']['BASKET'] ?? [];
foreach ($items as $item) {
$itemFields = $item->getFields()->getValues();
if (isset($basketItems[(int) $itemFields['ID']])) {
$itemFields['PRICE'] = $basketItems[(int) $itemFields['ID']]['PRICE'];
}
$arBasket['BASKET'][] = $itemFields;
}
}
return $arBasket;
}
public static function generateCartLink()
{
return sprintf(
'%s://%s/personal/cart',
!empty($_SERVER['HTTPS']) ? 'https' : 'http',
$_SERVER['HTTP_HOST']
);
}
}

View file

@ -0,0 +1,55 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Collector
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class RetailCrmCollector
*
* @category RetailCRM
* @package RetailCRM\Collector
*/
class RetailCrmCollector
{
public static $MODULE_ID = 'intaro.retailcrm';
public static $CRM_COLL_KEY = 'coll_key';
public static $CRM_COLL = 'collector';
/**
* Add Daemon Collector script
*
* @return bool
*/
public static function add()
{
$keys = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_COLL_KEY, 0));
$collector = COption::GetOptionString(self::$MODULE_ID, self::$CRM_COLL, 0);
$request = \Bitrix\Main\Context::getCurrent()->getRequest();
if ($collector === 'Y' && !empty($keys[SITE_ID]) && $request->isAdminSection() !== true) {
global $USER;
$params = array();
if ($USER->IsAuthorized()) {
$params['customerId'] = $USER->GetID();
}
$str = "<script type=\"text/javascript\">
(function(_,r,e,t,a,i,l){_['retailCRMObject']=a;_[a]=_[a]||function(){(_[a].q=_[a].q||[]).push(arguments)};_[a].l=1*new Date();l=r.getElementsByTagName(e)[0];i=r.createElement(e);i.async=!0;i.src=t;l.parentNode.insertBefore(i,l)})(window,document,'script','https://collector.retailcrm.pro/w.js','_rc');
_rc('create', '" . $keys[SITE_ID] . "', " . json_encode((object) $params) . ");
_rc('send', 'pageView');
</script>";
\Bitrix\Main\Page\Asset::getInstance()->addString($str, true);
return true;
} else {
return false;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<options>
<fields>
<field id="id" group="customer">id</field>
<field id="first_name" group="customer">firstName</field>
<field id="last_name" group="customer">lastName</field>
<field id="patronymic" group="customer">patronymic</field>
<field id="email" group="customer">email</field>
<field id="birthday" group="customer">birthday</field>
<field id="sex" group="customer">sex</field>
<field id="phones" group="customer">phones</field>
<field id="manager" group="customer">manager</field>
<field id="commentary" group="customer">commentary</field>
<field id="external_id" group="customer">externalId</field>
<field id="cumulative_discount" group="customer">cumulativeDiscount</field>
<field id="personal_discount" group="customer">personalDiscount</field>
<field id="discount_card_number" group="customer">discountCardNumber</field>
<field id="email_marketing_unsubscribed_at" group="customer">emailMarketingUnsubscribedAt</field>
<field id="address.index" group="customerAddress">index</field>
<field id="address.country" group="customerAddress">countryIso</field>
<field id="address.region" group="customerAddress">region</field>
<field id="address.city" group="customerAddress">city</field>
<field id="address.street" group="customerAddress">street</field>
<field id="address.building" group="customerAddress">building</field>
<field id="address.house" group="customerAddress">house</field>
<field id="address.block" group="customerAddress">block</field>
<field id="address.flat" group="customerAddress">flat</field>
<field id="address.floor" group="customerAddress">floor</field>
<field id="address.intercom_code" group="customerAddress">intercomCode</field>
<field id="address.metro" group="customerAddress">metro</field>
<field id="address.notes" group="customerAddress">notes</field>
<field id="contragent.contragent_type" group="customerContragent">contragentType</field>
<field id="contragent.legal_name" group="customerContragent">legalName</field>
<field id="contragent.legal_address" group="customerContragent">legalAddress</field>
<field id="contragent.certificate_number" group="customerContragent">certificateNumber</field>
<field id="contragent.certificate_date" group="customerContragent">certificateDate</field>
<field id="contragent.bank" group="customerContragent">bank</field>
<field id="contragent.bank_address" group="customerContragent">bankAddress</field>
<field id="contragent.i_n_n" group="customerContragent">INN</field>
<field id="contragent.o_k_p_o" group="customerContragent">OKPO</field>
<field id="contragent.k_p_p" group="customerContragent">KPP</field>
<field id="contragent.o_g_r_n" group="customerContragent">OGRN</field>
<field id="contragent.o_g_r_n_i_p" group="customerContragent">OGRNIP</field>
<field id="contragent.certificate_number" group="customerContragent">certificateNumber</field>
<field id="contragent.certificate_date" group="customerContragent">certificateDate</field>
<field id="contragent.b_i_k" group="customerContragent">BIK</field>
<field id="contragent.corr_account" group="customerContragent">corrAccount</field>
<field id="contragent.bank_account" group="customerContragent">bankAccount</field>
<field id="id" group="order">id</field>
<field id="created_at" group="order">createdAt</field>
<field id="order_type" group="order">orderType</field>
<field id="order_method" group="order">orderMethod</field>
<field id="site" group="order">site</field>
<field id="status" group="order">status</field>
<field id="status_comment" group="order">statusComment</field>
<field id="manager" group="order">manager</field>
<field id="first_name" group="order">firstName</field>
<field id="last_name" group="order">lastName</field>
<field id="patronymic" group="order">patronymic</field>
<field id="phone" group="order">phone</field>
<field id="additional_phone" group="order">additionalPhone</field>
<field id="email" group="order">email</field>
<field id="payment_type" group="order">paymentType</field>
<field id="payment_status" group="order">paymentStatus</field>
<field id="discount" group="order">discount</field>
<field id="discount_percent" group="order">discountPercent</field>
<field id="prepay_sum" group="order">prepaySum</field>
<field id="customer_comment" group="order">customerComment</field>
<field id="manager_comment" group="order">managerComment</field>
<field id="shipment_store" group="order">shipmentStore</field>
<field id="shipment_date" group="order">shipmentDate</field>
<field id="shipped" group="order">shipped</field>
<!--<field id="order_product" group="order">item</field>-->
<field id="order_product.id" group="item">id</field>
<field id="order_product.initial_price" group="item">initialPrice</field>
<field id="order_product.discount" group="item">discount</field>
<field id="order_product.discount_percent" group="item">discountPercent</field>
<field id="order_product.quantity" group="item">quantity</field>
<field id="order_product.status" group="item">status</field>
<field id="order_product.discount_total" group="item">discountTotal</field>
<field id="order_product.bonuses_charge" group="item">bonusesCharge</field>
<field id="order_product.bonuses_credit" group="item">bonusesCredit</field>
<field id="payments.status" group="payment">status</field>
<field id="payments.type" group="payment">type</field>
<field id="payments.external_id" group="payment">externalId</field>
<field id="payments.amount" group="payment">amount</field>
<field id="payments.comment" group="payment">comment</field>
<field id="delivery_type" group="delivery">code</field>
<field id="delivery_service" group="delivery">service</field>
<field id="delivery_date" group="delivery">date</field>
<field id="delivery_time" group="delivery">time</field>
<field id="delivery_cost" group="delivery">cost</field>
<field id="delivery_net_cost" group="delivery">netCost</field>
<field id="delivery_address.country" group="orderAddress">country</field>
<field id="delivery_address.index" group="orderAddress">index</field>
<field id="delivery_address.region" group="orderAddress">region</field>
<field id="delivery_address.city" group="orderAddress">city</field>
<field id="delivery_address.street" group="orderAddress">street</field>
<field id="delivery_address.building" group="orderAddress">building</field>
<field id="delivery_address.house" group="orderAddress">house</field>
<field id="delivery_address.housing" group="orderAddress">housing</field>
<field id="delivery_address.block" group="orderAddress">block</field>
<field id="delivery_address.flat" group="orderAddress">flat</field>
<field id="delivery_address.floor" group="orderAddress">floor</field>
<field id="delivery_address.intercom_code" group="orderAddress">intercomCode</field>
<field id="delivery_address.metro" group="orderAddress">metro</field>
<field id="delivery_address.notes" group="orderAddress">notes</field>
<field id="integration_delivery_data.status" group="integrationDelivery">status</field>
<field id="integration_delivery_data.track_number" group="integrationDelivery">trackNumber</field>
<field id="integration_delivery_data.courier" group="integrationDelivery">courier</field>
</fields>
</options>

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<options>
<contragents>
<contragent id="individual">Физ. лицо</contragent>
<contragent id="legal-entity">Юр. лицо</contragent>
<contragent id="enterpreneur">ИП</contragent>
</contragents>
<fields>
<field id="fio">Ф.И.О.</field>
<field id="phone">Телефон</field>
<field id="email">E-mail</field>
<field id="text">Адрес (строкой)</field>
<field id="city">Город</field>
<field id="index">Индекс</field>
<field id="street">Улица</field>
<field id="building">Номер дома</field>
<field id="flat">Квартира</field>
<field id="intercomcode">Домофон</field>
<field id="floor">Этаж</field>
<field id="block">Подъезд</field>
<field id="house">Строение</field>
<field id="housing">Корпус</field>
<field id="legalName" group="legal-entity, enterpreneur">Полное наименование</field>
<field id="legalAddress" group="legal-entity, enterpreneur">Адрес регистрации (Юридический адрес)</field>
<field id="INN" group="legal-entity, enterpreneur">ИНН</field>
<field id="OKPO" group="legal-entity, enterpreneur">ОКПО</field>
<field id="BIK" group="legal-entity, enterpreneur">БИК</field>
<field id="bank" group="legal-entity, enterpreneur">Банк</field>
<field id="bankAddress" group="legal-entity, enterpreneur">Адрес банка</field>
<field id="corrAccount" group="legal-entity, enterpreneur">Корреспондентский счет</field>
<field id="bankAccount" group="legal-entity, enterpreneur">Расчетный счет</field>
<field id="KPP" group="legal-entity">КПП</field>
<field id="OGRN" group="legal-entity">ОГРН</field>
<field id="OGRNIP" group="enterpreneur">ОГРНИП</field>
<field id="certificateNumber" group="enterpreneur">Номер свидетельства</field>
<field id="certificateDate" group="enterpreneur">Дата свидетельства</field>
</fields>
</options>

View file

@ -0,0 +1,567 @@
{
"customers": {
"externalId": {
"type": "string",
"required": true
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"patronymic": {
"type": "string"
},
"email": {
"type": "string"
},
"number": {
"type": "string"
},
"birthday": {
"type": "datetime",
"format": "Y-m-d"
},
"site": {
"type": "string"
},
"index": {
"type": "string"
},
"country": {
"type": "string"
},
"region": {
"type": "string"
},
"city": {
"type": "string"
},
"street": {
"type": "string"
},
"building": {
"type": "string"
},
"flat": {
"type": "string"
},
"intercomCode": {
"type": "string"
},
"floor": {
"type": "int"
},
"block": {
"type": "int"
},
"house": {
"type": "string"
},
"metro": {
"type": "string"
},
"notes": {
"type": "string"
},
"text": {
"type": "string"
},
"createdAt": {
"type": "datetime",
"format": "Y-m-d H:i:s"
},
"vip": {
"type": "bool",
"default": false
},
"bad": {
"type": "bool",
"default": false
},
"subscribed": {
"type": "string"
},
"commentary": {
"type": "string"
},
"customFields": {
"type": "skip"
},
"contragentType": {
"type": "enum",
"default": "individual",
"values": ["individual", "legal-entity", "enterpreneur"]
},
"legalName": {
"type": "string"
},
"legalAddress": {
"type": "string"
},
"INN": {
"type": "string"
},
"OKPO": {
"type": "string"
},
"KPP": {
"type": "string"
},
"OGRN": {
"type": "string"
},
"OGRNIP": {
"type": "string"
},
"certificateNumber": {
"type": "string"
},
"certificateDate": {
"type": "datetime",
"format": "Y-m-d"
},
"BIK": {
"type": "string"
},
"bank": {
"type": "string"
},
"bankAddress": {
"type": "string"
},
"corrAccount": {
"type": "string"
},
"bankAccount": {
"type": "string"
},
"managerId": {
"type": "int"
},
"browserId": {
"type": "string"
},
"discountCardNumber": {
"type": "string"
},
"personalDiscount": {
"type": "string"
},
"sex": {
"type": "string"
},
"emailMarketingUnsubscribedAt" : {
"type": "datetime",
"format": "Y-m-d H:i:s"
},
"source": {
"type": "string"
},
"medium": {
"type": "string"
},
"campaign": {
"type": "string"
},
"keyword": {
"type": "string"
},
"content": {
"type": "string"
}
},
"customerCorporate": {
"externalId": {
"type": "string",
"required": true
},
"createdAt": {
"type": "datetime",
"format": "Y-m-d H:i:s"
},
"contragentType": {
"type": "enum",
"default": "legal-entity",
"values": ["individual", "legal-entity", "enterpreneur"]
},
"isMain": {
"type": "bool",
"default": false
},
"site": {
"type": "string"
},
"nickName": {
"type": "string"
},
"name": {
"type": "string"
},
"text": {
"type": "string"
},
"legalName": {
"type": "string"
},
"legalAddress": {
"type": "string"
},
"INN": {
"type": "string"
},
"KPP": {
"type": "string"
}
},
"orders": {
"number": {
"type": "string"
},
"externalId": {
"type": "string",
"required": true
},
"id": {
"type": "string",
"required": false
},
"createdAt": {
"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,
"min": 0,
"decimals": 2
},
"discountPercent": {
"type": "double",
"default": 0,
"max": 100,
"min": 0,
"decimals": 2
},
"mark": {
"type": "int",
"max": 10,
"min": 0
},
"markDatetime": {
"type": "datetime",
"format": "Y-m-d H:i:s"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"patronymic": {
"type": "string"
},
"phone": {
"type": "string"
},
"additionalPhone": {
"type": "string"
},
"email": {
"type": "string"
},
"site": {
"type": "string"
},
"countryIso": {
"type": "string"
},
"call": {
"type": "bool",
"default": false
},
"expired": {
"type": "bool",
"default": false
},
"customerComment": {
"type": "string"
},
"managerComment": {
"type": "string"
},
"weight": {
"type": "double"
},
"length": {
"type": "int"
},
"width": {
"type": "int"
},
"height": {
"type": "int"
},
"paymentDetail": {
"type": "string"
},
"statusComment": {
"type": "string"
},
"customFields": {
"type": "skip"
},
"contragentType": {
"type": "enum",
"default": "individual",
"values": ["individual", "legal-entity", "enterpreneur"]
},
"legalName": {
"type": "string"
},
"legalAddress": {
"type": "string"
},
"INN": {
"type": "string"
},
"OKPO": {
"type": "string"
},
"KPP": {
"type": "string"
},
"OGRN": {
"type": "string"
},
"OGRNIP": {
"type": "string"
},
"certificateNumber": {
"type": "string"
},
"certificateDate": {
"type": "datetime",
"format": "Y-m-d"
},
"BIK": {
"type": "string"
},
"bank": {
"type": "string"
},
"bankAddress": {
"type": "string"
},
"corrAccount": {
"type": "string"
},
"bankAccount": {
"type": "string"
},
"shipmentDate": {
"type": "datetime",
"format": "Y-m-d"
},
"shipped": {
"type": "bool",
"default": false
},
"orderType": {
"type": "string"
},
"orderMethod": {
"type": "string"
},
"customerId": {
"type": "string"
},
"managerId": {
"type": "int"
},
"deliveryTime": {
"type": "string"
},
"paymentType": {
"type": "string"
},
"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"
},
"sourceId": {
"type": "string"
},
"initialPrice": {
"type": "double",
"default": 0,
"min": 0,
"decimals": 2
},
"quantity": {
"type": "double",
"default": 1,
"min": 0,
"decimals": 3
},
"properties": {
"type": "skip"
},
"productId": {
"type": "string"
},
"productName": {
"type": "string"
},
"comment": {
"type": "string"
},
"purchasePrice": {
"type": "double",
"default": 0,
"min": 0,
"decimals": 2
},
"code": {
"type": "string"
},
"integrationCode": {
"type": "string"
},
"data": {
"type": "skip"
},
"service": {
"type": "skip"
},
"cost": {
"type": "string"
},
"date": {
"type": "datetime",
"format": "Y-m-d"
},
"index": {
"type": "string"
},
"country": {
"type": "string"
},
"region": {
"type": "string"
},
"city": {
"type": "string"
},
"street": {
"type": "string"
},
"building": {
"type": "string"
},
"flat": {
"type": "string"
},
"intercomCode": {
"type": "string"
},
"floor": {
"type": "int"
},
"block": {
"type": "int"
},
"house": {
"type": "string"
},
"housing": {
"type": "string"
},
"metro": {
"type": "string"
},
"notes": {
"type": "string"
},
"text": {
"type": "string"
},
"address": {
"type": "string"
},
"shipmentStore": {
"type": "string"
},
"from": {
"type": "skip"
},
"to": {
"type": "skip"
},
"custom": {
"type": "string"
},
"vatRate": {
"type": "string"
},
"name": {
"type": "string"
},
"value": {
"type": "string"
},
"xmlId": {
"type": "string"
},
"netCost": {
"type": "double"
},
"source": {
"type": "string"
},
"medium": {
"type": "string"
},
"campaign": {
"type": "string"
},
"keyword": {
"type": "string"
},
"content": {
"type": "string"
},
"privilegeType": {
"type": "string"
}
}
}

View file

@ -0,0 +1,40 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Consultant
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class RetailCrmOnlineConsultant
*
* @category RetailCRM
* @package RetailCRM\Consultant
*/
class RetailCrmOnlineConsultant
{
/**
* Add a script of online consultant
*
* @return bool
*/
public static function add()
{
$request = \Bitrix\Main\Context::getCurrent()->getRequest();
if (RetailcrmConfigProvider::isOnlineConsultantEnabled() && $request->isAdminSection() !== true) {
\Bitrix\Main\Page\Asset::getInstance()->addString(
RetailcrmConfigProvider::getOnlineConsultantScript(),
true
);
return true;
} else {
return false;
}
}
}

View file

@ -0,0 +1,763 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Events
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
use Bitrix\Main\Context\Culture;
use Bitrix\Main\Engine\CurrentUser;
use Intaro\RetailCrm\Component\Constants;
use Intaro\RetailCrm\Component\ServiceLocator;
use Intaro\RetailCrm\Repository\UserRepository;
use Intaro\RetailCrm\Service\CustomerService;
use Intaro\RetailCrm\Service\LoyaltyAccountService;
use Intaro\RetailCrm\Service\ManagerService;
use Bitrix\Sale\Payment;
use Bitrix\Catalog\Model\Event;
use Bitrix\Main\UserTable;
use Bitrix\Sale\Order;
use Intaro\RetailCrm\Component\ConfigProvider;
use Intaro\RetailCrm\Model\Api\Response\OrdersCreateResponse;
use Intaro\RetailCrm\Model\Api\Response\OrdersEditResponse;
/**
* Class RetailCrmEvent
*
* @category RetailCRM
* @package RetailCRM\Events
*/
class RetailCrmEvent
{
protected static $MODULE_ID = 'intaro.retailcrm';
protected static $CRM_API_HOST_OPTION = 'api_host';
protected static $CRM_API_KEY_OPTION = 'api_key';
protected static $CRM_ORDER_TYPES_ARR = 'order_types_arr';
protected static $CRM_DELIVERY_TYPES_ARR = 'deliv_types_arr';
protected static $CRM_PAYMENT_TYPES = 'pay_types_arr';
protected static $CRM_PAYMENT_STATUSES = 'pay_statuses_arr';
protected static $CRM_PAYMENT = 'payment_arr';
protected static $CRM_ORDER_LAST_ID = 'order_last_id';
protected static $CRM_ORDER_PROPS = 'order_props';
protected static $CRM_LEGAL_DETAILS = 'legal_details';
protected static $CRM_CUSTOM_FIELDS = 'custom_fields';
protected static $CRM_CONTRAGENT_TYPE = 'contragent_type';
protected static $CRM_ORDER_FAILED_IDS = 'order_failed_ids';
protected static $CRM_SITES_LIST = 'sites_list';
protected static $CRM_CC = 'cc';
protected static $CRM_CORP_NAME = 'nickName-corporate';
protected static $CRM_CORP_ADRES = 'adres-corporate';
/**
* @param $arFields
*
* @return bool
* @throws InvalidArgumentException
*/
public static function OnAfterUserUpdate($arFields)
{
RetailCrmService::writeLogsSubscribe($arFields);
if (isset($GLOBALS['RETAIL_CRM_HISTORY']) && $GLOBALS['RETAIL_CRM_HISTORY']) {
return false;
}
if (!$arFields['RESULT']) {
return false;
}
$optionsSitesList = RetailcrmConfigProvider::getSitesList();
$api = new RetailCrm\ApiClient(RetailcrmConfigProvider::getApiUrl(), RetailcrmConfigProvider::getApiKey());
$resultOrder = RetailCrmUser::customerEdit($arFields, $api, $optionsSitesList);
if (!$resultOrder) {
RCrmActions::eventLog('RetailCrmEvent::OnAfterUserUpdate', 'RetailCrmUser::customerEdit', 'error update customer');
}
return true;
}
/**
* onUpdateOrder
*
* @param mixed $ID - Order id
* @param mixed $arFields - Order arFields
*/
public static function onUpdateOrder($ID, $arFields)
{
if (isset($GLOBALS['RETAIL_CRM_HISTORY']) && $GLOBALS['RETAIL_CRM_HISTORY']) {
$GLOBALS['RETAILCRM_ORDER_OLD_EVENT'] = false;
return;
}
$GLOBALS['RETAILCRM_ORDER_OLD_EVENT'] = true;
if (($arFields['CANCELED'] === 'Y')
&& (sizeof($arFields['BASKET_ITEMS']) == 0)
&& (sizeof($arFields['ORDER_PROP']) == 0)
) {
$GLOBALS['ORDER_DELETE_USER_ADMIN'] = true;
}
return;
}
/**
* orderDelete
*
* @param object $event - Order object
*/
public static function orderDelete($event)
{
$GLOBALS['RETAILCRM_ORDER_DELETE'] = true;
}
/**
* событие изменения корзины
*
* @param object $event
*/
public static function onChangeBasket($event)
{
$apiVersion = COption::GetOptionString(self::$MODULE_ID, 'api_version', 0);
if ($apiVersion !== 'v5') {
return;
}
$id = CurrentUser::get()->getId();
if ($id) {
$arBasket = RetailCrmCart::getBasketArray($event);
if ($arBasket === null) {
return;
}
$arBasket['USER_ID'] = $id;
RetailCrmCart::handlerCart($arBasket);
}
}
/**
* @param $event
*
* @return array|bool|OrdersCreateResponse|OrdersEditResponse|null
* @throws \Bitrix\Main\ArgumentException
* @throws \Bitrix\Main\ObjectPropertyException
* @throws \Bitrix\Main\SystemException
* @throws \Exception
*/
public static function orderSave($event)
{
if (!static::checkConfig()) {
return null;
}
$arOrder = static::getOrderArray($event);
$api = new RetailCrm\ApiClient(RetailcrmConfigProvider::getApiUrl(), RetailcrmConfigProvider::getApiKey());
//params
$optionsOrderTypes = RetailcrmConfigProvider::getOrderTypes();
$optionsDelivTypes = RetailcrmConfigProvider::getDeliveryTypes();
$optionsPayTypes = RetailcrmConfigProvider::getPaymentTypes();
$optionsPayStatuses = RetailcrmConfigProvider::getPaymentStatuses(); // --statuses
$optionsPayment = RetailcrmConfigProvider::getPayment();
$optionsSitesList = RetailcrmConfigProvider::getSitesList();
$optionsOrderProps = RetailcrmConfigProvider::getOrderProps();
$optionsLegalDetails = RetailcrmConfigProvider::getLegalDetails();
$optionsContragentType = RetailcrmConfigProvider::getContragentTypes();
$optionsCustomFields = RetailcrmConfigProvider::getCustomFields();
//corp cliente swich
$optionCorpClient = RetailcrmConfigProvider::getCorporateClientStatus();
$arParams = RCrmActions::clearArr([
'optionsOrderTypes' => $optionsOrderTypes,
'optionsDelivTypes' => $optionsDelivTypes,
'optionsPayTypes' => $optionsPayTypes,
'optionsPayStatuses' => $optionsPayStatuses,
'optionsPayment' => $optionsPayment,
'optionsOrderProps' => $optionsOrderProps,
'optionsLegalDetails' => $optionsLegalDetails,
'optionsContragentType' => $optionsContragentType,
'optionsSitesList' => $optionsSitesList,
'optionsCustomFields' => $optionsCustomFields,
'customOrderProps' => RetailcrmConfigProvider::getMatchedOrderProps(),
]);
//many sites?
if ($optionsSitesList) {
if (array_key_exists($arOrder['LID'], $optionsSitesList) && $optionsSitesList[$arOrder['LID']] !== null) {
$site = $optionsSitesList[$arOrder['LID']];
} else {
return null;
}
} elseif (!$optionsSitesList) {
$site = null;
}
$api->setSite($site);
//new order?
$orderCrm = RCrmActions::apiMethod($api, 'ordersGet', __METHOD__, $arOrder['ID'], $site);
if (isset($orderCrm['order'])) {
$methodApi = 'ordersEdit';
$arParams['crmOrder'] = $orderCrm['order'];
} else {
$methodApi = 'ordersCreate';
}
$orderCompany = null;
if (
('Y' === $optionCorpClient)
&& true === RetailCrmCorporateClient::isCorpTookExternalId((string)$arOrder['USER_ID'], $api, $site)
) {
RetailCrmCorporateClient::setPrefixForExternalId((string) $arOrder['USER_ID'], $api, $site);
}
//TODO эта управляющая конструкция по функционалу дублирует RetailCrmOrder::createCustomerForOrder.
// Необходимо устранить дублирование, вынеся логику в обособленный класс-сервис
if ('Y' === $optionCorpClient && in_array($optionsContragentType[$arOrder['PERSON_TYPE_ID']], ['legal-entity', 'enterpreneur'])) {
//corparate cliente
$nickName = '';
$address = '';
$corpAddress = '';
$contragent = [];
$userCorp = [];
$corpName = RetailcrmConfigProvider::getCorporateClientName();
$corpAddress = RetailcrmConfigProvider::getCorporateClientAddress();
foreach ($arOrder['PROPS']['properties'] as $prop) {
if ($prop['CODE'] === $corpName) {
$nickName = $prop['VALUE'][0];
}
if ($prop['CODE'] === $corpAddress) {
$address = $prop['VALUE'][0];
}
if (!empty($optionsLegalDetails)
&& $search = array_search($prop['CODE'], $optionsLegalDetails[$arOrder['PERSON_TYPE_ID']])
) {
$contragent[$search] = $prop['VALUE'][0];//legal order data
}
}
if (!empty($contragentType)) {
$contragent['contragentType'] = $contragentType;
}
$customersCorporate = false;
$response = $api->customersCorporateList(['companyName' => $nickName]);
if ($response && $response->getStatusCode() == 200) {
$customersCorporate = $response['customersCorporate'];
$singleCorp = reset($customersCorporate);
if (!empty($singleCorp)) {
$userCorp['customerCorporate'] = $singleCorp;
$companiesResponse = $api->customersCorporateCompanies(
$singleCorp['id'],
[],
null,
null,
'id',
$site
);
if ($companiesResponse && $companiesResponse->isSuccessful()) {
$orderCompany = array_reduce(
$companiesResponse['companies'],
function ($carry, $item) use ($nickName) {
if (is_array($item) && $item['name'] === $nickName) {
$carry = $item;
}
return $carry;
},
null
);
}
}
} else {
RCrmActions::eventLog(
'RetailCrmEvent::orderSave',
'ApiClient::customersCorporateList',
'error during fetching corporate customers'
);
return null;
}
//user
$userCrm = RCrmActions::apiMethod($api, 'customersGet', __METHOD__, $arOrder['USER_ID'], $site);
if (!isset($userCrm['customer'])) {
$arUser = CUser::GetByID($arOrder['USER_ID'])->Fetch();
if (!empty($address)) {
$arUser['PERSONAL_STREET'] = $address;
}
$resultUser = RetailCrmUser::customerSend($arUser, $api, 'individual', true, $site);
if (!$resultUser) {
RCrmActions::eventLog(
__CLASS__ . '::' . __METHOD__,
'RetailCrmUser::customerSend',
'error during creating customer'
);
return null;
}
$userCrm = ['customer' => ['externalId' => $arOrder['USER_ID']]];
}
if (!isset($userCorp['customerCorporate'])) {
$resultUserCorp = RetailCrmCorporateClient::clientSend(
$arOrder,
$api,
$optionsContragentType[$arOrder['PERSON_TYPE_ID']],
true,
false,
$site
);
Logger::getInstance()->write($resultUserCorp, 'resultUserCorp');
if (!$resultUserCorp) {
RCrmActions::eventLog('RetailCrmEvent::orderSave', 'RetailCrmCorporateClient::clientSend', 'error during creating client');
return null;
}
$arParams['customerCorporate'] = $resultUserCorp;
$arParams['orderCompany'] = $resultUserCorp['mainCompany'] ?? null;
$customerCorporateAddress = [];
$customerCorporateCompany = [];
$addressResult = null;
$companyResult = null;
if (!empty($address)) {
//TODO address builder add
$customerCorporateAddress = [
'name' => $nickName,
'isMain' => true,
'text' => $address,
];
$addressResult = $api->customersCorporateAddressesCreate($resultUserCorp['id'], $customerCorporateAddress, 'id', $site);
}
$customerCorporateCompany = [
'name' => $nickName,
'isMain' => true,
'contragent' => $contragent,
];
if (!empty($addressResult)) {
$customerCorporateCompany['address'] = [
'id' => $addressResult['id'],
];
}
$companyResult = $api->customersCorporateCompaniesCreate($resultUserCorp['id'], $customerCorporateCompany, 'id', $site);
$customerCorporateContact = [
'isMain' => true,
'customer' => [
'externalId' => $arOrder['USER_ID'],
'site' => $site,
],
];
if (!empty($companyResult)) {
$orderCompany = [
'id' => $companyResult['id'],
];
$customerCorporateContact['companies'] = [
[
'company' => $orderCompany,
],
];
}
$api->customersCorporateContactsCreate(
$resultUserCorp['id'],
$customerCorporateContact,
'id',
$site
);
$arParams['orderCompany'] = array_merge(
$customerCorporateCompany,
['id' => $companyResult['id']]
);
} else {
RetailCrmCorporateClient::addCustomersCorporateAddresses(
$userCorp['customerCorporate']['id'],
$nickName,
$address,
$api,
$site
);
$arParams['customerCorporate'] = $userCorp['customerCorporate'];
if (!empty($orderCompany)) {
$arParams['orderCompany'] = $orderCompany;
}
}
$arParams['contactExId'] = $userCrm['customer']['externalId'];
} else {
//user
$userCrm = RCrmActions::apiMethod($api, 'customersGet', __METHOD__, $arOrder['USER_ID'], $site);
if (!isset($userCrm['customer'])) {
$arUser = CUser::GetByID($arOrder['USER_ID'])->Fetch();
$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 null;
}
}
}
if (isset($arOrder['RESPONSIBLE_ID']) && !empty($arOrder['RESPONSIBLE_ID'])) {
$managerService = ManagerService::getInstance();
$arParams['managerId'] = $managerService->getManagerCrmId($arOrder['RESPONSIBLE_ID']);
}
//order
$resultOrder = RetailCrmOrder::orderSend($arOrder, $api, $arParams, true, $site, $methodApi);
if (!$resultOrder) {
RCrmActions::eventLog(
'RetailCrmEvent::orderSave',
'RetailCrmOrder::orderSend',
'error during creating order'
);
return null;
}
return $resultOrder;
}
/**
* @param \Bitrix\Sale\Payment $event
*
* @return bool
* @throws InvalidArgumentException
*
*/
public static function paymentSave(Payment $event)
{
$apiVersion = COption::GetOptionString(self::$MODULE_ID, 'api_version', 0);
/** @var \Bitrix\Sale\Order $order */
$order = $event->getCollection()->getOrder();
if ((isset($GLOBALS['RETAIL_CRM_HISTORY']) && $GLOBALS['RETAIL_CRM_HISTORY'])
|| $apiVersion !== 'v5'
|| $order->isNew()
) {
return false;
}
$optionsSitesList = RetailcrmConfigProvider::getSitesList();
$optionsPaymentTypes = RetailcrmConfigProvider::getPaymentTypes();
$optionsPayStatuses = RetailcrmConfigProvider::getPayment();
$integrationPaymentTypes = RetailcrmConfigProvider::getIntegrationPaymentTypes();
$arPayment = [
'ID' => $event->getId(),
'ORDER_ID' => $event->getField('ORDER_ID'),
'PAID' => $event->getField('PAID'),
'PAY_SYSTEM_ID' => $event->getField('PAY_SYSTEM_ID'),
'SUM' => $event->getField('SUM'),
'LID' => $order->getSiteId(),
'DATE_PAID' => $event->getField('DATE_PAID'),
];
if ($optionsSitesList) {
if (array_key_exists($arPayment['LID'], $optionsSitesList) && $optionsSitesList[$arPayment['LID']] !== null) {
$site = $optionsSitesList[$arPayment['LID']];
} else {
return false;
}
} elseif (!$optionsSitesList) {
$site = null;
}
$api = new RetailCrm\ApiClient(RetailcrmConfigProvider::getApiUrl(), RetailcrmConfigProvider::getApiKey());
$orderCrm = RCrmActions::apiMethod($api, 'ordersGet', __METHOD__, $arPayment['ORDER_ID'], $site);
if (isset($orderCrm['order'])) {
$payments = $orderCrm['order']['payments'];
}
$paymentsExternalIds = [];
if (!empty($payments)) {
foreach ($payments as $payment) {
if (isset($payment['externalId'])) {
if (RCrmActions::isNewExternalId($payment['externalId'])) {
$paymentsExternalIds[RCrmActions::getFromPaymentExternalId($payment['externalId'])] =
$payment;
} else {
$paymentsExternalIds[$payment['externalId']] = $payment;
}
}
}
}
if (!empty($arPayment['PAY_SYSTEM_ID']) && isset($optionsPaymentTypes[$arPayment['PAY_SYSTEM_ID']])) {
$paymentToCrm = [];
if (!empty($arPayment['ID'])) {
$paymentToCrm['externalId'] = RCrmActions::generatePaymentExternalId($arPayment['ID']);
}
if (!empty($arPayment['DATE_PAID'])) {
if (is_object($arPayment['DATE_PAID'])) {
$culture = new Culture(['FORMAT_DATETIME' => 'YYYY-MM-DD HH:MI:SS']);
$paymentToCrm['paidAt'] = $arPayment['DATE_PAID']->toString($culture);
} elseif (is_string($arPayment['DATE_PAID'])) {
$paymentToCrm['paidAt'] = $arPayment['DATE_PAID'];
}
}
if (!empty($optionsPayStatuses[$arPayment['PAID']])) {
$paymentToCrm['status'] = $optionsPayStatuses[$arPayment['PAID']];
}
if (!empty($arPayment['ORDER_ID'])) {
$paymentToCrm['order']['externalId'] = $arPayment['ORDER_ID'];
}
if (RetailcrmConfigProvider::shouldSendPaymentAmount()) {
$paymentToCrm['amount'] = $arPayment['SUM'];
}
$paymentToCrm = RetailCrmService::preparePayment($paymentToCrm, $arPayment, $optionsPaymentTypes);
} else {
RCrmActions::eventLog('RetailCrmEvent::paymentSave', 'payments', 'OrderID = ' . $arPayment['ID'] . '. Payment not found.');
return false;
}
$arPaymentExtId = RCrmActions::generatePaymentExternalId($arPayment['ID']);
if (!empty($paymentsExternalIds) && array_key_exists($arPaymentExtId, $paymentsExternalIds)) {
$paymentData = $paymentsExternalIds[$arPaymentExtId];
} elseif (!empty($paymentsExternalIds) && array_key_exists($arPayment['ID'], $paymentsExternalIds)) {
$paymentData = $paymentsExternalIds[$arPayment['ID']];
} else {
$paymentData = [];
}
if (empty($paymentData)) {
RCrmActions::apiMethod($api, 'ordersPaymentCreate', __METHOD__, $paymentToCrm, $site);
} elseif ($paymentData['type'] == $optionsPaymentTypes[$arPayment['PAY_SYSTEM_ID']]) {
if (in_array($paymentData['type'], $integrationPaymentTypes)) {
RCrmActions::eventLog(
'RetailCrmEvent::paymentSave',
'payments',
'OrderID = ' . $arPayment['ID'] . '. Integration payment detected, which is not editable.'
);
return false;
}
$paymentToCrm['externalId'] = $paymentData['externalId'];
RCrmActions::apiMethod($api, 'paymentEditByExternalId', __METHOD__, $paymentToCrm, $site);
} elseif ($paymentData['type'] != $optionsPaymentTypes[$arPayment['PAY_SYSTEM_ID']]) {
RCrmActions::apiMethod(
$api,
'ordersPaymentDelete',
__METHOD__,
$paymentData['id']
);
RCrmActions::apiMethod($api, 'ordersPaymentCreate', __METHOD__, $paymentToCrm, $site);
}
return true;
}
/**
* @param \Bitrix\Sale\Payment $event
*
* @throws InvalidArgumentException
*/
public static function paymentDelete(Payment $event): void
{
$apiVersion = COption::GetOptionString(self::$MODULE_ID, 'api_version', 0);
if ((isset($GLOBALS['RETAIL_CRM_HISTORY']) && $GLOBALS['RETAIL_CRM_HISTORY'])
|| $apiVersion !== 'v5'
|| !$event->getId()
) {
return;
}
$optionsSitesList = RetailcrmConfigProvider::getSitesList();
$arPayment = [
'ID' => $event->getId(),
'ORDER_ID' => $event->getField('ORDER_ID'),
'LID' => $event->getCollection()->getOrder()->getSiteId(),
];
if ($optionsSitesList) {
if (array_key_exists($arPayment['LID'], $optionsSitesList) && $optionsSitesList[$arPayment['LID']] !== null) {
$site = $optionsSitesList[$arPayment['LID']];
} else {
return;
}
} elseif (!$optionsSitesList) {
$site = null;
}
$api = new RetailCrm\ApiClient(ConfigProvider::getApiUrl(), ConfigProvider::getApiKey());
$orderCrm = RCrmActions::apiMethod($api, 'ordersGet', __METHOD__, $arPayment['ORDER_ID'], $site);
if (isset($orderCrm['order']['payments']) && $orderCrm['order']['payments']) {
foreach ($orderCrm['order']['payments'] as $payment) {
if (isset($payment['externalId'])
&& ($payment['externalId'] == $event->getId()
|| RCrmActions::getFromPaymentExternalId($payment['externalId']) == $event->getId())
) {
RCrmActions::apiMethod($api, 'ordersPaymentDelete', __METHOD__, $payment['id']);
}
}
}
}
/**
* Регистрирует пользователя в CRM системе после регистрации на сайте
*
* @param array $arFields
* @return mixed
* @throws \ReflectionException
*/
public static function OnAfterUserRegister(array $arFields): void
{
if (isset($arFields['USER_ID']) && $arFields['USER_ID'] > 0) {
$user = UserRepository::getById($arFields['USER_ID']);
if (isset($_POST['REGISTER']['PERSONAL_PHONE'])) {
$phone = htmlspecialchars($_POST['REGISTER']['PERSONAL_PHONE']);
if ($user !== null) {
$user->setPersonalPhone($phone);
$user->save();
}
$arFields['PERSONAL_PHONE'] = $phone;
}
/* @var CustomerService $customerService */
$customerService = ServiceLocator::get(CustomerService::class);
$customer = $customerService->createModel($arFields['USER_ID']);
$customerService->createOrUpdateCustomer($customer);
RetailCrmService::writeLogsSubscribe($arFields);
//Если пользователь выразил желание зарегистрироваться в ПЛ и согласился со всеми правилами
if ((int) $arFields['UF_REG_IN_PL_INTARO'] === 1
&& (int) $arFields['UF_AGREE_PL_INTARO'] === 1
&& (int) $arFields['UF_PD_PROC_PL_INTARO'] === 1
) {
$phone = $arFields['PERSONAL_PHONE'] ?? '';
$card = $arFields['UF_CARD_NUM_INTARO'] ?? '';
$customerId = (string) $arFields['USER_ID'];
/** @var LoyaltyAccountService $service */
$service = ServiceLocator::get(LoyaltyAccountService::class);
$createResponse = $service->createLoyaltyAccount($phone, $card, $customerId);
$service->activateLpUserInBitrix($createResponse, $arFields['USER_ID']);
}
}
}
/**
* @param $arFields
*
* @return void
* @throws InvalidArgumentException
*/
public static function OnAfterUserAdd($arFields)
{
RetailCrmService::writeLogsSubscribe($arFields);
}
/**
* @return bool
*/
private static function checkConfig(): bool
{
if (true == $GLOBALS['ORDER_DELETE_USER_ADMIN']) {
return false;
}
if ($GLOBALS['RETAILCRM_ORDER_OLD_EVENT'] === false
&& $GLOBALS['RETAILCRM_ORDER_DELETE'] === true
) {
return false;
}
if ($GLOBALS['RETAIL_CRM_HISTORY'] === true) {
return false;
}
if (!RetailcrmDependencyLoader::loadDependencies()) {
return false;
}
return true;
}
/**
* @param \Bitrix\Sale\Order|\Bitrix\Main\Event $event
*
* @throws \Bitrix\Main\SystemException
*/
private static function getOrderArray($event): ?array
{
if ($event instanceof Order) {
$obOrder = $event;
} elseif ($event instanceof Event) {
$obOrder = $event->getParameter('ENTITY');
} else {
RCrmActions::eventLog('RetailCrmEvent::orderSave', 'events', 'event error');
return null;
}
return RetailCrmOrder::orderObjToArr($obOrder);
}
}

View file

@ -0,0 +1,37 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\History
*/
define("NO_KEEP_STATISTIC", true);
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php');
$GLOBALS['APPLICATION']->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);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,54 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\History
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class RetailUser
*
* @category RetailCRM
* @package RetailCRM\History
*/
class RetailUser extends CUser
{
/**
* @return int|mixed|string|null
*/
public function GetID()
{
$rsUser = CUser::GetList(($by = 'ID'), ($order = 'DESC'), ['LOGIN' => 'retailcrm']);
if ($arUser = $rsUser->Fetch()) {
return $arUser['ID'];
}
$retailUser = new CUser;
$userPassword = uniqid();
$arFields = [
'NAME' => 'retailcrm',
'LAST_NAME' => 'retailcrm',
'EMAIL' => 'retailcrm@retailcrm.com',
'LOGIN' => 'retailcrm',
'LID' => 'ru',
'ACTIVE' => 'Y',
'GROUP_ID' => [2],
'PASSWORD' => $userPassword,
'CONFIRM_PASSWORD' => $userPassword,
];
$id = $retailUser->Add($arFields);
if (!$id) {
return null;
}
return $id;
}
}

View file

@ -0,0 +1,170 @@
<?php
IncludeModuleLangFile(__FILE__);
/**
* @category RetailCRM
* @package RetailCRM\Inventories
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class RetailCrmInventories
*
* @category RetailCRM
* @package RetailCRM\Inventories
*/
class RetailCrmInventories
{
public static $pageSize = 500;
public static function inventoriesUpload()
{
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 = new RetailCrm\ApiClient(RetailcrmConfigProvider::getApiUrl(), RetailcrmConfigProvider::getApiKey());
$infoBlocks = RetailcrmConfigProvider::getInfoblocksInventories();
$stores = RetailcrmConfigProvider::getStores();
$shops = RetailcrmConfigProvider::getShops();
try {
$inventoriesList = $api->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) {
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();
$storesChunks = array_chunk($stores, 50, true);
foreach ($storesChunks as $storesChunk) {
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($storesChunk)),
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' => $storesChunk[$arStoreProduct['STORE_ID']],
'available' => self::switchCount($arStoreProduct['AMOUNT'], $inventoriesType[$storesChunk[$arStoreProduct['STORE_ID']]]),
);
}
//for log
$splitedItems = array_chunk($invUpload, 200);
foreach ($splitedItems as $chunk) {
Logger::getInstance()->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;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,170 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Prices
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
IncludeModuleLangFile(__FILE__);
/**
* Class RetailCrmPrices
*
* @category RetailCRM
* @package RetailCRM\Prices
*/
class RetailCrmPrices
{
public static $MODULE_ID = 'intaro.retailcrm';
public static $CRM_API_HOST_OPTION = 'api_host';
public static $CRM_API_KEY_OPTION = 'api_key';
public static $CRM_PRICES_UPLOAD = 'prices_upload';
public static $CRM_PRICES = 'prices';
public static $CRM_PRICE_SHOPS = 'price_shops';
public static $CRM_IBLOCKS_PRICES = 'iblock_prices';
public static $pageSize = 500;
public static function pricesUpload()
{
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);
$api = new RetailCrm\ApiClient($api_host, $api_key);
$infoBlocks = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_IBLOCKS_PRICES, 0));
$prices = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_PRICES, 0));
$shops = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_PRICE_SHOPS, 0));
if (count($shops) == 0) {
RCrmActions::eventLog('RetailCrmPrices::pricesUpload()', '$shops', 'No stores selected for download');
return false;
}
if (count($prices) == 0) {
RCrmActions::eventLog('RetailCrmPrices::pricesUpload()', '$prices', 'No prices selected for download');
return false;
}
if (count($infoBlocks) > 0) {
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'],
);
}
}
foreach ($shops as $shop) {
foreach ($elems as $value) {
if (!array_key_exists($value . '-' . $shop, $pricesUpload)) {
foreach ($prices as $key => $price) {
$pricesUpload[$value . '-' . $shop] = array(
'externalId' => $value,
'site' => $shop
);
$pricesUpload[$value . '-'. $shop]['prices'][] = array(
'code' => $prices[$key],
'remove' => true
);
}
}
}
}
//for log
$splitedItems = array_chunk($pricesUpload, 200);
foreach ($splitedItems as $chunk) {
Logger::getInstance()->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();';
}
}

View file

@ -0,0 +1,65 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Service
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
use Bitrix\Sale\Order;
use Bitrix\Main\Context;
use Bitrix\Catalog\StoreTable;
/**
* Class BitrixOrderService
*
* @category RetailCRM
* @package RetailCRM\Service
*/
class BitrixOrderService
{
public static function getCountryList()
{
$server = Context::getCurrent()->getServer()->getDocumentRoot();
$countryList = [];
if (file_exists($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/country.xml')) {
$countryFile = simplexml_load_file($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/country.xml');
foreach ($countryFile->country as $country) {
$countryList[RCrmActions::fromJSON((string) $country->name)] = (string) $country->alpha;
}
}
return $countryList;
}
public static function getPickupPointAddress($arOrder)
{
$address = '';
$orderInfo = Order::load($arOrder['ID']);
foreach ($orderInfo->getShipmentCollection() as $store) {
$storeId = $store->getStoreId();
if ($storeId) {
$arStore = StoreTable::getRow([
'filter' => [
'ID' => $storeId,
]
]);
if (!empty($arStore['ADDRESS'])) {
$address = GetMessage('PICKUP_POINT') . $arStore['ADDRESS'];
break;
}
}
}
return $address;
}
}

View file

@ -0,0 +1,220 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Service
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
use Intaro\RetailCrm\Component\Constants;
/**
* Class RetailCrmService
*
* @category RetailCRM
* @package RetailCRM\Service
*/
class RetailCrmService
{
/**
* @param $order
*
* @return array
*/
public static function unsetIntegrationDeliveryFields(array $order): array
{
$integrationDelivery = RetailcrmConfigProvider::getCrmIntegrationDelivery();
if (isset($order['delivery']['code'])) {
$deliveryCode = $order['delivery']['code'];
if (!empty($integrationDelivery[$deliveryCode])
&& $integrationDelivery[$deliveryCode] !== 'sdek'
&& $integrationDelivery[$deliveryCode] !== 'dpd'
&& $integrationDelivery[$deliveryCode] !== 'newpost'
&& $integrationDelivery[$deliveryCode] !== 'courier'
) {
unset($order['weight']);
unset($order['firstName']);
unset($order['lastName']);
unset($order['phone']);
unset($order['delivery']['cost']);
unset($order['paymentType']);
unset($order['shipmentStore']);
unset($order['delivery']['address']);
unset($order['delivery']['data']);
}
switch ($integrationDelivery[$deliveryCode]) {
case "sdek":
unset($order['weight']);
unset($order['length']);
unset($order['width']);
unset($order['height']);
unset($order['phone']);
unset($order['delivery']['cost']);
unset($order['paymentType']);
unset($order['shipmentStore']);
unset($order['number']);
unset($order['delivery']['address']);
unset($order['delivery']['data']);
break;
case "dpd":
unset($order['weight']);
unset($order['manager']);
unset($order['phone']);
unset($order['firstName']);
unset($order['lastName']);
unset($order['delivery']['cost']);
unset($order['paymentType']);
unset($order['shipmentStore']);
unset($order['delivery']['address']);
unset($order['delivery']['data']);
break;
case "newpost":
unset($order['weight']);
unset($order['customer']);
unset($order['phone']);
unset($order['shipmentStore']);
unset($order['paymentType']);
unset($order['delivery']['cost']);
unset($order['delivery']['address']);
unset($order['delivery']['data']);
break;
}
}
return $order;
}
/**
* @param array $data
*
* @return array
*/
public static function selectIntegrationDeliveries(array $data): array
{
$result = [];
foreach ($data as $elem) {
if (!empty($elem['integrationCode'])) {
$result[$elem['code']] = $elem['integrationCode'];
}
}
return $result;
}
/**
* @param array $data
*
* @return array
*/
public static function selectIntegrationPayments(array $data): array
{
$result = [];
foreach ($data as $elem) {
if (!empty($elem['integrationModule'])) {
$result[] = $elem['code'];
}
}
return $result;
}
/**
* @param int|null $paySystemId
*
* @return bool
*/
public static function isIntegrationPayment(?int $paySystemId): bool {
return in_array(
RetailcrmConfigProvider::getPaymentTypes()[$paySystemId] ?? null,
RetailcrmConfigProvider::getIntegrationPaymentTypes(),
true
);
}
/**
* @param array|null $availableSites
* @param array|null $types
*
* @return array
*/
public static function getAvailableTypes(?array $availableSites, ?array $types)
{
$result = [];
foreach ($types as $type) {
if ($type['active'] !== true) {
continue;
}
if (empty($type['sites'])) {
$result[$type['code']] = $type;
} else {
foreach ($type['sites'] as $site) {
if (!empty($availableSites[$site])) {
$result[$type['code']] = $type;
break;
}
}
}
}
return $result;
}
/**
* @param array $arFields
* @return void
*/
public static function writeLogsSubscribe(array $arFields): void
{
if (array_key_exists('UF_SUBSCRIBE_USER_EMAIL', $arFields)) {
$actionSub = GetMessage('SUBSCRIBED_USER');
$fileSub = 'subscribe';
if (empty($arFields['UF_SUBSCRIBE_USER_EMAIL'])) {
$actionSub = GetMessage('UNSUBSCRIBED_USER');
$fileSub = 'unSubscribe';
}
$id = $arFields['ID'] ?? $arFields['USER_ID'];
Logger::getInstance()->write(
$actionSub . ' (' . $id . ')',
$fileSub
);
}
}
/**
* @param array $crmPayment
* @param array $bitrixPayment
* @param array $optionsPaymentTypes
* @return array mixed
*/
public static function preparePayment($crmPayment, $bitrixPayment, $optionsPaymentTypes)
{
$isIntegrationPayment = self::isIntegrationPayment($bitrixPayment['PAY_SYSTEM_ID'] ?? null);
if ($isIntegrationPayment && RetailcrmConfigProvider::getSyncIntegrationPayment() === 'Y') {
$crmPayment['type'] = $optionsPaymentTypes[$bitrixPayment['PAY_SYSTEM_ID']] .
Constants::CRM_PART_SUBSTITUTED_PAYMENT_CODE;
} else {
$crmPayment['type'] = $optionsPaymentTypes[$bitrixPayment['PAY_SYSTEM_ID']];
if ($isIntegrationPayment) {
unset($crmPayment['paidAt'], $crmPayment['status']);
}
}
return $crmPayment;
}
}

View file

@ -0,0 +1,101 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\Ua
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
* Class RetailCrmUa
*
* @category RetailCRM
* @package RetailCRM\Ua
*/
class RetailCrmUa
{
public static $MODULE_ID = 'intaro.retailcrm';
public static $CRM_UA = 'ua';
public static $CRM_UA_KEYS = 'ua_keys';
public static function add()
{
$ua = COption::GetOptionString(self::$MODULE_ID, self::$CRM_UA, 0);
$uaKeys = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_UA_KEYS, 0));
$request = \Bitrix\Main\Context::getCurrent()->getRequest();
if ($ua === 'Y' && !empty($uaKeys[SITE_ID]['ID']) && !empty($uaKeys[SITE_ID]['INDEX']) && $request->isAdminSection() !== true) {
global $APPLICATION;
$ua = "
<script type=\"text/javascript\">
(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');
</script>";
/**
* В $_GET['ORDER_ID'] содержится номер заказа, а не его ID.
* Номер может совпадать с ID заказа, но это необязательное условие,
* то есть они могут отличаться.
*/
if (isset($_GET['ORDER_ID'])) {
CModule::IncludeModule("sale");
$order = \Bitrix\Sale\Order::loadByAccountNumber($_GET['ORDER_ID']);
if ($order instanceof \Bitrix\Sale\Order) {
$arOrder = array(
'ID' => $order->getId(),
'PRICE' => $order->getPrice(),
'DISCOUNT_VALUE' => $order->getField('DISCOUNT_VALUE')
);
$ua .= "<script type=\"text/javascript\">
ga('require', 'ecommerce', 'ecommerce.js');
ga('ecommerce:addTransaction', {
'id': $arOrder[ID],
'affiliation': '$_SERVER[SERVER_NAME]',
'revenue': $arOrder[PRICE],
'tax': $arOrder[DISCOUNT_VALUE]
});
";
$arBasketItems = CsaleBasket::GetList(
array('id' => 'asc'),
array('ORDER_ID' => $_GET['ORDER_ID']),
false,
false,
array('PRODUCT_ID', 'NAME', 'PRICE', 'QUANTITY', 'ORDER_ID', 'ID')
);
while ($arItem = $arBasketItems->fetch()) {
$ua .= "
ga('ecommerce:addItem', {
'id': $arOrder[ID],
'sku': '$arItem[PRODUCT_ID]',
'name': '$arItem[NAME]',
'price': $arItem[PRICE],
'quantity': $arItem[QUANTITY]
});
";
}
$ua .= "ga('ecommerce:send');";
$ua .= "</script>";
}
}
$APPLICATION->AddHeadString($ua);
}
}
}

View file

@ -0,0 +1,234 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\User
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
use Bitrix\Main\UserTable;
use RetailCrm\ApiClient;
use RetailCrm\Response\ApiResponse;
IncludeModuleLangFile(__FILE__);
/**
* Class RetailCrmCorporateClient
*
* @category RetailCRM
* @package RetailCRM\User
*/
class RetailCrmCorporateClient
{
const CORP_PREFIX = 'corp';
public static function clientSend($arOrder, $api, $contragentType, $send = false, $fillCorp = false, $site = null)
{
if (!$api || empty($contragentType)) {
return false;
}
$address = array();
$contragent = array();
$shops = RetailcrmConfigProvider::getSitesListCorporate();
$optionsLegalDetails = RetailcrmConfigProvider::getLegalDetails();
$arUser = UserTable::getById($arOrder['USER_ID'])->fetch();
if (count($shops) == 0) {
RCrmActions::eventLog('RetailCrmCorporateClient::clientSend()', '$shops', 'No stores selected for download');
return false;
}
foreach ($arOrder['PROPS']['properties'] as $prop) {
if ($prop['CODE'] == RetailcrmConfigProvider::getCorporateClientName()) {
$nickName = $prop['VALUE'][0];
}
if ($prop['CODE'] == RetailcrmConfigProvider::getCorporateClientAddress()) {
$address = $prop['VALUE'][0];
}
if (!empty($optionsLegalDetails)
&& $search = array_search($prop['CODE'], $optionsLegalDetails[$arOrder['PERSON_TYPE_ID']])
) {
$contragent[$search] = $prop['VALUE'][0];//legal order data
}
}
if (empty($nickName)) {
$nickName = $arUser['WORK_COMPANY'];
}
if (!empty($contragentType)) {
$contragent['contragentType'] = $contragentType;
}
foreach ($shops as $shop) {
$customerCorporate = [
'createdAt' => $arOrder['DATE_INSERT'],
"nickName" => $nickName,
];
if ($fillCorp) {
$customerCorporate = array_merge(
$customerCorporate,
[
'customerContacts' => [
[
'isMain' => true,
'customer' => [
'externalId' => $arUser['ID'],
'site' => $shop,
],
],
],
'companies' => [
[
'name' => $nickName,
'isMain' => true,
],
],
'addresses' => [
[
'name' => $nickName,
'isMain' => true,
'text' => $address,
],
],
]
);
}
}
if (isset($customerCorporate)) {
if ($send && isset($_COOKIE['_rc']) && $_COOKIE['_rc'] != '') {
$customerCorporate['browserId'] = $_COOKIE['_rc'];
}
$normalizer = new RestNormalizer();
$customerCorporate = $normalizer->normalize($customerCorporate, 'customerCorporate');
Logger::getInstance()->write($customerCorporate, 'clientCorporate');
if ($send) {
$result = RCrmActions::apiMethod($api, 'customersCorporateCreate', __METHOD__, $customerCorporate, $site);
if (!$result) {
return false;
}
$customerCorporate['id'] = $result['id'];
}
return $customerCorporate;
}
return array();
}
public static function addCustomersCorporateAddresses($customeId, $legalName, $adress, $api, $site)
{
$found = false;
$addresses = $api->customersCorporateAddresses(
$customeId,
array(),
null,
100,
'id',
$site
);
if ($addresses && $addresses->isSuccessful() && $addresses->offsetExists('addresses')) {
foreach ($addresses['addresses'] as $corpAddress) {
if (isset($corpAddress['text']) && $corpAddress['text'] == $adress) {
$found = true;
break;
}
}
if (!$found) {
$customerCorporateAddress = array(
'name' => $legalName,
'text' => $adress
);
$addressResult = $api->customersCorporateAddressesCreate(
$customeId,
$customerCorporateAddress,
'id',
$site
);
if (!$addressResult || ($addressResult && !$addressResult->isSuccessful())) {
Logger::getInstance()->write(sprintf(
'error while trying to append address to corporate customer%s%s',
PHP_EOL,
print_r(array(
'address' => $customerCorporateAddress,
'customer' => $customeId
), true)
), 'apiErrors');
}
}
}
}
/**
* Проверяет, существует ли корпоративный клиент с указанным externalId
*
* @param string $bitrixUserId
* @param \RetailCrm\ApiClient $api
*
* @return bool
*/
public static function isCorpTookExternalId(string $bitrixUserId, ApiClient $api, $site = null): bool
{
$response = RCrmActions::apiMethod(
$api,
'customersCorporateGet',
__METHOD__,
$bitrixUserId,
$site
);
if (false === $response) {
return false;
}
if ($response instanceof ApiResponse && $response->offsetGet('customerCorporate')) {
return true;
}
return false;
}
/**
* @param string $externalId
* @param \RetailCrm\ApiClient $api
*/
public static function setPrefixForExternalId(string $externalId, ApiClient $api, $site = null)
{
$response = RCrmActions::apiMethod(
$api,
'customersCorporateEdit',
__METHOD__,
[
'urlId' => $externalId,
'externalId' => self::CORP_PREFIX . $externalId
],
$site
);
if (false === $response) {
Logger::getInstance()->write(
sprintf('Не удалось добавить префикс для корпоративного клиента %s', $externalId),
'clientCorporate'
);
}
}
}

View file

@ -0,0 +1,267 @@
<?php
/**
* @category RetailCRM
* @package RetailCRM\User
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
IncludeModuleLangFile(__FILE__);
use Bitrix\Main\UserTable;
/**
* Class RetailCrmUser
*
* @category RetailCRM
* @package RetailCRM\User
*/
class RetailCrmUser
{
/**
* @param array $arFields
* @param $api
* @param $contragentType
* @param false $send
* @param null $site
*
* @return array|false
* @throws \Exception
*/
public static function customerSend(array $arFields, $api, $contragentType, bool $send = false, $site = null)
{
if (!$api || empty($contragentType)) {
return false;
}
if (empty($arFields)) {
RCrmActions::eventLog('RetailCrmUser::customerSend', 'empty($arFields)', 'incorrect customer');
return false;
}
$customer = self::getSimpleCustomer($arFields);
$customer['createdAt'] = new \DateTime($arFields['DATE_REGISTER']);
$customer['contragent'] = ['contragentType' => $contragentType];
if (RetailcrmConfigProvider::getCustomFieldsStatus() === 'Y') {
$customer['customFields'] = self::getCustomFields($arFields);
}
if ($send && isset($_COOKIE['_rc']) && $_COOKIE['_rc'] != '') {
$customer['browserId'] = $_COOKIE['_rc'];
}
if (function_exists('retailCrmBeforeCustomerSend')) {
$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;
}
}
$normalizer = new RestNormalizer();
$customer = $normalizer->normalize($customer, 'customers');
if (array_key_exists('UF_SUBSCRIBE_USER_EMAIL', $arFields)) {
// UF_SUBSCRIBE_USER_EMAIL = '1' or '0'
$customer['subscribed'] = (bool) $arFields['UF_SUBSCRIBE_USER_EMAIL'];
}
Logger::getInstance()->write($customer, 'customerSend');
if (
$send
&& !RCrmActions::apiMethod($api, 'customersCreate', __METHOD__, $customer, $site)
) {
return false;
}
return $customer;
}
public static function customerEdit($arFields, $api, $optionsSitesList = array()) : bool
{
if (empty($arFields)) {
RCrmActions::eventLog('RetailCrmUser::customerEdit', 'empty($arFields)', 'incorrect customer');
return false;
}
$customer = self::getSimpleCustomer($arFields);
$found = false;
if (RetailcrmConfigProvider::getCustomFieldsStatus() === 'Y') {
$customer['customFields'] = self::getCustomFields($arFields);
}
if (count($optionsSitesList) > 0) {
foreach ($optionsSitesList as $site) {
$userCrm = RCrmActions::apiMethod($api, 'customersGet', __METHOD__, $arFields['ID'], $site);
if (isset($userCrm['customer'])) {
$found = true;
break;
}
}
} else {
$site = null;
$userCrm = RCrmActions::apiMethod($api, 'customersGet', __METHOD__, $arFields['ID'], $site);
if (isset($userCrm['customer'])) {
$found = true;
}
}
if ($found) {
$normalizer = new RestNormalizer();
$customer = $normalizer->normalize($customer, 'customers');
$customer = self::getBooleanFields($customer, $arFields);
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;
}
}
Logger::getInstance()->write($customer, 'customerSend');
RCrmActions::apiMethod($api, 'customersEdit', __METHOD__, $customer, $site);
}
return true;
}
/**
* @param array $arFields
*
* @return array
*/
private static function getSimpleCustomer(array $arFields): array
{
$customer['externalId'] = $arFields['ID'];
$customer['firstName'] = $arFields['NAME'] ?? null;
$customer['lastName'] = $arFields['LAST_NAME'] ?? null;
$customer['patronymic'] = $arFields['SECOND_NAME'] ?? null;
$customer['phones'][]['number'] = $arFields['PERSONAL_PHONE'] ?? null;
$customer['phones'][]['number'] = $arFields['WORK_PHONE'] ?? null;
$customer['address']['city'] = $arFields['PERSONAL_CITY'] ?? null;
$customer['address']['text'] = $arFields['PERSONAL_STREET'] ?? null;
$customer['address']['index'] = $arFields['PERSONAL_ZIP'] ?? null;
if (mb_strlen($arFields['EMAIL']) < 100) {
$customer['email'] = $arFields['EMAIL'];
}
return $customer;
}
private static function getBooleanFields($customer, $arFields)
{
if (isset($arFields['UF_SUBSCRIBE_USER_EMAIL'])) {
if ($arFields['UF_SUBSCRIBE_USER_EMAIL'] === "1") {
$customer['subscribed'] = true;
} else {
$customer['subscribed'] = false;
}
}
return $customer;
}
private static function getCustomFields(array $arFields)
{
if (!method_exists(RCrmActions::class, 'getTypeUserField')
|| !method_exists(RCrmActions::class, 'convertCmsFieldToCrmValue')
) {
return [];
}
$customUserFields = RetailcrmConfigProvider::getMatchedUserFields();
$typeList = RCrmActions::getTypeUserField();
$result = [];
foreach ($customUserFields as $code => $codeCrm) {
if (isset($arFields[$code])) {
$type = $typeList[$code] ?? '';
$result[$codeCrm] = RCrmActions::convertCmsFieldToCrmValue($arFields[$code], $type);
}
}
return $result;
}
public static function fixDateCustomer(): void
{
CAgent::RemoveAgent("RetailCrmUser::fixDateCustomer();", RetailcrmConstants::MODULE_ID);
COption::SetOptionString(RetailcrmConstants::MODULE_ID, RetailcrmConstants::OPTION_FIX_DATE_CUSTOMER, 'Y');
$startId = COption::GetOptionInt(RetailcrmConstants::MODULE_ID, RetailcrmConstants::OPTION_FIX_DATE_CUSTOMER_LAST_ID, 0);
$api = new RetailCrm\ApiClient(RetailcrmConfigProvider::getApiUrl(), RetailcrmConfigProvider::getApiKey());
$optionsSitesList = RetailcrmConfigProvider::getSitesList();
$limit = 50;
$offset = 0;
while(true) {
try {
$usersResult = UserTable::getList([
'select' => ['ID', 'DATE_REGISTER', 'LID'],
'filter' => ['>ID' => $startId],
'order' => ['ID'],
'limit' => $limit,
'offset' => $offset,
]);
} catch (\Throwable $exception) {
Logger::getInstance()->write($exception->getMessage(), 'fixDateCustomers');
break;
}
$users = $usersResult->fetchAll();
if ($users === []) {
break;
}
foreach ($users as $user) {
$site = null;
if ($optionsSitesList) {
if (isset($user['LID']) && array_key_exists($user['LID'], $optionsSitesList) && $optionsSitesList[$user['LID']] !== null) {
$site = $optionsSitesList[$user['LID']];
} else {
continue;
}
}
$customer['externalId'] = $user['ID'];
try {
$date = new \DateTime($user['DATE_REGISTER']);
$customer['createdAt'] = $date->format('Y-m-d H:i:s');
RCrmActions::apiMethod($api, 'customersEdit', __METHOD__, $customer, $site);
} catch (\Throwable $exception) {
Logger::getInstance()->write($exception->getMessage(), 'fixDateCustomers');
continue;
}
time_nanosleep(0, 250000000);
}
COption::SetOptionInt(RetailcrmConstants::MODULE_ID, RetailcrmConstants::OPTION_FIX_DATE_CUSTOMER_LAST_ID, end($users)['ID']);
$offset += $limit;
}
}
}

View file

@ -0,0 +1 @@
- Исправлена передача габаритов при выгрузке заказов по агенту

View file

@ -0,0 +1,163 @@
<?php
use Bitrix\Highloadblock\HighloadBlockTable;
use Intaro\RetailCrm\Icml\IcmlDirector;
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup;
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetupProps;
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetupPropsCategories;
use Intaro\RetailCrm\Repository\CatalogRepository;
use Intaro\RetailCrm\Icml\SettingsService;
/** @var $SETUP_FILE_NAME */
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/bitrix/php_interface/retailcrm/export_run.php')) {
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/php_interface/retailcrm/export_run.php');
} else {
ignore_user_abort(true);
set_time_limit(0);
global $APPLICATION;
if (
!CModule::IncludeModule('iblock')
|| !CModule::IncludeModule('catalog')
|| !CModule::IncludeModule('intaro.retailcrm')
) {
return;
}
$hlblockModule = false;
if (CModule::IncludeModule('highloadblock')) {
$hlblockModule = true;
$hlblockList = [];
$hlblockListDb = HighloadBlockTable::getList();
while ($hlblockArr = $hlblockListDb->Fetch()) {
$hlblockList[$hlblockArr["TABLE_NAME"]] = $hlblockArr;
}
}
global $PROFILE_ID;
$settingService = SettingsService::getInstance([], '', $PROFILE_ID ?? $profile_id);
$iblockPropertySku = [];
$iblockPropertySkuHl = [];
$iblockPropertyUnitSku = [];
$iblockPropertyProduct = [];
$iblockPropertyProductHl = [];
$iblockPropertyUnitProduct = [];
foreach (array_keys($settingService->actualPropList) as $prop) {
$skuUnitProps = ('iblockPropertyUnitSku_' . $prop);
$skuUnitProps = $$skuUnitProps;
if (is_array($skuUnitProps)) {
foreach ($skuUnitProps as $iblock => $val) {
$iblockPropertyUnitSku[$iblock][$prop] = $val;
}
}
$skuProps = ('iblockPropertySku_' . $prop);
$skuProps = $$skuProps;
if (is_array($skuProps)) {
foreach ($skuProps as $iblock => $val) {
$iblockPropertySku[$iblock][$prop] = $val;
}
}
if ($hlblockModule === true) {
foreach ($hlblockList as $hlblockTable => $hlblock) {
$hbProps = ('highloadblock' . $hlblockTable . '_' . $prop);
$hbProps = $$hbProps;
if (is_array($hbProps)) {
foreach ($hbProps as $iblock => $val) {
$iblockPropertySkuHl[$hlblockTable][$iblock][$prop] = $val;
}
}
}
}
$productUnitProps = 'iblockPropertyUnitProduct_' . $prop;
$productUnitProps = $$productUnitProps;
if (is_array($productUnitProps)) {
foreach ($productUnitProps as $iblock => $val) {
$iblockPropertyUnitProduct[$iblock][$prop] = $val;
}
}
$productProps = "iblockPropertyProduct_" . $prop;
$productProps = $$productProps;
if (is_array($productProps)) {
foreach ($productProps as $iblock => $val) {
$iblockPropertyProduct[$iblock][$prop] = $val;
}
}
if ($hlblockModule === true) {
foreach ($hlblockList as $hlblockTable => $hlblock) {
$hbProps = ('highloadblock_product' . $hlblockTable . '_' . $prop);
$hbProps = $$hbProps;
if (is_array($hbProps)) {
foreach ($hbProps as $iblock => $val) {
$iblockPropertyProductHl[$hlblockTable][$iblock][$prop] = $val;
}
}
}
}
}
$productPictures = [];
if (is_array($iblockPropertyProduct_picture)) {
foreach ($iblockPropertyProduct_picture as $key => $value) {
$productPictures[$key] = $value;
}
}
$skuPictures = [];
if (is_array($iblockPropertySku_picture)) {
foreach ($iblockPropertySku_picture as $key => $value) {
$skuPictures[$key] = $value;
}
}
$xmlProps = new XmlSetupPropsCategories(
new XmlSetupProps($iblockPropertyProduct, $iblockPropertyUnitProduct, $productPictures),
new XmlSetupProps($iblockPropertySku, $iblockPropertyUnitSku, $skuPictures)
);
if ($hlblockModule === true) {
$xmlProps->highloadblockSku = $iblockPropertySkuHl;
$xmlProps->highloadblockProduct = $iblockPropertyProductHl;
}
$logger = Logger::getInstance('/bitrix/catalog_export/');
if (!file_exists(dirname($SETUP_FILE_NAME))) {
$SETUP_FILE_NAME = $_SERVER['DOCUMENT_ROOT'] . $SETUP_FILE_NAME;
if (!file_exists(dirname($SETUP_FILE_NAME))) {
$logger->write(GetMessage('TARGET_DIR_DOESNT_EXIST'), 'i_crm_load_log');
return;
}
}
$fileSetup = new XmlSetup($xmlProps);
$fileSetup->profileId = $profile_id;
$fileSetup->iblocksForExport = $iblockExport;
$fileSetup->maxOffersValue = $maxOffersValue ?? null;
$fileSetup->filePath = $SETUP_FILE_NAME;
$fileSetup->loadPurchasePrice = $loadPurchasePrice === 'Y';
$fileSetup->loadNonActivity = $loadNonActivity === 'Y';
$fileSetup->basePriceId = CatalogRepository::getBasePriceId($fileSetup->profileId);
if (!is_array($fileSetup->iblocksForExport) || count($fileSetup->iblocksForExport) === 0) {
$logger->write(GetMessage("IBLOCK_NOT_SELECTED"), 'i_crm_load_log');
} else {
$loader = new IcmlDirector($fileSetup, $logger);
$loader->generateXml();
}
}

View file

@ -0,0 +1,984 @@
<?php
use Intaro\RetailCrm\Icml\SettingsService;
CModule::IncludeModule('intaro.retailcrm');
/**
* Документация по шаблонам экспорта:
* @link https://dev.1c-bitrix.ru/api_help/catalog/templates.php
*
* Предопределенные переменные:
*
* Ранее сохраненные настройки экспорта из SETUP_VARS b_catalog_export
* @var $arOldSetupVars
*
* @var $APPLICATION
* @var $ACTION
*
* 1 - вывод настроек, 2 - сохранение формы с настройками
* @var $STEP
* @var $PROFILE_ID
* @var $SETUP_FILE_NAME
* @var $SETUP_PROFILE_NAME
*/
//TODO заменить вызов на сервис-локатор, когда он приедет
$settingsService = SettingsService::getInstance(
$arOldSetupVars ?? [],
$ACTION,
$PROFILE_ID
);
$isSetupModulePage = $settingsService->isSetupModulePage();
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/bitrix/php_interface/retailcrm/export_setup.php')) {
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/php_interface/retailcrm/export_setup.php');
return;
}
if (!check_bitrix_sessid()) {
return;
}
__IncludeLang(GetLangFileName(
$_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/intaro.retailcrm/lang/',
'/icml_export_setup.php')
);
$basePriceId = RetailcrmConfigProvider::getCrmBasePrice($_REQUEST['PROFILE_ID']);
$priceTypes = $settingsService->priceTypes;
$iblockFieldsName = $settingsService->getIblockFieldsNames();
$units = $settingsService->getUnitsNames();
$hintUnit = $settingsService->getHintUnit();
//highloadblock
if (CModule::IncludeModule('highloadblock')) {
$hlblockModule = true;
$hlBlockList = $settingsService->getHlBlockList();
}
if (($ACTION === 'EXPORT' || $ACTION === 'EXPORT_EDIT' || $ACTION === 'EXPORT_COPY') && $STEP === 1) {
$SETUP_FILE_NAME = $settingsService->setupFileName;
$SETUP_PROFILE_NAME = $settingsService->setupProfileName;
$loadPurchasePrice = $settingsService->loadPurchasePrice;
$iblockExport = $settingsService->iblockExport;
$loadNonActivity = $settingsService->loadNonActivity;
if ($iblockExport) {
$maxOffersValue = $settingsService->getSingleSetting('maxOffersValue');
}
$settingsService->setProps();
$iblockPropertySku = $settingsService->iblockPropertySku;
$iblockPropertyUnitSku = $settingsService->iblockPropertyUnitSku;
$iblockPropertyProduct = $settingsService->iblockPropertyProduct;
$iblockPropertyUnitProduct = $settingsService->iblockPropertyUnitProduct;
$boolAll = false;
$intCountChecked = 0;
$intCountAvailIBlock = 0;
}
if (!isset($iblockExport) || !is_array($iblockExport)) {
$iblockExport = [];
}
[$arIBlockList, $intCountChecked, $intCountAvailIBlock, $isExportIblock]
= $settingsService->getSettingsForIblocks();
if (count($iblockExport) !== 0) {
if ($intCountChecked === $intCountAvailIBlock) {
$boolAll = true;
}
} else {
$intCountChecked = $intCountAvailIBlock;
$boolAll = true;
}
//Проверка на ошибки
$STEP = $settingsService->returnIfErrors($STEP, $SETUP_FILE_NAME, $SETUP_PROFILE_NAME);
//Отображение формы
if ($STEP === 1) {
?>
<style>
.iblock-export-table-display-none {
display: none;
}
</style>
<form method="post" id="submit-form" action="<?=$APPLICATION->GetCurPage()?>">
<?php
if ($ACTION === 'EXPORT_EDIT' || $ACTION === 'EXPORT_COPY') {
?>
<input type="hidden" name="PROFILE_ID" value="<?=(int)$PROFILE_ID?>">
<?php
}
?>
<h3><?=GetMessage('SETTINGS_INFOBLOCK')?></h3>
<span class="text"><?=GetMessage('EXPORT_CATALOGS');?><br><br></span>
<span class="text" style="font-weight: bold;"><?=GetMessage('CHECK_ALL_INFOBLOCKS')?></span>
<input
style="vertical-align: middle;"
type="checkbox"
name="icml_export_all"
id="icml_export_all"
value="Y"
onclick="checkAll(this,<?=$intCountAvailIBlock?>);"
<?=($boolAll ? ' checked' : '')?>>
</br>
</br>
<div>
<?php
$checkBoxCounter = 0;
//Перебираем все торговые каталоги, формируя для каждого таблицу настроек
foreach ($arIBlockList as $arIBlock) {
?>
<div>
<div>
<span class="text" style="font-weight: bold;">
<?= htmlspecialcharsex('['
. $arIBlock['IBLOCK_TYPE_ID']
. '] '
. $arIBlock['NAME']
. ' '
. $arIBlock['SITE_LIST']) ?>
</span>
<input
type="checkbox"
name="iblockExport[<?=$arIBlock['ID']?>]"
id="iblockExport<?=++$checkBoxCounter?>"
value="<?=$arIBlock['ID']?>"
<?php
if ($arIBlock['iblockExport']) {
echo ' checked';
} ?>
onclick="checkOne(this,<?=$intCountAvailIBlock?>);"
>
</div>
<br>
<div id="iblockExportTable<?=$checkBoxCounter?>" class="iblockExportTable"
data-type="<?=$arIBlock['ID']?>">
<table class="adm-list-table" id="export_setup"
<?=($arIBlock['PROPERTIES_SKU'] === null ? 'style="width: 66%;"' : '')?>
>
<thead>
<tr class="adm-list-table-header">
<td class="adm-list-table-cell">
<div class="adm-list-table-cell-inner"><?=GetMessage('LOADED_PROPERTY');?></div>
</td>
<td class="adm-list-table-cell">
<div class="adm-list-table-cell-inner">
<?=GetMessage('PROPERTY_PRODUCT_HEADER_NAME')?>
</div>
</td>
<?php
if ($arIBlock['PROPERTIES_SKU'] !== null) {?>
<td class="adm-list-table-cell">
<div class="adm-list-table-cell-inner">
<?=GetMessage('PROPERTY_OFFER_HEADER_NAME');?>
</div>
</td>
<?php
} ?>
</tr>
</thead>
<tbody>
<?php
foreach ($settingsService->defaultPropList as $propertyKey => $property) { ?>
<tr class="adm-list-table-row">
<td class="adm-list-table-cell">
<?=htmlspecialcharsex($property)?>
</td>
<td class="adm-list-table-cell">
<select
style="width: 200px;"
id="iblockPropertyProduct_<?=$propertyKey . $arIBlock['ID']?>"
name="iblockPropertyProduct_<?=$propertyKey?>[<?=$arIBlock['ID']?>]"
class="property-export"
data-type="<?=$propertyKey?>"
onchange="propertyChange(this);">
<option value=""></option>
<?php
if ($settingsService->isOptionHasPreset($propertyKey)) {
?>
<optgroup label="<?=GetMessage('SELECT_FIELD_NAME')?>">
<?php
foreach ($iblockFieldsName as $keyField => $field) {
if ($keyField === $propertyKey) { ?>
<option value="<?=$field['CODE']?>"
<?php
$isSelected = $settingsService->isOptionSelected(
$field,
$arIBlock['OLD_PROPERTY_PRODUCT_SELECT'],
$propertyKey
);
?>
<?= $isSelected ? ' selected' : ''?>
>
<?=$field['name']?>
</option>
<?php
}
} ?>
</optgroup>
<optgroup label="<?=GetMessage('SELECT_PROPERTY_NAME')?>">
<?php
}
$productHlTableName = '';
foreach ($arIBlock['PROPERTIES_PRODUCT'] as $prop) { ?>
<option value="<?=$prop['CODE']?>"
<?php
echo $settingsService->getOptionClass($prop, true);
$isSelected = $settingsService->isOptionSelected(
$prop,
$arIBlock['OLD_PROPERTY_PRODUCT_SELECT'],
$propertyKey
);
$productHlTableName
= $settingsService->getHlTableName($prop)
?? $productHlTableName;
echo $isSelected ? ' selected' : '';
?>
>
<?=$prop['NAME']?>
</option>
<?php
}
if ($settingsService->isOptionHasPreset($propertyKey)) {
?>
</optgroup>
<?php
} ?>
</select>
<?php
if ($settingsService->isHlSelected(
$propertyKey,
$arIBlock['ID'],
$productHlTableName,
'_product'
)
) {?>
<select name="highloadblock_product<?=$productHlTableName . '_' .
$propertyKey . '[' . $arIBlock['ID'] . ']' ?>" id="highloadblock"
style="width: 100px; margin-left: 50px;">
<?php
foreach ($hlBlockList[$productHlTableName]['FIELDS'] as $field) {
?>
<option value="<?=$field?>"
<?= $settingsService->getHlOptionStatus(
$productHlTableName,
$propertyKey,
$arIBlock['ID'],
(string) $field,
'highloadblock_product'
) ?>
>
<?=$field?>
</option>
<?php
} ?>
</select>
<?php
}
//Единицы измерения для товаров
if (array_key_exists($propertyKey, $iblockFieldsName)) :?>
<select
style="width: 100px; margin-left: 50px;"
id="iblockPropertyUnitProduct_<?=$propertyKey . $arIBlock['ID']?>"
name="iblockPropertyUnitProduct_<?=$propertyKey?>[<?=$arIBlock['ID']?>]"
>
<?php
foreach ($units as $unitTypeName => $unitType) { ?>
<?php
if ($unitTypeName == $iblockFieldsName[$propertyKey]['unit']): ?>
<?php
foreach ($unitType as $keyUnit => $unit): ?>
<option value="<?=$keyUnit?>"
<?=$settingsService->getUnitOptionStatus(
$arIBlock['OLD_PROPERTY_UNIT_PRODUCT_SELECT'],
$keyUnit,
$propertyKey,
(string) $unitTypeName
)
?>
>
<?=$unit?>
</option>
<?php
endforeach; ?>
<?php
endif; ?>
<?php
} ?>
</select>
<?php
endif; ?>
</td>
<?php
//Столбец со свойствами тороговых предложений
if ($arIBlock['PROPERTIES_SKU'] !== null) {?>
<td class="adm-list-table-cell">
<select
style="width: 200px;"
id="iblockPropertySku_<?=$propertyKey?><?=$arIBlock['ID']?>"
name="iblockPropertySku_<?=$propertyKey?>[<?=$arIBlock['ID']?>]"
class="property-export"
data-type="<?=$propertyKey?>"
onchange="propertyChange(this);">
<option value=""></option>
<?php
if ($settingsService->isOptionHasPreset($propertyKey)) {
?>
<optgroup label="<?=GetMessage('SELECT_FIELD_NAME');?>">
<?php
foreach ($iblockFieldsName as $keyField => $field) {
if ($keyField === $propertyKey) :?>
<option value="<?=$field['CODE']?>"
<?php
$isSelected = $settingsService->isOptionSelected(
$field,
$arIBlock['OLD_PROPERTY_SKU_SELECT'],
$propertyKey
);
echo $isSelected ? ' selected' : '';
?>
>
<?=$field['name']?>
</option>
<?php
endif;
} ?>
</optgroup>
<optgroup label="<?=GetMessage('SELECT_PROPERTY_NAME');?>">
<?php
}
$skuHlTableName = '';
foreach ($arIBlock['PROPERTIES_SKU'] as $prop) { ?>
<option value="<?=$prop['CODE']?>"
<?php
echo $settingsService->getOptionClass($prop, false);
$isSelected = $settingsService->isOptionSelected(
$prop,
$arIBlock['OLD_PROPERTY_SKU_SELECT'],
$propertyKey
);
$skuHlTableName
= $settingsService->getHlTableName($prop)
?? $skuHlTableName;
echo $isSelected ? ' selected' : '';
?>
>
<?=$prop['NAME']?>
</option>
<?php
}
if ($settingsService->isOptionHasPreset($propertyKey)) {
?>
</optgroup>
<?php
} ?>
</select>
<?php
if (
$settingsService->isHlSelected(
$propertyKey,
$arIBlock['ID'],
$skuHlTableName
)
) { ?>
<select
name="highloadblock<?=$skuHlTableName . '_' . $propertyKey . '['
. $arIBlock['ID'] . ']'?>"
id="highloadblock"
style="width: 100px;
margin-left: 50px;"
>
<?php
foreach ($hlBlockList[$skuHlTableName]['FIELDS'] as $field)
: ?>
<option value="<?=$field?>"
<?=
$settingsService->getHlOptionStatus(
$skuHlTableName,
$propertyKey,
$arIBlock['ID'],
(string) $field,
'highloadblock'
)?>
>
<?=$field?>
</option>
<?php
endforeach; ?>
</select>
<?php
}
if (array_key_exists($propertyKey, $iblockFieldsName)) {?>
<select
style="width: 100px; margin-left: 50px;"
id="iblockPropertyUnitSku_<?=$propertyKey?><?=$arIBlock['ID']?>"
name="iblockPropertyUnitSku_<?=$propertyKey?>[<?=$arIBlock['ID']?>]"
>
<?php
foreach ($units as $unitTypeName => $unitType) {
if ($unitTypeName == $iblockFieldsName[$propertyKey]['unit']) {
foreach ($unitType as $keyUnit => $unit) { ?>
<option value="<?=$keyUnit?>"
<?php
echo $settingsService->getUnitOptionStatus(
$arIBlock['OLD_PROPERTY_UNIT_SKU_SELECT'],
$keyUnit,
$propertyKey,
$unitTypeName
);
?>
>
<?=$unit?>
</option>
<?php
}
}
} ?>
</select>
<?php
} ?>
</td>
<?php
} ?>
</tr>
<?php
} ?>
<?php
$catalogId = $arIBlock['ID'];
$catalogCustomProps = $settingsService->customPropList[$catalogId];
if (!empty($catalogCustomProps)) {
foreach ($catalogCustomProps as $catalogCustomPropCode => $catalogCustomPropValue) { ?>
<tr class="adm-list-table-row custom-property-row">
<td class="adm-list-table-cell custom-property-title">
<?=htmlspecialcharsex($catalogCustomPropValue)?>
</td>
<td class="adm-list-table-cell">
<select
name="iblockPropertyProduct_<?=$catalogCustomPropCode?>[<?= $catalogId ?>]"
id="iblockPropertyProduct_<?=$catalogCustomPropCode . $catalogId ?>"
class="property-export"
data-type="<?= $catalogCustomPropCode ?>"
onchange="propertyChange(this)"
style="width: 200px">
<option value=""></option>
<?php foreach ($arIBlock['PROPERTIES_PRODUCT'] as $prop) {
$productHlTableName = ''; ?>
<option value="<?=$prop['CODE']?>"
<?php
echo $settingsService->getOptionClass($prop, true);
$isSelected = $settingsService->isOptionSelected(
$prop,
$arIBlock['OLD_PROPERTY_PRODUCT_SELECT'],
$catalogCustomPropCode
);
$productHlTableName
= $settingsService->getHlTableName($prop)
?? $productHlTableName;
echo $isSelected ? ' selected' : '';
?>
>
<?=$prop['NAME']?>
</option>
<?php } ?>
</select>
</td>
<?php if ($arIBlock['PROPERTIES_SKU'] !== null) { ?>
<td class="adm-list-table-cell">
<select
name="iblockPropertySku_<?=$catalogCustomPropCode?>[<?= $catalogId ?>]"
id="iblockPropertySku_<?=$catalogCustomPropCode . $catalogId ?>"
class="property-export"
data-type="<?= $catalogCustomPropCode ?>"
onchange="propertyChange(this)"
style="width: 200px">
<option value=""></option>
<?php foreach ($arIBlock['PROPERTIES_SKU'] as $prop) {
$skuHlTableName = ''; ?>
<option value="<?=$prop['CODE']?>"
<?php
echo $settingsService->getOptionClass($prop, false);
$isSelected = $settingsService->isOptionSelected(
$prop,
$arIBlock['OLD_PROPERTY_SKU_SELECT'],
$catalogCustomPropCode
);
$skuHlTableName
= $settingsService->getHlTableName($prop)
?? $skuHlTableName;
echo $isSelected ? ' selected' : '';
?>
>
<?=$prop['NAME']?>
</option>
<?php } ?>
</select>
<button id="delete-custom-row" class="adm-btn-save" type="button" style="margin-left: 10px"><?= GetMessage('DELETE_PROPERTY');?></button>
</td>
<?php } ?>
</tr>
<?php }
}
?>
</tbody>
</table>
<button class="adm-btn-save add-custom-row" type="button" style="margin-top: 20px;"><?= GetMessage('ADD_PROPERTY');?></button>
<br>
</div>
</div>
<?php
} ?>
</div>
<input type="hidden" name="count_checked" id="count_checked" value="<?=$intCountChecked?>">
<br>
<template id="custom-property-template-row">
<tr class="adm-list-table-row custom-property-row">
<td class="adm-list-table-cell">
<input type="text" title="Название нового свойства" name="custom-property-title" style="width: 200px">
</td>
<td class="adm-list-table-cell">
<select name="iblockPropertyProduct_" id="iblockPropertyProduct_" class="property-export" onchange="propertyChange(this)" style="width: 200px"></select>
</td>
<td class="adm-list-table-cell">
<select name="iblockPropertySku_" id="iiblockPropertySku_" class="property-export" onchange="propertyChange(this)" style="width: 200px"></select>
<button id="delete-new-custom-row" class="adm-btn-save" type="button" style="margin-left: 10px"><?= GetMessage('DELETE_PROPERTY');?></button>
</td>
</tr>
</template>
<h3><?=GetMessage('SETTINGS_EXPORT')?></h3>
<span class="text"><?=GetMessage('FILENAME')?><br><br></span>
<input type="text" name="SETUP_FILE_NAME" value="<?=htmlspecialcharsbx(strlen($SETUP_FILE_NAME) > 0 ?
$SETUP_FILE_NAME : $settingsService->setupFileName); ?>" size="50"><br><br>
<span class="text"><?=GetMessage('LOAD_PURCHASE_PRICE')?>&nbsp;</span>
<input type="checkbox" name="loadPurchasePrice" value="Y" <?=$loadPurchasePrice === 'Y' ? 'checked' : ''?>>
<br><br>
<span class="text"><?=GetMessage('LOAD_NON_ACTIVITY')?>&nbsp;</span>
<input type="checkbox" name="loadNonActivity" value="Y" <?=$loadNonActivity === 'Y' ? 'checked' : ''?>>
<br><br>
<?php
if ($isSetupModulePage) { ?>
<span class="text"><?=GetMessage('AGENT_LOADING')?>&nbsp;</span>
<input id="add-agent" type="checkbox" name="NEED_CATALOG_AGENT" value="agent"><br><br>
<span class="text" style="font-weight: bold; font-size: 14px"><?=GetMessage('LOAD_NOW')?>&nbsp;</span>
<input id="load-now" type="checkbox" onchange="checkLoadStatus(this)" name="LOAD_NOW" value="now"><br>
<br>
<div id="loadMessageNow" hidden><?=GetMessage('LOAD_NOW_MSG')?></div>
<br>
<?php
}?>
<span class="text"><?=GetMessage('BASE_PRICE')?>&nbsp;</span>
<select name="price-types" class="typeselect">
<option value=""></option>
<?php
foreach ($priceTypes as $priceType) { ?>
<option value="<?=$priceType['ID']?>" <?= $priceType['ID'] == $basePriceId ? ' selected' : ''?>>
<?=$priceType['NAME']?>
</option>
<?php
} ?>
</select><br><br><br>
<?php
if ($ACTION === 'EXPORT_SETUP' || $ACTION === 'EXPORT_EDIT' || $ACTION === 'EXPORT_COPY') { ?>
<span class="text"><?=GetMessage('OFFERS_VALUE')?><br><br></span>
<label>
<input
type="text"
name="maxOffersValue"
value="<?=htmlspecialchars($maxOffersValue)?>"
size="15">
</label><br><br><br>
<span class="text"><?=GetMessage('PROFILE_NAME')?><br><br></span>
<label>
<input
type="text"
name="SETUP_PROFILE_NAME"
value="<?=htmlspecialchars(strlen($SETUP_PROFILE_NAME) > 0 ?
$SETUP_PROFILE_NAME : $settingsService->setupProfileName)?>"
size="50">
</label><br><br><br>
<?php
}
?>
<?=bitrix_sessid_post()?>
<?php
if ($isSetupModulePage) { ?>
<input type="hidden" name="lang" value="<?= LANG; ?>">
<input type="hidden" name="id" value="intaro.retailcrm">
<input type="hidden" name="install" value="Y">
<input type="hidden" name="step" value="6">
<input type="hidden" name="continue" value="5">
<div style="padding: 1px 13px 2px; height:28px;">
<div align="right" style="float:right; width:50%; position:relative;">
<input type="submit" name="inst" onclick="BX.showWait()" value="<?= GetMessage('MOD_NEXT_STEP'); ?>"
class="adm-btn-save">
</div>
<div align="left" style="float:right; width:50%; position:relative;">
<input type="submit" name="back" value="<?= GetMessage('MOD_PREV_STEP'); ?>" class="adm-btn-save">
</div>
</div>
<?php
} else {?>
<input type="hidden" name="lang" value="<?=LANGUAGE_ID?>">
<input type="hidden" name="ACT_FILE" value="<?=htmlspecialcharsbx($_REQUEST['ACT_FILE'])?>">
<input type="hidden" name="ACTION" value="<?=htmlspecialcharsbx($ACTION)?>">
<input type="hidden" name="STEP" value="<?=$STEP + 1?>">
<input type="hidden" name="SETUP_FIELDS_LIST" value="<?=
$settingsService->getSetupFieldsString(
array_keys($settingsService->actualPropList) ?? [],
$hlblockModule === true,
$hlBlockList ?? []
)
?>">
<input type="submit" value="<?=($ACTION === 'EXPORT') ? GetMessage('EXPORT') : GetMessage('SAVE')?>">
<?php
} ?>
</form>
<?php CJSCore::Init(['jquery']);?>
<?php CUtil::InitJSCore(['intaro_custom_props']); ?>
<script type="text/javascript">
BX.ready(function() {
if (typeof createCustomPropsRaw !== 'function') {
$('.add-custom-row').hide();
}
});
$('.add-custom-row').click(function () {
if (typeof createCustomPropsRaw === 'function') {
createCustomPropsRaw($(this));
}
});
$(document).on('click', '#delete-new-custom-row', function () {
if (typeof deleteCustomPropRow === 'function') {
deleteCustomPropRow($(this));
}
});
$(document).on('click', '#delete-custom-row', function () {
let buttonElem = $(this);
if (typeof addCustomPropToDelete === 'function' && typeof deleteCustomPropRow === 'function') {
addCustomPropToDelete(buttonElem);
deleteCustomPropRow(buttonElem);
}
});
$(document).on('blur', 'input[name="custom-property-title"]', function () {
if (typeof getUniquePropertyCode === 'function' && typeof addCustomPropCodeToSelectAttributes === 'function') {
let inputElem = $(this);
let newPropertyTitle = inputElem.val();
if (!newPropertyTitle) {
return;
}
let newPropertyCode = getUniquePropertyCode(newPropertyTitle);
addCustomPropCodeToSelectAttributes(newPropertyCode, inputElem);
}
});
$('#submit-form').submit(function (formEvent) {
if (typeof setCustomProperties !== "function") {
return;
}
formEvent.preventDefault();
let savePromise = null;
let deletePromise = null;
let formElem = formEvent.currentTarget;
let profileId = $($('input[name="PROFILE_ID"]')).val();
setCustomProperties();
if (Object.keys(customProps).length > 0) {
savePromise = BX.ajax.runAction('intaro:retailcrm.api.customexportprops.save', {
json: {
properties: customProps,
profileId: profileId
},
}).then(addParamsToSetupFieldsList());
}
if (Object.keys(customPropsToDelete).length > 0) {
deletePromise = BX.ajax.runAction('intaro:retailcrm.api.customexportprops.delete', {
json: {
properties: customPropsToDelete,
profileId: profileId
},
}).then(deleteParamsFromSetupFieldsList());
}
const promises = [savePromise, deletePromise].filter(Boolean);
if (promises.length > 0) {
Promise.all(promises)
.finally(() => {
formElem.submit();
});
} else {
formElem.submit();
}
});
const setupFieldsListElement = $('input[name="SETUP_FIELDS_LIST"]');
let customProps = {};
let customPropsToDelete = {};
const setupFieldsParamsToFill = [
'iblockPropertySku_',
'iblockPropertyUnitSku_',
'iblockPropertyProduct_',
'iblockPropertyUnitProduct_',
'highloadblockb_hlsys_marking_code_group_',
'highloadblock_productb_hlsys_marking_code_group_',
'highloadblockeshop_color_reference_',
'highloadblock_producteshop_color_reference_',
'highloadblockeshop_brand_reference_',
'highloadblock_producteshop_brand_reference_'
];
function checkLoadStatus(object)
{
if (object.checked) {
$('#loadMessageNow').show();
} else {
$('#loadMessageNow').hide();
}
}
function checkAll(obj, cnt) {
for (let i = 0; i < cnt; i++) {
if (obj.checked) {
BX.removeClass('iblockExportTable' + (i + 1), "iblock-export-table-display-none");
}
}
const table = BX(obj.id.replace('iblockExport', 'iblockExportTable'));
if (obj.checked) {
BX.removeClass(table, "iblock-export-table-display-none");
}
const easing = new BX.easing({
duration: 150,
start: {opacity: obj.checked ? 0 : 100},
finish: {opacity: obj.checked ? 100 : 0},
transition: BX.easing.transitions.linear,
step: function(state) {
for (let i = 0; i < cnt; i++) {
BX('iblockExportTable' + (i + 1)).style.opacity = state.opacity / 100;
}
},
complete: function() {
for (let i = 0; i < cnt; i++) {
if (!obj.checked) {
BX.addClass('iblockExportTable' + (i + 1), "iblock-export-table-display-none");
}
}
}
});
easing.animate();
const boolCheck = obj.checked;
for (let i = 0; i < cnt; i++) {
BX('iblockExport' + (i + 1)).checked = boolCheck;
}
BX('count_checked').value = (boolCheck ? cnt : 0);
}
function checkOne(obj, cnt) {
const table = BX(obj.id.replace('iblockExport', 'iblockExportTable'));
if (obj.checked) {
BX.removeClass(table, "iblock-export-table-display-none");
}
const easing = new BX.easing({
duration: 150,
start: {opacity: obj.checked ? 0 : 100},
finish: {opacity: obj.checked ? 100 : 0},
transition: BX.easing.transitions.linear,
step: function(state) {
table.style.opacity = state.opacity / 100;
},
complete: function() {
if (!obj.checked) {
BX.addClass(table, "iblock-export-table-display-none");
}
}
});
easing.animate();
const boolCheck = obj.checked;
let intCurrent = parseInt(BX('count_checked').value);
intCurrent += (boolCheck ? 1 : -1);
BX('icml_export_all').checked = (intCurrent >= cnt);
BX('count_checked').value = intCurrent;
}
function propertyChange(obj) {
let selectedOption = $(obj).find('option')[obj.selectedIndex];
if (selectedOption.className === 'not-highloadblock') {
let objId = '#' + obj.id;
$(objId).parent().children('#highloadblock').remove();
}
if (selectedOption.className === 'highloadblock') {
getHlTablesFromController(selectedOption, 'sku', obj.getAttribute('data-type'));
}
if (selectedOption.className === 'highloadblock-product') {
getHlTablesFromController(selectedOption, 'product', obj.getAttribute('data-type'));
}
}
function setHlFieldsInInstallPage(that, type, key){
const td = $(that).parents('td .adm-list-table-cell');
const select = $(that).parent('select').siblings('#highloadblock');
const iblock = $(that).parents('.iblockExportTable').attr('data-type');
const sessid = BX.bitrix_sessid();
const table_name = $(that).attr('id');
const step = $('input[name="continue"]').val();
const id = $('input[name="id"]').val();
const install = $('input[name="install"]').val();
const data = 'install=' + install + '&step=' + step + '&sessid=' + sessid +
'&id=' + id + '&ajax=1&table=' + table_name;
$.ajax({
url: '/bitrix/admin/partner_modules.php',
type: 'POST',
data: data,
dataType: "json",
success: function(res) {
$(select).remove();
$('#waiting').remove();
let new_options = '';
$.each(res.fields, function(key, value) {
new_options += '<option value="' + value + '">' + value + '</option>';
});
if (type === 'sku') {
$(td).append(getSelect(res, key, iblock, new_options, 'highloadblock'));
}
if (type === 'product') {
$(td).append(getSelect(res, key, iblock, new_options, 'highloadblock_product'));
}
},
beforeSend: function() {
$(td).append('<span style="margin-left:50px;" id="waiting"><?=GetMessage('WAIT')?></span>');
}
});
}
function setHlFieldsInSettingsPage(that, type, key){
const td = $(that).parents('td .adm-list-table-cell');
const select = $(that).parent('select').siblings('#highloadblock');
const table_name = $(that).attr('id');
const iblock = $(that).parents('.iblockExportTable').attr('data-type');
BX.ajax.runAction('intaro:retailcrm.api.icml.getHlTable',
{
method: 'POST',
data: {
sessid: BX.bitrix_sessid(),
tableName: table_name
}
}
).then((response) => {
$(select).remove();
$('#waiting').remove();
let new_options = '';
$.each(response.data.fields, function(key, value) {
new_options += '<option value="' + value + '">' + value + '</option>';
});
let typeValue = 'highloadblock';
if (type === 'product') {
typeValue += '_product'
}
$(td).append(getSelect (response.data, key, iblock, new_options, typeValue));
}
);
}
function getHlTablesFromController(that, type, key) {
const url = $('td .adm-list-table-cell').parents('form').attr('action');
if (url === '/bitrix/admin/partner_modules.php') {
setHlFieldsInInstallPage(that, type, key);
} else {
setHlFieldsInSettingsPage(that, type, key)
}
}
function getSelect (res, key, iblock, new_options, type){
let select = document.createElement('select');
let atrName = type + res.table + '_' + key + '[' + iblock + ']';
select.setAttribute('name', atrName);
select.setAttribute('id', 'highloadblock');
select.setAttribute('style','width: 100px; margin-left: 50px;');
select.innerHTML = new_options;
return select;
}
</script>
<?php
}
//Сохранение и выход
if ($STEP === 2) {
RetailcrmConfigProvider::setProfileBasePrice($_REQUEST['PROFILE_ID'], $_POST['price-types']);
$FINITE = true;
}
?>

View file

@ -0,0 +1,72 @@
<?php
use Bitrix\Main\ArgumentOutOfRangeException;
use Bitrix\Main\Context;
use Bitrix\Main\Loader;
use Intaro\RetailCrm\Component\ConfigProvider;
use Intaro\RetailCrm\Component\Factory\ClientFactory;
use Intaro\RetailCrm\Component\ServiceLocator;
use Intaro\RetailCrm\Service\CookieService;
use Intaro\RetailCrm\Service\OrderLoyaltyDataService;
use Intaro\RetailCrm\Service\LoyaltyService;
use Intaro\RetailCrm\Service\LoyaltyAccountService;
use Intaro\RetailCrm\Service\CustomerService;
use Intaro\RetailCrm\Vendor\Doctrine\Common\Annotations\AnnotationReader;
use Intaro\RetailCrm\Vendor\Doctrine\Common\Annotations\AnnotationRegistry;
use \Intaro\RetailCrm\Component\Builder\Api\CustomerBuilder;
use RetailCrm\Exception\CurlException;
require_once __DIR__ . '/RetailcrmClasspathBuilder.php';
$retailcrmModuleId = 'intaro.retailcrm';
$server = Context::getCurrent()->getServer()->getDocumentRoot();
$version = COption::GetOptionString('intaro.retailcrm', 'api_version');
$builder = new RetailcrmClasspathBuilder();
$builder->setDisableNamespaces(true)
->setDocumentRoot($server)
->setModuleId($retailcrmModuleId)
->setDirectories(['classes', 'lib/icml'])
->setVersion($version)
->build();
Loader::registerAutoLoadClasses('intaro.retailcrm', $builder->getResult());
AnnotationRegistry::registerLoader('class_exists');
ServiceLocator::registerServices([
\Intaro\RetailCrm\Service\Utils::class,
Logger::class,
AnnotationReader::class,
CookieService::class,
LoyaltyAccountService::class,
LoyaltyService::class,
CustomerService::class,
OrderLoyaltyDataService::class,
CustomerBuilder::class
]);
$arJsConfig = [
'intaro_countdown' => [
'js' => '/bitrix/js/intaro/sms.js',
'rel' => [],
],
'intaro_custom_props' => [
'js' => '/bitrix/js/intaro/export/custom-props-export.js',
'rel' => [],
],
];
foreach ($arJsConfig as $ext => $arExt) {
CJSCore::RegisterExt($ext, $arExt);
}
if (empty(ConfigProvider::getSitesAvailable())) {
$client = ClientFactory::createClientAdapter();
try {
$credentials = $client->getCredentials();
ConfigProvider::setSitesAvailable($credentials->sitesAvailable[0] ?? '');
} catch (ArgumentOutOfRangeException | CurlException $exception) {
Logger::getInstance()->write($exception->getMessage());
}
}

View file

@ -0,0 +1,228 @@
function deleteCustomPropRow(deleteButton)
{
deleteButton.closest('tr').remove();
}
function addCustomPropToDelete(deleteButton)
{
let deletedPropTitle = deleteButton.closest('td').siblings().filter('.custom-property-title').text().trim();
let deletedPropCode = deleteButton.siblings().filter('select').first().data('type');
let customPropCatalogId = deleteButton.closest('.iblockExportTable').data('type');
let values = {
'code': deletedPropCode,
'title': deletedPropTitle,
};
if (customPropsToDelete.hasOwnProperty(customPropCatalogId)) {
customPropsToDelete[customPropCatalogId].push(values);
} else {
customPropsToDelete[customPropCatalogId] = [values];
}
}
function addCustomPropCodeToSelectAttributes(customPropCode, customPropTitleElem)
{
let selectElements = customPropTitleElem.closest('.custom-property-row').find('td select');
let catalogId = customPropTitleElem.closest('.iblockExportTable').data('type');
selectElements.each(function (index, element) {
let selectElem = $(element);
let newSelectIdValue = selectElem.attr('id').match(/^[^_]*_/)[0] + customPropCode + catalogId;
let newSelectNameValue = selectElem.attr('name').match(/^[^_]*_/)[0] + customPropCode + `[${catalogId}]`;
selectElem.attr('id', newSelectIdValue);
selectElem.attr('name', newSelectNameValue);
selectElem.data('type', customPropCode);
triggerSelectChange(selectElem);
});
}
function triggerSelectChange(selectElem)
{
if (selectElem.val().length > 0) {
selectElem.trigger('change', [self]);
}
}
function setCustomProperties()
{
let customPropertiesRows = $('.custom-property-row');
if (customPropertiesRows.length === 0) {
return;
}
let customPropertyCatalogId;
let customPropertyTitle = '';
let customPropertyCode = '';
let productPropertyMatch = '';
let offerPropertyMatch = '';
let catalogIds = [];
customPropertiesRows.each(function (index, propertyRow) {
let propertyRowObj = $(propertyRow);
customPropertyCatalogId = propertyRowObj.closest('.iblockExportTable').data('type');
customPropertyTitle = propertyRowObj.find('input[name="custom-property-title"]').val();
if (!customPropertyTitle) {
return true;
}
customPropertyCode = getUniquePropertyCode(customPropertyTitle);
productPropertyMatch = propertyRowObj.find('select[name=custom-product-property-select]').val();
offerPropertyMatch = propertyRowObj.find('select[name=custom-offer-property-select]').val();
let values = {
'title': customPropertyTitle,
'code': customPropertyCode,
'productProperty': productPropertyMatch,
'offerProperty': offerPropertyMatch
};
if (catalogIds.indexOf(customPropertyCatalogId) === -1) {
customProps[customPropertyCatalogId] = [values];
} else {
customProps[customPropertyCatalogId].push(values);
}
catalogIds.push(customPropertyCatalogId);
});
}
function getUniquePropertyCode(customPropertyTitle)
{
let uniqueValue = transliterate(customPropertyTitle).replace(/ /g, '_');
let counter = 0;
const setupFieldsListValues = setupFieldsListElement.val().split(',');
while (setupFieldsListValues.includes(uniqueValue)) {
uniqueValue = `${customPropertyTitle}${++counter}`;
}
return uniqueValue;
}
function addParamsToSetupFieldsList()
{
let newParams = '';
if (Object.keys(customProps).length === 0) {
return;
}
for (let propertiesByCatalogId of Object.values(customProps)) {
propertiesByCatalogId.forEach(function (values) {
setupFieldsParamsToFill.forEach(function (param) {
newParams += ',' + param + values.code;
});
});
}
let newValue = setupFieldsListElement.val() + newParams;
setupFieldsListElement.val(newValue);
return true;
}
function deleteParamsFromSetupFieldsList()
{
let setupFields = setupFieldsListElement.val();
if (Object.keys(customPropsToDelete).length === 0) {
return;
}
for (let propsByCatalogId of Object.values(customPropsToDelete)) {
propsByCatalogId.forEach(function (propValues) {
setupFieldsParamsToFill.forEach(function (param) {
let paramToDelete = ',' + param + propValues.code;
setupFields = setupFields.replace(paramToDelete, '');
});
});
}
setupFieldsListElement.val(setupFields);
return true;
}
function createCustomPropsRaw(addRowButton)
{
let templateRow = $($('#custom-property-template-row').html());
let templateSelectElements = templateRow.find('select');
let prevTableRow = $(addRowButton).prev('table').find('tbody tr:last-child');
let lastRawSelectElements = prevTableRow.find('td select');
lastRawSelectElements.each(function (index, element) {
let selectElement = $(element);
let templateSelectElement = templateSelectElements[index];
fillTemplateSelect(selectElement, templateSelectElement);
prevTableRow.after(templateRow);
});
}
function fillTemplateSelect(sourceSelectElement, templateSelectElement)
{
let selectOptions = sourceSelectElement.find('option');
selectOptions.each(function (index, element) {
let optionElem = $(element);
let value = $(optionElem).val();
let text = $(optionElem).text();
$('<option>', { value: value, text: text }).appendTo(templateSelectElement);
});
}
function transliterate(titleToTransliterate)
{
const hasCyrillicChars = /[\u0400-\u04FF]/.test(titleToTransliterate);
if (!hasCyrillicChars) {
return titleToTransliterate;
}
translitedText = '';
for (var i = 0; i < titleToTransliterate.length; i++) {
switch (titleToTransliterate[i]) {
case 'а': case 'А': translitedText += 'a'; break;
case 'б': case 'Б': translitedText += 'b'; break;
case 'в': case 'В': translitedText += 'v'; break;
case 'г': case 'Г': translitedText += 'g'; break;
case 'д': case 'Д': translitedText += 'd'; break;
case 'е': case 'Е': translitedText += 'e'; break;
case 'ё': case 'Ё': translitedText += 'yo'; break;
case 'ж': case 'Ж': translitedText += 'zh'; break;
case 'з': case 'З': translitedText += 'z'; break;
case 'и': case 'И': translitedText += 'i'; break;
case 'й': case 'Й': translitedText += 'y'; break;
case 'к': case 'К': translitedText += 'k'; break;
case 'л': case 'Л': translitedText += 'l'; break;
case 'м': case 'М': translitedText += 'm'; break;
case 'н': case 'Н': translitedText += 'n'; break;
case 'о': case 'О': translitedText += 'o'; break;
case 'п': case 'П': translitedText += 'p'; break;
case 'р': case 'Р': translitedText += 'r'; break;
case 'с': case 'С': translitedText += 's'; break;
case 'т': case 'Т': translitedText += 't'; break;
case 'у': case 'У': translitedText += 'u'; break;
case 'ф': case 'Ф': translitedText += 'f'; break;
case 'х': case 'Х': translitedText += 'h'; break;
case 'ц': case 'Ц': translitedText += 'c'; break;
case 'ч': case 'Ч': translitedText += 'ch'; break;
case 'ш': case 'Ш': translitedText += 'sh'; break;
case 'щ': case 'Щ': translitedText += 'sch'; break;
case 'ъ': case 'Ъ': translitedText += ''; break;
case 'ы': case 'Ы': translitedText += 'y'; break;
case 'ь': case 'Ь': translitedText += ''; break;
case 'э': case 'Э': translitedText += 'e'; break;
case 'ю': case 'Ю': translitedText += 'yu'; break;
case 'я': case 'Я': translitedText += 'ya'; break;
default: translitedText += titleToTransliterate[i]; break;
}
}
return translitedText;
}

View file

@ -0,0 +1,59 @@
function getTimeRemaining(endtime) {
return Date.parse(endtime) - Date.parse(new Date());
}
function initializeClock(id, endtime) {
$('#countdownDiv').show();
$('#deadlineMessage').hide();
const timeInterval = setInterval(updateClock, 1000);
const clock = document.getElementById(id);
function updateClock() {
const time = getTimeRemaining(endtime);
if (time <= 0) {
$('#countdownDiv').hide();
$('#deadlineMessage').show();
clearInterval(timeInterval);
return true;
}
clock.innerText = String(time).slice(0, -3);
}
updateClock();
}
function resendRegisterSms(idInLoyalty) {
BX.ajax.runAction('intaro:retailcrm.api.loyalty.register.resendRegisterSms',
{
data: {
sessid: BX.bitrix_sessid(),
idInLoyalty: idInLoyalty
}
}
).then(function(response) {
$('#lpRegMsg').text(response.data.msg);
$('#checkIdField').val(response.data.form.fields.checkId.value);
initializeClock("countdown", response.data.resendAvailable);
});
}
function resendOrderSms(orderId) {
BX.ajax.runAction('intaro:retailcrm.api.loyalty.order.resendOrderSms',
{
data: {
sessid: BX.bitrix_sessid(),
orderId: orderId
}
}
).then(function(response) {
if (response.data.msg !== undefined) {
$('#msg').text(response.data.msg);
} else if (response.data.resendAvailable !== undefined) {
$('#checkIdVerify').val(response.data.checkId);
initializeClock("countdown", new Date(response.data.resendAvailable.date));
}
});
}

View file

@ -0,0 +1,3 @@
<?
//<title>RetailCRM</title>
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/intaro.retailcrm/export/export_run.php");

View file

@ -0,0 +1,3 @@
<?
//<title>RetailCRM</title>
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/intaro.retailcrm/export/export_setup.php");

View file

@ -0,0 +1,16 @@
<?php
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) {
die();
}
$arComponentDescription = [
"NAME" => GetMessage("COMP_MAIN_USER_REGISTER_TITLE"),
"DESCRIPTION" => GetMessage("COMP_MAIN_USER_REGISTER_DESCR"),
"PATH" => [
"ID" => "utility",
"CHILD" => [
"ID" => "user",
"NAME" => GetMessage("MAIN_USER_GROUP_NAME"),
],
],
];

View file

@ -0,0 +1,4 @@
<?php
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) {
die();
}

View file

@ -0,0 +1,6 @@
<?php
if(!defined("B_PROLOG_INCLUDED")||B_PROLOG_INCLUDED!==true) {
die();
}
$this->IncludeComponentTemplate();

View file

@ -0,0 +1,4 @@
<?php
$MESS ['COMP_MAIN_USER_REGISTER_TITLE'] = "Регистрация в программе лояльности";
$MESS ['COMP_MAIN_USER_REGISTER_DESCR'] = "Управляемая регистрация в программе лояльности";
$MESS ['MAIN_USER_GROUP_NAME'] = "Пользователь";

View file

@ -0,0 +1,3 @@
<?php
$MESS ['INTARO_NOT_INSTALLED'] = "Модуль интеграции с RetailCRM не установлен";

View file

@ -0,0 +1,6 @@
<?php
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) {
die();
}
$arTemplateParameters = [];

View file

@ -0,0 +1,2 @@
<?php
$MESS ['USER_PROPERTY_NAME'] = "Name of the custom property block";

View file

@ -0,0 +1,29 @@
<?php
$MESS["main_register_sms"] = "Confirmation code from SMS:";
$MESS["PERSONAL_PHONE"] = "Phone";
$MESS["main_register_sms_send"] = "Send";
$MESS["UF_REG_IN_PL_INTARO"] = "Register in loyalty program";
$MESS["UF_AGREE_PL_INTARO"] = "loyalty programs:";
$MESS["I_AM_AGREE"] = "I agree to the terms and conditions";
$MESS["UF_PD_PROC_PL_INTARO"] = "personal data processing:";
$MESS["LP_CARD_NUMBER"] = "Loyalty program card number";
$MESS["SEND"] = "Send";
$MESS["TRY_AGAIN"] = "Try Again";
$MESS["VERIFICATION_CODE"] = "Confirmation Code";
$MESS["SEND_VERIFICATION_CODE"] = "Send confirmation code";
$MESS["REG_LP_MESSAGE"] = "Enter your phone number and loyalty program card number to complete your loyalty program registration.";
$MESS["YES"] = "Yes";
$MESS["BONUS_CARD_NUMBER"] = "Loyalty card number (if any):";
$MESS["SUCCESS_PL_REG"] = "You have successfully registered in the loyalty program.";
$MESS["LP_FIELDS_NOT_EXIST"] = "PL module installation error. UF fields for USER are missing.";
$MESS["REG_LP_ERROR"] = "Error of registration in the Loyalty Program";
$MESS["REGISTER_CONTINUE"] = "Fill out the form to complete your registration in the loyalty program.";
$MESS["UF_CARD_NUM_INTARO"] = "Loyalty card number (if any)";
$MESS["REGISTER_LP_TITLE"] = "Registration in the loyalty program";
$MESS["NOT_AUTHORIZED"] = "You are not logged in. To register, please follow the <a href=\"./lp-register\">link</a>";
$MESS["LP_NOT_ACTIVE"] = "Loyalty program is not active at the moment";
$MESS["SEC"] = "seconds";
$MESS["RESEND_SMS"] = "Send sms again";
$MESS["RESEND_POSSIBLE"] = "It is possible to resend sms via";
$MESS["LOYALTY_CONNECTION_ERROR"] = "There are problems connecting to the remote server. Try reloading the page.";
$MESS ["NO_VALID_EMAIL"] = "Check that your email is filled in correctly";

View file

@ -0,0 +1,2 @@
<?php
$MESS ['USER_PROPERTY_NAME'] = "Название блока пользовательских свойств";

View file

@ -0,0 +1,29 @@
<?php
$MESS["main_register_sms"] = "Код подтверждения из СМС:";
$MESS["PERSONAL_PHONE"] = "Телефон";
$MESS["main_register_sms_send"] = "Отправить";
$MESS["UF_REG_IN_PL_INTARO"] = "Зарегистрироваться в программе лояльности";
$MESS["UF_AGREE_PL_INTARO"] = "программы лояльности:";
$MESS["I_AM_AGREE"] = "Я согласен с условиями";
$MESS["UF_PD_PROC_PL_INTARO"] = "обработки персональных данных:";
$MESS["LP_CARD_NUMBER"] = "Номер карты программы лояльности";
$MESS["SEND"] = "Отправить";
$MESS["TRY_AGAIN"] = "Попробовать снова";
$MESS["VERIFICATION_CODE"] = "Код подтверждения";
$MESS["SEND_VERIFICATION_CODE"] = "Отправьте код подтверждения";
$MESS["REG_LP_MESSAGE"] = "Для завершения регистрации в программе лояльности введите номер телефона и номер карты программы лояльности";
$MESS["YES"] = "Да";
$MESS["BONUS_CARD_NUMBER"] = "Номер карты лояльности (если есть):";
$MESS["SUCCESS_PL_REG"] = "Вы успешно зарегистрировались в программе лояльности.";
$MESS["LP_FIELDS_NOT_EXIST"] = "Ошибка установки модуля ПЛ. Отсутствуют UF поля для USER";
$MESS["REG_LP_ERROR"] = "Ошибка регистрации в Программе лояльности";
$MESS["REGISTER_CONTINUE"] = "Для завершения регистрации в программе лояльности заполните форму.";
$MESS["UF_CARD_NUM_INTARO"] = "Номер карты лояльности (если есть)";
$MESS["REGISTER_LP_TITLE"] = "Регистрация в программе лояльности";
$MESS["NOT_AUTHORIZED"] = "Вы не авторизованы на сайте. Для регистрации пройдите по <a href=\"./lp-register\">ссылке</a>";
$MESS["LP_NOT_ACTIVE"] = "Программа лояльности в данный момент не активна";
$MESS["SEC"] = "сек.";
$MESS["RESEND_SMS"] = "Отправить смс повторно";
$MESS["RESEND_POSSIBLE"] = "Повторная отправка смс возможна через";
$MESS["LOYALTY_CONNECTION_ERROR"] = "Возникли проблемы с подключением к удаленному серверу. Попробуйте перезагрузить страницу.";
$MESS ["NO_VALID_EMAIL"] = "Проверьте правильность заполнения email";

View file

@ -0,0 +1,76 @@
<?php
use Bitrix\Main\ArgumentException;
use Bitrix\Main\Loader;
use Bitrix\Main\LoaderException;
use Bitrix\Main\ObjectPropertyException;
use Bitrix\Main\SystemException;
use Intaro\RetailCrm\Component\ConfigProvider;
use Intaro\RetailCrm\Component\Constants;
use Intaro\RetailCrm\Component\ServiceLocator;
use Intaro\RetailCrm\Repository\AgreementRepository;
use Intaro\RetailCrm\Service\CustomerService;
use Intaro\RetailCrm\Service\LoyaltyAccountService;
use RetailCrm\Exception\CurlException;
/** RetailCRM loyalty program start */
function checkLoadIntaro(): bool
{
try {
return Loader::includeModule('intaro.retailcrm');
} catch (LoaderException $e) {
return false;
}
}
if (checkLoadIntaro()) {
$arResult['LOYALTY_STATUS'] = ConfigProvider::getLoyaltyProgramStatus();
global $USER;
if ('Y' === $arResult['LOYALTY_STATUS'] && $USER->IsAuthorized()) {
try {
/** @var CustomerService $customerService */
$customerService = ServiceLocator::get(CustomerService::class);
$customer = $customerService->createModel($USER->GetID());
$customerService->createCustomer($customer);
/* @var LoyaltyAccountService $service */
$service = ServiceLocator::get(LoyaltyAccountService::class);
$arResult['LP_REGISTER'] = $service->checkRegInLp();
} catch (CurlException $exception){
Logger::getInstance()->write($exception->getMessage(), Constants::TEMPLATES_ERROR);
$arResult['LOYALTY_CONNECTION_ERROR'] = true;
}
}
$arResult['ACTIVATE'] = isset($_GET['activate'])
&& $_GET['activate'] === 'Y'
&& $arResult['LP_REGISTER']['form']['button']['action'] === 'activateAccount';
try {
$agreementPersonalData = AgreementRepository::getFirstByWhere(
['AGREEMENT_TEXT'],
[
['CODE', '=', 'AGREEMENT_PERSONAL_DATA_CODE'],
]
);
$agreementLoyaltyProgram = AgreementRepository::getFirstByWhere(
['AGREEMENT_TEXT'],
[
['CODE', '=', 'AGREEMENT_LOYALTY_PROGRAM_CODE'],
]
);
} catch (ObjectPropertyException | ArgumentException | SystemException $exception) {
Logger::getInstance()->write($exception->getMessage(), Constants::TEMPLATES_ERROR);
}
$arResult['AGREEMENT_PERSONAL_DATA'] = $agreementPersonalData['AGREEMENT_TEXT'];
$arResult['AGREEMENT_LOYALTY_PROGRAM'] = $agreementLoyaltyProgram['AGREEMENT_TEXT'];
} else {
AddMessage2Log(GetMessage('INTARO_NOT_INSTALLED'));
}
/** RetailCRM loyalty program end */

Some files were not shown because too many files have changed in this diff Show more