1
0
Fork 0
mirror of synced 2025-04-10 04:31:04 +00:00

Compare commits

...

433 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
714 changed files with 119999 additions and 7547 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

8
.gitignore vendored
View file

@ -7,5 +7,11 @@
.idea/*
/.idea
/.idea/*
.travis.yml
/intaro.retailcrm/log/*
/tmp/
/vendor/
.env
.phpunit.result.cache
/release/
coverage.xml

View file

@ -1,3 +1,728 @@
## 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
* Добавлена поддержка реквизитов юр. лиц
@ -11,12 +736,14 @@
* Исправлена неправильная выгрузка сервисов для служб доставок
* Исправлено не правильное определение местоположения
* Рефакторинг модуля
## 2015-02-13 v.1.0.16
* Все действия агента происходят от имени retailcrm
## 2015-02-12 v.1.0.16
* Исправлен агент
* Исправлены ошибки с запоминанием пользователя
* Исправленна ошибка с выходом пользователя из системы
* Исправлена ошибка с выходом пользователя из системы
* Исправлена ошибка хождения пользователя под другим логином
* Исправлены проблема с fix-external-ids
* Добавлена возможность получения скидки из CRM в Битрикс

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 [retailCRM](http://www.retailcrm.ru) through [REST API](http://retailcrm.ru/docs/Разработчики).
Bitrix module for interaction with [RetailCRM](https://www.retailcrm.ru)
Module allows:
* Exchange the orders with retailCRM
* Configure relations between dictionaries of retailCRM and Bitrix (statuses, payments, delivery types and etc)
* Generate [ICML](http://docs.retailcrm.ru/index.php?n=Разработчики.ФорматICML) (Intaro Markup Language) for catalog loading by retailCRM
* 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/solutions/intaro.intarocrm/).
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,7 +0,0 @@
<?php
namespace RetailCrm\Exception;
class CurlException extends \RuntimeException
{
}

View file

@ -1,7 +0,0 @@
<?php
namespace RetailCrm\Exception;
class InvalidJsonException extends \DomainException
{
}

View file

@ -1,538 +0,0 @@
<?php
global $MESS;
IncludeModuleLangFile(__FILE__);
class ICMLLoader {
public $iblocks;
public $filename;
public $serverName;
public $propertiesSKU;
public $propertiesUnitSKU;
public $propertiesProduct;
public $propertiesUnitProduct;
public $application;
public $encoding = 'utf-8';
public $encodingDefault = 'utf-8';
public $loadPurchasePrice = false;
protected $fp;
protected $mainSection = 1000000;
protected $pageSize = 500;
protected $offerPageSize = 50;
protected $isLogged = false;
protected $logFile = '/bitrix/catalog_export/i_crm_load_log.txt';
protected $fpLog;
protected $MODULE_ID = 'intaro.intarocrm';
protected $CRM_CATALOG_BASE_PRICE = 'catalog_base_price';
protected $measurement = array (
'mm' => 1, // 1 mm = 1 mm
'cm' => 10, // 1 cm = 10 mm
'm' => 1000,
'mg' => 0.001, // 0.001 g = 1 mg
'g' => 1,
'kg' => 1000,
);
protected $measurementLink = array (
'mm' => 'mm',
'cm' => 'mm',
'm' => 'mm',
'mg' => 'g',
'g' => 'g',
'kg' => 'g',
);
public function Load()
{
global $USER;
if(!isset($_SESSION["SESS_AUTH"]["USER_ID"]) || !$_SESSION["SESS_AUTH"]["USER_ID"])
$USER = new CUser;
$this->isLogged = true;
$defaultSite = CSite::GetList($by="def", $order="desc", Array())->Fetch();
$this->encodingDefault = $defaultSite["CHARSET"];
$this->PrepareSettings();
$this->fp = $this->PrepareFile($this->filename. '.tmp');
if ($this->isLogged) {
$this->fpLog = $this->PrepareFile($this->logFile);
$this->WriteLog("Start Loading");
}
$this->PreWriteCatalog();
$categories = $this->GetCategories();
$this->WriteCategories($categories);
$this->PreWriteOffers();
$this->BuildOffers($categories);
$this->PostWriteOffers();
$this->PostWriteCatalog();
if ($this->isLogged) {
$this->WriteLog("Loading was ended successfully (peek memory usage: " . memory_get_peak_usage() . ")");
}
$this->CloseFile($this->fp);
$this->CloseFile($this->fpLog);
unlink($_SERVER["DOCUMENT_ROOT"] . $this->filename);
rename($_SERVER["DOCUMENT_ROOT"] . $this->filename. '.tmp', $_SERVER["DOCUMENT_ROOT"] . $this->filename);
return true;
}
protected function PrepareSettings()
{
foreach ($this->propertiesSKU as $iblock => $arr) {
foreach ($arr as $id => $sku) {
$this->propertiesSKU[$iblock][$id] = strtoupper($sku);
}
}
foreach ($this->propertiesProduct as $iblock => $arr) {
foreach ($arr as $id => $prod) {
$this->propertiesProduct[$iblock][$id] = strtoupper($prod);
}
}
}
protected function PrepareValue($text)
{
$newText = $this->application->ConvertCharset($text, $this->encodingDefault, $this->encoding);
$newText = strip_tags($newText);
$newText = str_replace("&", "&#x26;", $newText);
return $newText;
}
protected function PrepareFile($filename)
{
$fullFilename = $_SERVER["DOCUMENT_ROOT"] . $filename;
CheckDirPath($fullFilename);
if ($fp = @fopen($fullFilename, "w"))
return $fp;
else
return false;
}
protected function PreWriteCatalog()
{
@fwrite($this->fp, "<yml_catalog date=\"" . $this->PrepareValue(Date("Y-m-d H:i:s")) . "\">\n
<shop>\n
<name>" . $this->PrepareValue(COption::GetOptionString("main", "site_name", ""))."</name>\n
<company>" . $this->PrepareValue(COption::GetOptionString("main", "site_name", ""))."</company>\n"
);
}
protected function WriteCategories($categories)
{
$stringCategories = "";
@fwrite($this->fp, "<categories>\n");
foreach ($categories as $category) {
$stringCategories .= $this->BuildCategory($category);
}
@fwrite($this->fp, $stringCategories);
@fwrite($this->fp, "</categories>\n");
}
protected function PreWriteOffers()
{
@fwrite($this->fp, "<offers>\n");
}
protected function PostWriteOffers()
{
@fwrite($this->fp, "</offers>\n");
}
protected function WriteOffers($offers)
{
@fwrite($this->fp, $offers);
}
protected function WriteLog($text)
{
if ($this->isLogged)
@fwrite($this->fpLog, Date("Y:m:d H:i:s") . ": " . $text . "\n");
}
protected function PostWriteCatalog()
{
@fwrite($this->fp, "</shop>\n
</yml_catalog>\n");
}
protected function CloseFile($fp)
{
@fclose($fp);
}
protected function GetCategories()
{
$categories = array();
foreach ($this->iblocks as $id)
{
$filter = array("IBLOCK_ID" => $id);
$dbRes = CIBlockSection::GetList(array("left_margin" => "asc"), $filter);
$hasCategories = false;
while ($arRes = $dbRes->Fetch()) {
$categories[$arRes['ID']] = $arRes;
$hasCategories = true;
}
if (!$hasCategories) {
$iblock = CIBlock::GetByID($id)->Fetch();
$arRes = Array();
$arRes['ID'] = $this->mainSection + $id;
$arRes['IBLOCK_SECTION_ID'] = 0;
$arRes['NAME'] = sprintf(GetMessage('ROOT_CATEGORY_FOR_CATALOG'), $iblock['NAME']);
$categories[$arRes['ID']] = $arRes;
}
}
return $categories;
}
protected function BuildCategory($arCategory)
{
return "
<category id=\"" . $this->PrepareValue($arCategory["ID"]) . "\""
. ( intval($arCategory["IBLOCK_SECTION_ID"] ) > 0 ?
" parentId=\"" . $this->PrepareValue($arCategory["IBLOCK_SECTION_ID"]) . "\""
:"")
. ">"
. $this->PrepareValue($arCategory["NAME"])
. "</category>\n";
}
protected function BuildOffers(&$allCategories)
{
$basePriceId = COption::GetOptionString($this->MODULE_ID, $this->CRM_CATALOG_BASE_PRICE, 1);
foreach ($this->iblocks as $key => $id)
{
// Get Info by infoblocks
$iblock['IBLOCK_DB'] = CIBlock::GetByID($id)->Fetch();
$iblockOffer = CCatalogSKU::GetInfoByProductIBlock($id);
$arSelect = Array (
"ID",
"LID",
"IBLOCK_ID",
"IBLOCK_SECTION_ID",
"ACTIVE",
"ACTIVE_FROM",
"ACTIVE_TO",
"NAME",
"DETAIL_PICTURE",
"DETAIL_TEXT",
"DETAIL_PICTURE",
"LANG_DIR",
"DETAIL_PAGE_URL",
"CATALOG_GROUP_" . $basePriceId
);
// Set selected properties
foreach ($this->propertiesProduct[$id] as $key => $propProduct) {
if ($this->propertiesProduct[$id][$key] != "") {
$arSelect[] = "PROPERTY_" . $propProduct;
$arSelect[] = "PROPERTY_" . $propProduct . ".NAME";
}
}
$arSelectOffer = Array (
'ID',
'ACTIVE',
"NAME",
"DETAIL_TEXT",
"DETAIL_PAGE_URL",
"DETAIL_PICTURE",
'PROPERTY_' . $iblockOffer['SKU_PROPERTY_ID'],
"CATALOG_GROUP_" . $basePriceId
);
// Set selected properties
foreach ($this->propertiesSKU[$id] as $key => $propSKU) {
if ($this->propertiesSKU[$id][$key] != "") {
$arSelectOffer[] = "PROPERTY_" . $propSKU;
$arSelectOffer[] = "PROPERTY_" . $propSKU . ".NAME";
}
}
// Set filter
$filter = array(
"IBLOCK_ID" => $id,
"INCLUDE_SUBSECTIONS" => "Y",
);
$order = array("id");
$arNavStatParams = Array(
"iNumPage" => 1,
"nPageSize" => $this->pageSize,
);
// Cycle page to page
do {
// Get products on this page
$dbResProducts = CIBlockElement::GetList($order, $filter, false, $arNavStatParams, $arSelect);
$pictures = array();
$products = array();
while ($product = $dbResProducts->GetNext()) {
// Compile products to array
$products[$product['ID']] = $product;
$products[$product['ID']]['offers'] = array();
$detailPicture = intval($product["DETAIL_PICTURE"]);
$previewPicture = intval($product["PREVIEW_PICTURE"]);
if ($detailPicture > 0 || $previewPicture > 0)
{
$picture = $detailPicture;
if ($picture <= 0) {
$picture = $previewPicture;
}
// Link pictureID and productID
$pictures[$picture] = $product['ID'];
}
}
unset($product);
unset($detailPicture, $previewPicture, $picture);
$pictureIDs = array_keys($pictures);
// Get pathes of pictures
$dbFiles = CFile::GetList(Array(), Array("@ID" => implode(',', $pictureIDs)));
while($file = $dbFiles->GetNext()) {
// Link picture to product
$products[$pictures[$file['ID']]]['PICTURE'] = ($_SERVER["HTTPS"] == 'on' ? "https://" : "http://") .
$this->serverName .
'/upload/' . $file['SUBDIR'] .
'/' . $file['FILE_NAME'] ;
}
unset($pictures);
if (!empty($iblockOffer['IBLOCK_ID'])) {
$arFilterOffer = array(
'IBLOCK_ID' => $iblockOffer['IBLOCK_ID'],
'PROPERTY_' . $iblockOffer['SKU_PROPERTY_ID'] => array_keys($products),
);
// Get all offers for products on this page
$dbResOffers = CIBlockElement::GetList(
array(),
$arFilterOffer,
false,
array('nTopCount' => $this->pageSize * $this->offerPageSize),
$arSelectOffer
);
while ($offer = $dbResOffers->GetNext()) {
// Link offers to products
$products[$offer['PROPERTY_' . $iblockOffer['SKU_PROPERTY_ID'] . '_VALUE']]['offers'][$offer['ID']] = $offer;
}
unset($offer, $dbResOffers);
}
$stringOffers = "";
foreach ($products as $product) {
// Get properties of product
$resPropertiesProduct = Array();
foreach ($this->propertiesProduct[$id] as $key => $propProduct) {
$resPropertiesProduct[$key] = "";
if ($propProduct != "") {
if (isset($product["PROPERTY_" . $propProduct . "_NAME"]))
$resPropertiesProduct[$key] = $product["PROPERTY_" . $propProduct . "_NAME"];
elseif (isset($product["PROPERTY_" . $propProduct . "_VALUE"]))
$resPropertiesProduct[$key] = $product["PROPERTY_" . $propProduct . "_VALUE"];
elseif (isset($product[$propProduct]))
$resPropertiesProduct[$key] = $product[$propProduct];
if (array_key_exists($key, $this->propertiesUnitProduct[$id])) {
$resPropertiesProduct[$key] *= $this->measurement[$this->propertiesUnitProduct[$id][$key]];
$resPropertiesProduct[$key . "_UNIT"] = $this->measurementLink[$this->propertiesUnitProduct[$id][$key]];
}
}
}
// Get categories of product
$categories = Array();
$dbResCategories = CIBlockElement::GetElementGroups($product['ID'], true);
while ($arResCategory = $dbResCategories->Fetch()) {
$categories[$arResCategory["ID"]] = array(
'ID' => $arResCategory["ID"],
'NAME' => $arResCategory["NAME"],
);
}
if (count($categories) == 0) {
$catId = $this->mainSection + $id;
$categories[$catId] = $allCategories[$catId];
}
$existOffer = false;
if (!empty($iblockOffer['IBLOCK_ID'])) {
foreach ($product['offers'] as $offer) {
$offer['PRODUCT_ID'] = $product["ID"];
$offer['DETAIL_PAGE_URL'] = $product["DETAIL_PAGE_URL"];
$offer['PICTURE'] = $product["PICTURE"];
$offer['PRODUCT_NAME'] = $product["NAME"];
$offer['PRODUCT_ACTIVE'] = $product["ACTIVE"];
$offer['PRICE'] = $offer['CATALOG_PRICE_' . $basePriceId];
$offer['PURCHASE_PRICE'] = $offer['CATALOG_PURCHASING_PRICE'];
$offer['QUANTITY'] = $offer["CATALOG_QUANTITY"];
// Get properties of product
foreach ($this->propertiesSKU[$id] as $key => $propSKU) {
if ($propSKU != "") {
if (isset ($offer["PROPERTY_" . $propSKU . "_NAME"]))
$offer['_PROP_' . $key] = $offer["PROPERTY_" . $propSKU . "_NAME"];
elseif (isset($offer["PROPERTY_" . $propSKU . "_VALUE"]))
$offer['_PROP_' . $key] = $offer["PROPERTY_" . $propSKU . "_VALUE"];
elseif (isset($offer[$propSKU]))
$offer['_PROP_' . $key] = $offer[$propSKU];
if (array_key_exists($key, $this->propertiesUnitSKU[$id])) {
$offer['_PROP_' . $key] *= $this->measurement[$this->propertiesUnitSKU[$id][$key]];
$offer['_PROP_' . $key . "_UNIT"] = $this->measurementLink[$this->propertiesUnitSKU[$id][$key]];
}
}
}
foreach ($resPropertiesProduct as $key => $propProduct) {
if ($this->propertiesProduct[$id][$key] != "" && !isset($offer[$key]))
$offer['_PROP_' . $key] = $propProduct;
}
$stringOffers .= $this->BuildOffer($offer, $categories, $iblock, $allCategories);
$existOffer = true;
}
}
if (!$existOffer) {
$product['PRODUCT_ID'] = $product["ID"];
$product['PRODUCT_NAME'] = $product["NAME"];
$product['PRODUCT_ACTIVE'] = $product["ACTIVE"];
$product['PRICE'] = $product['CATALOG_PRICE_' . $basePriceId];
$product['PURCHASE_PRICE'] = $product['CATALOG_PURCHASING_PRICE'];
$product['QUANTITY'] = $product["CATALOG_QUANTITY"];
foreach ($resPropertiesProduct as $key => $propProduct) {
if ($this->propertiesProduct[$id][$key] != "" || $this->propertiesProduct[$id][str_replace("_UNIT", "", $key)] != "") {
$product['_PROP_' . $key] = $propProduct;
}
}
$stringOffers .= $this->BuildOffer($product, $categories, $iblock, $allCategories);
}
}
unset($products);
if ($this->isLogged)
$this->WriteLog(($this->pageSize * $arNavStatParams['iNumPage']) . " product(s) has been loaded from " . $id . " IB (memory usage: " . memory_get_usage() . ")");
if ($stringOffers != "") {
$this->WriteOffers($stringOffers);
$stringOffers = "";
}
$arNavStatParams['iNumPage'] = $dbResProducts->NavPageNomer + 1;
}
while ($dbResProducts->NavPageNomer < $dbResProducts->NavPageCount);
}
}
protected function BuildOffer($arOffer, $categories, $iblock, &$allCategories)
{
$offer = "";
$offer .= "<offer id=\"" .$this->PrepareValue($arOffer["ID"]) . "\" ".
"productId=\"" . $this->PrepareValue($arOffer["PRODUCT_ID"]) . "\" ".
"quantity=\"" . $this->PrepareValue(DoubleVal($arOffer['QUANTITY'])) . "\">\n";
if ($arOffer['PRODUCT_ACTIVE'] == "N")
$offer .= "<productActivity>" . $this->PrepareValue($arOffer['PRODUCT_ACTIVE']) . "</productActivity>\n";
$keys = array_keys($categories);
if (strpos($arOffer['DETAIL_PAGE_URL'], "#SECTION_PATH#") !== false) {
if (count($categories) != 0) {
$category = $allCategories[$keys[0]];
$path = $category['CODE'];
if(intval($category["IBLOCK_SECTION_ID"] ) != 0) {
while (true) {
$category = $allCategories[$category['IBLOCK_SECTION_ID']];
$path = $category['CODE'] . '/' . $path;
if(intval($category["IBLOCK_SECTION_ID"] ) == 0)
break;
}
}
}
$arOffer['DETAIL_PAGE_URL'] = str_replace("#SECTION_PATH#", $path, $arOffer['DETAIL_PAGE_URL']);
}
$offer .= "<picture>" . $this->PrepareValue($arOffer["PICTURE"]) . "</picture>\n";
$offer .= "<url>" . ($_SERVER["HTTPS"] == 'on' ? "https://" : "http://") . $this->serverName . $this->PrepareValue($arOffer['DETAIL_PAGE_URL']) . "</url>\n";
$offer .= "<price>" . $this->PrepareValue($arOffer['PRICE']) . "</price>\n";
if ($arOffer['PURCHASE_PRICE'] && $this->loadPurchasePrice) {
$offer .= "<purchasePrice>" . $this->PrepareValue($arOffer['PURCHASE_PRICE']) . "</purchasePrice>\n";
}
foreach ($categories as $category)
$offer .= "<categoryId>" . $category['ID'] . "</categoryId>\n";
$offer .= "<name>" . $this->PrepareValue($arOffer["NAME"]) . "</name>\n";
$offer .= "<xmlId>" . $this->PrepareValue($arOffer["EXTERNAL_ID"]) . "</xmlId>\n";
$offer .= "<productName>" . $this->PrepareValue($arOffer["PRODUCT_NAME"]) . "</productName>\n";
foreach ($this->propertiesProduct[$iblock['IBLOCK_DB']['ID']] as $key => $propProduct) {
if ($propProduct != "" && $arOffer['_PROP_' . $key] != null) {
if ($key === "manufacturer")
$offer .= "<vendor>" . $this->PrepareValue($arOffer['_PROP_' . $key]) . "</vendor>\n";
else
$offer .= '<param name="' . $key . '"' . (isset($arOffer['_PROP_' . $key . "_UNIT"]) ? ' unit="' . $arOffer['_PROP_' . $key . "_UNIT"] . '"' : "") . ">" . $this->PrepareValue($arOffer['_PROP_' . $key]) . "</param>\n";
}
}
foreach ($this->propertiesSKU[$iblock['IBLOCK_DB']['ID']] as $key => $propProduct) {
if ($propProduct != "" && $arOffer['_PROP_' . $key] != null) {
if ($key === "manufacturer")
$offer .= "<vendor>" . $this->PrepareValue($arOffer['_PROP_' . $key]) . "</vendor>\n";
else
$offer .= '<param name="' . $key . '"' . (isset($arOffer['_PROP_' . $key . "_UNIT"]) ? ' unit="' . $arOffer['_PROP_' . $key . "_UNIT"] . '"' : "") . ">" . $this->PrepareValue($arOffer['_PROP_' . $key]) . "</param>\n";
}
}
$offer.= "</offer>\n";
return $offer;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,689 +0,0 @@
<?php
namespace RetailCrm;
use RetailCrm\Response\ApiResponse;
use RetailCrm\Exception\CurlException;
/**
* retailCRM API client class
*/
class RestApi
{
const VERSION = 'v3';
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';
protected $client;
protected $url;
protected $defaultParameters;
protected $generatedAt;
/**
* Site code
*/
protected $siteCode;
/**
* Client creating
*
* @param string $url - url сайта
* @param string $apiKey - ключ API
* @param string $site - символьный код сайта
* @return mixed
*/
public function __construct($url, $apiKey, $site = null)
{
if ('/' != substr($url, strlen($url) - 1, 1)) {
$url .= '/';
}
$url = $url . 'api/' . self::VERSION;
if (false === stripos($url, 'https://')) {
throw new \InvalidArgumentException('API schema requires HTTPS protocol');
}
$this->url = $url;
$this->defaultParameters = array('apiKey' => $apiKey);
$this->siteCode = $site;
}
/* Методы для работы с заказами */
/**
* Получение заказа по id
*
* @param string $id - идентификатор заказа
* @param string $by - поиск заказа по id или externalId
* @param string $site - символьный код сайта
* @return ApiResponse - информация о заказе
*/
public function ordersGet($id, $by = 'externalId', $site = null)
{
$this->checkIdParameter($by);
return $this->makeRequest("/orders/$id", self::METHOD_GET, $this->fillSite($site, array(
'by' => $by
)));
}
/**
* Создание заказа
*
* @param array $order - информация о заказе
* @param string $site - символьный код сайта
* @return ApiResponse
*/
public function ordersCreate($order, $site = null)
{
if (!sizeof($order)) {
throw new \InvalidArgumentException('Parameter `order` must contains a data');
}
return $this->makeRequest("/orders/create", self::METHOD_POST, $this->fillSite($site, array(
'order' => json_encode($order)
)));
}
/**
* Изменение заказа
*
* @param array $order - информация о заказе
* @param string $by - изменение заказа по id или externalId
* @param string $site - символьный код сайта
* @return ApiResponse
*/
public function orderEdit($order, $by = 'externalId', $site = null)
{
if (!sizeof($order)) {
throw new \InvalidArgumentException('Parameter `order` must contains a data');
}
$this->checkIdParameter($by);
if (!isset($order[$by])) {
throw new \InvalidArgumentException(sprintf('Order array must contain the "%s" parameter.', $by));
}
return $this->makeRequest(
"/orders/" . $order[$by] . "/edit",
self::METHOD_POST,
$this->fillSite($site, array(
'order' => json_encode($order),
'by' => $by,
))
);
}
/**
* Пакетная загрузка заказов
*
* @param array $orders - массив заказов
* @param string $site - символьный код сайта
* @return ApiResponse
*/
public function orderUpload($orders, $site = null)
{
if (!sizeof($orders)) {
throw new \InvalidArgumentException('Parameter `orders` must contains array of the orders');
}
return $this->makeRequest("/orders/upload", self::METHOD_POST, $this->fillSite($site, array(
'orders' => json_encode($orders),
)));
}
/**
* Обновление externalId у заказов с переданными id
*
* @param array $order - массив, содержащий id и externalId заказа
* @return ApiResponse
*/
public function orderFixExternalIds($order)
{
if (!sizeof($order)) {
throw new \InvalidArgumentException('Method parameter must contains at least one IDs pair');
}
return $this->makeRequest("/orders/fix-external-ids", self::METHOD_POST, array(
'orders' => json_encode($order),
));
}
/**
* Получение последних измененных заказов
*
* @param \DateTime|string|int $startDate - начальная дата и время выборки (Y-m-d H:i:s)
* @param \DateTime|string|int $endDate - конечная дата и время выборки (Y-m-d H:i:s)
* @param int $limit - ограничение на размер выборки
* @param int $offset - сдвиг
* @param bool $skipMyChanges
* @return ApiResponse
*/
public function orderHistory(
$startDate = null,
$endDate = null,
$limit = 100,
$offset = 0,
$skipMyChanges = true
) {
$parameters = array();
if ($startDate) {
$parameters['startDate'] = $this->ensureDateTime($startDate);
}
if ($endDate) {
$parameters['endDate'] = $this->ensureDateTime($endDate);
}
if ($limit) {
$parameters['limit'] = (int) $limit;
}
if ($offset) {
$parameters['offset'] = (int) $offset;
}
if ($skipMyChanges) {
$parameters['skipMyChanges'] = (bool) $skipMyChanges;
}
return $this->makeRequest('/orders/history', self::METHOD_GET, $parameters);
}
/* Методы для работы с клиентами */
/**
* Получение клиента по id
*
* @param string $id - идентификатор
* @param string $by - поиск заказа по id или externalId
* @param string $site - символьный код сайта
* @return array - информация о клиенте
*/
public function customerGet($id, $by = 'externalId', $site = null)
{
$this->checkIdParameter($by);
return $this->makeRequest("/customers/$id", self::METHOD_GET, $this->fillSite($site, array(
'by' => $by
)));
}
/**
* Получение списка клиентов в соответсвии с запросом
*
* @param array $filter - фильтры
* @param int $page - страница
* @param int $limit - ограничение на размер выборки
* @return ApiResponse
*/
public function customersList(array $filter = array(), $page = null, $limit = null)
{
$parameters = array();
if (sizeof($filter)) {
$parameters['filter'] = $filter;
}
if (null !== $page) {
$parameters['page'] = (int) $page;
}
if (null !== $limit) {
$parameters['limit'] = (int) $limit;
}
return $this->makeRequest('/customers', self::METHOD_GET, $parameters);
}
/**
* Создание клиента
*
* @param array $customer - информация о клиенте
* @param string $site - символьный код сайта
* @return ApiResponse
*/
public function customersCreate(array $customer, $site = null)
{
if (!sizeof($customer)) {
throw new \InvalidArgumentException('Parameter `customer` must contains a data');
}
return $this->makeRequest("/customers/create", self::METHOD_POST, $this->fillSite($site, array(
'customer' => json_encode($customer)
)));
}
/**
* Редактирование клиента
*
* @param array $customer - информация о клиенте
* @param string $by - изменение клиента по id или externalId
* @param string $site - символьный код сайта
* @return ApiResponse
*/
public function customerEdit($customer, $by = 'externalId', $site = null)
{
if (!sizeof($customer)) {
throw new \InvalidArgumentException('Parameter `customer` must contains a data');
}
$this->checkIdParameter($by);
if (!isset($customer[$by])) {
throw new \InvalidArgumentException(sprintf('Customer array must contain the "%s" parameter.', $by));
}
return $this->makeRequest(
"/customers/" . $customer[$by] . "/edit",
self::METHOD_POST,
$this->fillSite($site, array(
'customer' => json_encode($customer),
'by' => $by,
)
));
}
/**
* Пакетная загрузка клиентов
*
* @param array $customers - массив клиентов
* @param string $site - символьный код сайта
* @return ApiResponse
*/
public function customerUpload($customers, $site = null)
{
if (!sizeof($customers)) {
throw new \InvalidArgumentException('Parameter `customers` must contains array of the customers');
}
return $this->makeRequest("/customers/upload", self::METHOD_POST, $this->fillSite($site, array(
'customers' => json_encode($customers),
)));
}
/**
* Обновление externalId у клиентов с переданными id
*
* @param array $customers - массив, содержащий id и externalId заказа
* @return array
*/
public function customerFixExternalIds($customers)
{
if (!sizeof($customers)) {
throw new \InvalidArgumentException('Method parameter must contains at least one IDs pair');
}
return $this->makeRequest("/customers/fix-external-ids", self::METHOD_POST, array(
'customers' => json_encode($customers),
));
}
/* Методы для работы со справочниками */
/**
* Получение списка типов доставки
*
* @return ApiResponse
*/
public function deliveryTypesList()
{
return $this->makeRequest('/reference/delivery-types', self::METHOD_GET);
}
/**
* Редактирование типа доставки
*
* @param array $delivery - информация о типе доставки
* @return ApiResponse
*/
public function deliveryTypeEdit($delivery)
{
if (!isset($delivery['code'])) {
throw new \InvalidArgumentException('Data must contain "code" parameter.');
}
return $this->makeRequest(
'/reference/delivery-types/' . $delivery['code'] . '/edit',
self::METHOD_POST,
array(
'deliveryType' => json_encode($delivery)
)
);
}
/**
* Получение списка служб доставки
*
* @return ApiResponse
*/
public function deliveryServicesList()
{
return $this->makeRequest('/reference/delivery-services', self::METHOD_GET);
}
/**
* Редактирование службы доставки
*
* @param array $delivery - информация о типе доставки
* @return ApiResponse
*/
public function deliveryServiceEdit($delivery)
{
if (!isset($delivery['code'])) {
throw new \InvalidArgumentException('Data must contain "code" parameter.');
}
return $this->makeRequest(
'/reference/delivery-services/' . $delivery['code'] . '/edit',
self::METHOD_POST,
array(
'deliveryService' => json_encode($delivery)
)
);
}
/**
* Получение списка типов оплаты
*
* @return ApiResponse
*/
public function paymentTypesList()
{
return $this->makeRequest('/reference/payment-types', self::METHOD_GET);
}
/**
* Редактирование типа оплаты
*
* @param array $paymentType - информация о типе оплаты
* @return ApiResponse
*/
public function paymentTypesEdit($paymentType)
{
if (!isset($paymentType['code'])) {
throw new \InvalidArgumentException('Data must contain "code" parameter.');
}
return $this->makeRequest(
'/reference/payment-types/' . $paymentType['code'] . '/edit',
self::METHOD_POST,
array(
'paymentType' => json_encode($paymentType)
)
);
}
/**
* Получение списка статусов оплаты
*
* @return ApiResponse
*/
public function paymentStatusesList()
{
return $this->makeRequest('/reference/payment-statuses', self::METHOD_GET);
}
/**
* Редактирование статуса оплаты
*
* @param array $paymentStatus - информация о статусе оплаты
* @return ApiResponse
*/
public function paymentStatusesEdit($paymentStatus)
{
if (!isset($paymentStatus['code'])) {
throw new \InvalidArgumentException('Data must contain "code" parameter.');
}
return $this->makeRequest(
'/reference/payment-statuses/' . $paymentStatus['code'] . '/edit',
self::METHOD_POST,
array(
'paymentStatus' => json_encode($paymentStatus)
)
);
}
/**
* Получение списка типов заказа
*
* @return ApiResponse
*/
public function orderTypesList()
{
return $this->makeRequest('/reference/order-types', self::METHOD_GET);
}
/**
* Редактирование типа заказа
*
* @param array $orderType - информация о типе заказа
* @return ApiResponse
*/
public function orderTypesEdit($orderType)
{
if (!isset($orderType['code'])) {
throw new \InvalidArgumentException('Data must contain "code" parameter.');
}
return $this->makeRequest(
'/reference/order-types/' . $orderType['code'] . '/edit',
self::METHOD_POST,
array(
'orderType' => json_encode($orderType)
)
);
}
/**
* Получение списка способов оформления заказа
*
* @return ApiResponse
*/
public function orderMethodsList()
{
return $this->makeRequest('/reference/order-methods', self::METHOD_GET);
}
/**
* Редактирование способа оформления заказа
*
* @param array $orderMethod - информация о способе оформления заказа
* @return ApiResponse
*/
public function orderMethodsEdit($orderMethod)
{
if (!isset($orderMethod['code'])) {
throw new \InvalidArgumentException('Data must contain "code" parameter.');
}
return $this->makeRequest(
'/reference/order-methods/' . $orderMethod['code'] . '/edit',
self::METHOD_POST,
array(
'orderMethod' => json_encode($orderMethod)
)
);
}
/**
* Получение списка статусов заказа
*
* @return ApiResponse
*/
public function orderStatusesList()
{
return $this->makeRequest('/reference/statuses', self::METHOD_GET);
}
/**
* Получение списка сайтов
*
* @return ApiResponse
*/
public function sitesList()
{
return $this->makeRequest('/reference/sites', self::METHOD_GET);
}
/**
* Редактирование статуса заказа
*
* @param array $status - информация о статусе заказа
* @return ApiResponse
*/
public function orderStatusEdit($status)
{
if (!isset($status['code'])) {
throw new \InvalidArgumentException('Data must contain "code" parameter.');
}
return $this->makeRequest(
'/reference/statuses/' . $status['code'] . '/edit',
self::METHOD_POST,
array(
'status' => json_encode($status)
)
);
}
/**
* Получение списка групп статусов заказа
*
* @return ApiResponse
*/
public function orderStatusGroupsList()
{
return $this->makeRequest('/reference/status-groups', self::METHOD_GET);
}
/**
* Обновление статистики
*
* @return ApiResponse
*/
public function statisticUpdate()
{
return $this->makeRequest('/statistic/update', self::METHOD_GET);
}
/**
* @return \DateTime
*/
public function getGeneratedAt()
{
return $this->generatedAt;
}
protected function ensureDateTime($value)
{
if ($value instanceof \DateTime) {
return $value->format('Y-m-d H:i:s');
} elseif (is_int($value)) {
return date('Y-m-d H:i:s', $value);
}
return $value;
}
/**
* Check ID parameter
*
* @param string $by
* @return bool
*/
protected function checkIdParameter($by)
{
$allowedForBy = array('externalId', 'id');
if (!in_array($by, $allowedForBy)) {
throw new \InvalidArgumentException(sprintf(
'Value "%s" for parameter "by" is not valid. Allowed values are %s.',
$by,
implode(', ', $allowedForBy)
));
}
return true;
}
/**
* Fill params by site value
*
* @param string $site
* @param array $params
* @return array
*/
protected function fillSite($site, array $params)
{
if ($site) {
$params['site'] = $site;
} elseif ($this->siteCode) {
$params['site'] = $this->siteCode;
}
return $params;
}
/**
* Make HTTP request
*
* @param string $path
* @param string $method (default: 'GET')
* @param array $parameters (default: array())
* @param int $timeout
* @return ApiResponse
*/
public function makeRequest($path, $method, $parameters = array(), $timeout = 30)
{
$allowedMethods = array(self::METHOD_GET, self::METHOD_POST);
if (!in_array($method, $allowedMethods)) {
throw new \InvalidArgumentException(sprintf(
'Method "%s" is not valid. Allowed methods are %s',
$method,
implode(', ', $allowedMethods)
));
}
$parameters = array_merge($this->defaultParameters, $parameters);
$path = $this->url . $path;
if (self::METHOD_GET === $method && sizeof($parameters)) {
$path .= '?' . http_build_query($parameters);
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $path);
curl_setopt($ch, CURLOPT_FAILONERROR, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // return into a variable
curl_setopt($ch, CURLOPT_TIMEOUT, (int) $timeout); // times out after 30s
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // allow redirects
if (self::METHOD_POST === $method) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters);
}
$responseBody = curl_exec($ch);
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$errno = curl_errno($ch);
$error = curl_error($ch);
curl_close($ch);
if ($errno) {
throw new CurlException($error, $errno);
}
$result = json_decode($responseBody, true);
if (isset($result['generatedAt'])) {
$this->generatedAt = new \DateTime($result['generatedAt']);
unset($result['generatedAt']);
}
return new ApiResponse($statusCode, $responseBody);
}
}

View file

@ -1,336 +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';
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';
/**
* onBeforeOrderAdd
*
* @param mixed $arFields - Order arFields
*/
function onBeforeOrderAdd($arFields = array()) {
$GLOBALS['INTARO_CRM_ORDER_ADD'] = true;
return;
}
/**
* OnSaleBeforeReserveOrder
*
* @param mixed $arFields - Order arFields
*/
function OnSaleBeforeReserveOrder($arFields = array()) {
$GLOBALS['INTARO_CRM_ORDER_RESERVE'] = true;
return;
}
/**
* OnSaleReserveOrder
*
* @param mixed $arFields - Order arFields
*/
function OnSaleReserveOrder($arFields = array()) {
if(isset($GLOBALS['INTARO_CRM_ORDER_RESERVE']) && $GLOBALS['INTARO_CRM_ORDER_RESERVE'])
unset($GLOBALS['INTARO_CRM_ORDER_RESERVE']);
return;
}
/**
* onUpdateOrder
*
* @param mixed $ID - Order id
* @param mixed $arFields - Order arFields
*/
function onUpdateOrder($ID, $arFields) {
if(isset($GLOBALS['INTARO_CRM_ORDER_ADD']) && $GLOBALS['INTARO_CRM_ORDER_ADD'])
return;
if(isset($GLOBALS['INTARO_CRM_ORDER_RESERVE']) && $GLOBALS['INTARO_CRM_ORDER_RESERVE'])
return;
if(isset($GLOBALS['INTARO_CRM_FROM_HISTORY']) && $GLOBALS['INTARO_CRM_FROM_HISTORY'])
return;
if(isset($arFields['LOCKED_BY']) && $arFields['LOCKED_BY'])
return;
if(isset($arFields['CANCELED']))
return;
self::writeDataOnOrderCreate($ID, $arFields);
}
/**
* 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) {
if(isset($GLOBALS['INTARO_CRM_FROM_HISTORY']) && $GLOBALS['INTARO_CRM_FROM_HISTORY'])
return;
if(self::writeDataOnOrderCreate($ID))
COption::SetOptionString(self::$MODULE_ID, self::$CRM_ORDER_LAST_ID, $ID);
else {
$failedIds = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_FAILED_IDS, 0));
if(!$failedIds)
$failedIds = array();
$failedIds[] = $ID;
COption::SetOptionString(self::$MODULE_ID, self::$CRM_ORDER_FAILED_IDS, serialize($failedIds));
}
}
/**
* writeDataOnOrderCreate via api
*
* @param $ID - Order Id
* @param array $arFields
* @return boolean
*/
function writeDataOnOrderCreate($ID, $arFields) {
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;
}
$GLOBALS['INTARO_CRM_FROM_HISTORY'] = 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);
//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));
$optionsSitesList = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_SITES_LIST, 0));
$optionsOrderProps = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_PROPS, 0));
$optionsLegalDetails = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_LEGAL_DETAILS, 0));
$optionsContragentType = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_CONTRAGENT_TYPE, 0));
$optionsCustomFields = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_CUSTOM_FIELDS, 0));
$api = new RetailCrm\RestApi($api_host, $api_key);
$arParams = ICrmOrderActions::clearArr(array(
'optionsOrderTypes' => $optionsOrderTypes,
'optionsDelivTypes' => $optionsDelivTypes,
'optionsPayTypes' => $optionsPayTypes,
'optionsPayStatuses' => $optionsPayStatuses,
'optionsPayment' => $optionsPayment,
'optionsOrderProps' => $optionsOrderProps,
'optionsLegalDetails' => $optionsLegalDetails,
'optionsContragentType' => $optionsContragentType,
'optionsSitesList' => $optionsSitesList,
'optionsCustomFields' => $optionsCustomFields
));
$arOrder = CSaleOrder::GetById($ID);
if (is_array($arFields) && !empty($arFields)) {
$arFieldsNew = array(
'USER_ID' => $arOrder['USER_ID'],
'ID' => $ID,
'PERSON_TYPE_ID' => $arOrder['PERSON_TYPE_ID'],
'CANCELED' => $arOrder['CANCELED'],
'STATUS_ID' => $arOrder['STATUS_ID'],
'DATE_INSERT' => $arOrder['DATE_INSERT'],
'LID' => $arOrder['LID']
);
$arFieldsNew = array_merge($arFieldsNew, $arFields);
$arOrder = $arFieldsNew;
}
if(count($optionsSitesList)>1){
$result = ICrmOrderActions::orderCreate($arOrder, $api, $arParams, true, $optionsSitesList[$arOrder['LID']]);
}
else{
$result = ICrmOrderActions::orderCreate($arOrder, $api, $arParams, true);
}
if(!$result) {
ICrmOrderActions::eventLog('ICrmOrderEvent::writeDataOnOrderCreate', 'ICrmOrderActions::orderCreate', 'error during creating order');
return false;
}
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(isset($GLOBALS['INTARO_CRM_FROM_HISTORY']) && $GLOBALS['INTARO_CRM_FROM_HISTORY'])
return;
if(!$ID || !$cancel)
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 RetailCrm\RestApi($api_host, $api_key);
$order = array();
if($cancel == 'Y') {
$order = array(
'externalId' => (int) $ID,
'status' => $optionsPayStatuses[$cancel.$cancel],
'statusComment' => ICrmOrderActions::toJSON($reason)
);
} else if($cancel == 'N') {
$arOrder = CSaleOrder::GetById((int) $ID);
$order = array(
'externalId' => (int) $ID,
'status' => $optionsPayStatuses[$arOrder['STATUS_ID']],
'managerComment' => $arOrder['COMMENTS']
);
}
try {
$api->orderEdit($order);
} catch (\RetailCrm\Exception\CurlException $e) {
ICrmOrderActions::eventLog(
'ICrmOrderEvent::onSaleCancelOrder', 'RetailCrm\RestApi::orderEdit::CurlException',
$e->getCode() . ': ' . $e->getMessage()
);
}
return true;
}
/**
*
* @param type $ID -- orderId
* @param type $payed -- Y / N - pay order status
* @return boolean
*/
function onSalePayOrder($ID, $payed) {
if(isset($GLOBALS['INTARO_CRM_FROM_HISTORY']) && $GLOBALS['INTARO_CRM_FROM_HISTORY'])
return;
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 RetailCrm\RestApi($api_host, $api_key);
$order = array(
'externalId' => (int) $ID,
'paymentStatus' => $optionsPayment[$payed]
);
$api->orderEdit($order);
try {
$api->orderEdit($order);
} catch (\RetailCrm\Exception\CurlException $e) {
ICrmOrderActions::eventLog(
'ICrmOrderEvent::onSalePayOrder', 'RetailCrm\RestApi::orderEdit::CurlException',
$e->getCode() . ': ' . $e->getMessage()
);
}
return true;
}
/**
*
* @param type $ID -- orderId
* @param type $value -- ACCOUNT_NUMBER
* @return boolean
*/
function onBeforeOrderAccountNumberSet($ID, $value) {
if(isset($GLOBALS['ICRM_ACCOUNT_NUMBER']) && $GLOBALS['ICRM_ACCOUNT_NUMBER'])
return $GLOBALS['ICRM_ACCOUNT_NUMBER'];
return false;
}
}

View file

@ -1,13 +0,0 @@
- Модуль переведен на новую версию API
- Добавлена поддержка реквизитов юр. лиц
- Добавлена многосайтовость
- Добавлена выборочная загрузка заказов из настроек модуля
- Оптимизирована загрузка старых заказов
- Исправлена ошибка со скидками на заказ и товары
- Исправлена ошибка с удалением id товара в заказе
- Исправлена ошибка пустого $_SERVER['SERVER_NAME'] при экспорте каталога
- Исправлена ошибка с неправильной скидкой у товара при наличии копеек
- Исправлена ошибка с пропаданием автоматических служб доставок из настроек модуля
- Исправлена неправельная выгрузка сервисов для служб доставок
- Исправлено не правельное определение местоположения
- Рефакторинг модуля

View file

@ -1,82 +0,0 @@
<?php
set_time_limit(0);
global $APPLICATION;
if (!CModule::IncludeModule("iblock"))
return;
if (!CModule::IncludeModule("catalog"))
return;
if (!CModule::IncludeModule("intaro.intarocrm"))
return;
$rsSites = CSite::GetList($by, $sort, array('ACTIVE' => 'Y'));
while ($ar = $rsSites->Fetch()){
if($ar['DEF'] == 'Y'){
$SERVER_NAME = $ar['SERVER_NAME'];//разделить потом с учетом многосайтовости
}
}
$iblockProperties = Array(
"article" => "article",
"manufacturer" => "manufacturer",
"color" =>"color",
"weight" => "weight",
"size" => "size",
"length" => "length",
"width" => "width",
"height" => "height",
);
$IBLOCK_PROPERTY_SKU = array();
$IBLOCK_PROPERTY_UNIT_SKU = array();
foreach ($iblockProperties as $prop) {
$skuUnitProps = ('IBLOCK_PROPERTY_UNIT_SKU' . "_" . $prop);
$skuUnitProps = $$skuUnitProps;
if (is_array($skuUnitProps)) {
foreach ($skuUnitProps as $iblock => $val) {
$IBLOCK_PROPERTY_UNIT_SKU[$iblock][$prop] = $val;
}
}
$skuProps = ('IBLOCK_PROPERTY_SKU' . "_" . $prop);
$skuProps = $$skuProps;
if (is_array($skuProps)) {
foreach ($skuProps as $iblock => $val) {
$IBLOCK_PROPERTY_SKU[$iblock][$prop] = $val;
}
}
}
$IBLOCK_PROPERTY_PRODUCT = array();
$IBLOCK_PROPERTY_UNIT_PRODUCT = array();
foreach ($iblockProperties as $prop) {
$productUnitProps = "IBLOCK_PROPERTY_UNIT_PRODUCT" . "_" . $prop;
$productUnitProps = $$productUnitProps;
if (is_array($productUnitProps)) {
foreach ($productUnitProps as $iblock => $val) {
$IBLOCK_PROPERTY_UNIT_PRODUCT[$iblock][$prop] = $val;
}
}
$productProps = "IBLOCK_PROPERTY_PRODUCT" . "_" . $prop;
$productProps = $$productProps;
if (is_array($productProps)) {
foreach ($productProps as $iblock => $val) {
$IBLOCK_PROPERTY_PRODUCT[$iblock][$prop] = $val;
}
}
}
$loader = new ICMLLoader();
$loader->iblocks = $IBLOCK_EXPORT;
$loader->propertiesSKU = $IBLOCK_PROPERTY_SKU;
$loader->propertiesUnitSKU = $IBLOCK_PROPERTY_UNIT_SKU;
$loader->propertiesProduct = $IBLOCK_PROPERTY_PRODUCT;
$loader->propertiesUnitProduct = $IBLOCK_PROPERTY_UNIT_PRODUCT;
$loader->filename = $SETUP_FILE_NAME;
$loader->serverName = $SERVER_NAME;
$loader->application = $APPLICATION;
$loader->loadPurchasePrice = $LOAD_PURCHASE_PRICE == 'Y';
$loader->Load();

View file

@ -1,700 +0,0 @@
<?
$iblockProperties = Array(
"article" => "article",
"manufacturer" => "manufacturer",
"color" =>"color",
"size" => "size",
"weight" => "weight",
"length" => "length",
"width" => "width",
"height" => "height",
);
if(!check_bitrix_sessid()) return;
__IncludeLang(GetLangFileName($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/intaro.intarocrm/lang/", "/icml_export_setup.php"));
$MODULE_ID = 'intaro.intarocrm';
$CRM_CATALOG_BASE_PRICE = 'catalog_base_price';
$basePriceId = COption::GetOptionString($MODULE_ID, $CRM_CATALOG_BASE_PRICE, 1);
$arResult['PRICE_TYPES'] = array();
$dbPriceType = CCatalogGroup::GetList(
array("SORT" => "ASC"), array(), array(), array(), array("ID", "NAME", "BASE")
);
while ($arPriceType = $dbPriceType->Fetch()) {
$arResult['PRICE_TYPES'][$arPriceType['ID']] = $arPriceType;
}
if (($ACTION == 'EXPORT' || $ACTION == 'EXPORT_EDIT' || $ACTION == 'EXPORT_COPY') && $STEP == 1)
{
if (isset($arOldSetupVars['SETUP_FILE_NAME']))
$SETUP_FILE_NAME = $arOldSetupVars['SETUP_FILE_NAME'];
if (isset($arOldSetupVars['LOAD_PURCHASE_PRICE']))
$LOAD_PURCHASE_PRICE = $arOldSetupVars['LOAD_PURCHASE_PRICE'];
if (isset($arOldSetupVars['SETUP_PROFILE_NAME']))
$SETUP_PROFILE_NAME = $arOldSetupVars['SETUP_PROFILE_NAME'];
if (isset($arOldSetupVars['IBLOCK_EXPORT']))
$IBLOCK_EXPORT = $arOldSetupVars['IBLOCK_EXPORT'];
$IBLOCK_PROPERTY_SKU = array();
$IBLOCK_PROPERTY_UNIT_SKU = array();
foreach ($iblockProperties as $prop) {
foreach ($arOldSetupVars['IBLOCK_PROPERTY_SKU'. '_' . $prop] as $iblock => $val) {
$IBLOCK_PROPERTY_SKU[$iblock][$prop] = $val;
}
foreach ($arOldSetupVars['IBLOCK_PROPERTY_UNIT_SKU'. '_' . $prop] as $iblock => $val) {
$IBLOCK_PROPERTY_UNIT_SKU[$iblock][$prop] = $val;
}
}
$IBLOCK_PROPERTY_PRODUCT = array();
$IBLOCK_PROPERTY_UNIT_PRODUCT = array();
foreach ($iblockProperties as $prop) {
foreach ($arOldSetupVars['IBLOCK_PROPERTY_PRODUCT'. '_' . $prop] as $iblock => $val) {
$IBLOCK_PROPERTY_PRODUCT[$iblock][$prop] = $val;
}
foreach ($arOldSetupVars['IBLOCK_PROPERTY_UNIT_PRODUCT'. '_' . $prop] as $iblock => $val) {
$IBLOCK_PROPERTY_UNIT_PRODUCT[$iblock][$prop] = $val;
}
}
}
if ($STEP>1)
{
if (strlen($SETUP_FILE_NAME)<=0)
{
$arSetupErrors[] = GetMessage("CET_ERROR_NO_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)
{
?>
<style type="text/css">
.iblock-export-table-display-none {
display: none;
}
</style>
<form method="post" action="<?php echo $APPLICATION->GetCurPage(); ?>" >
<?if ($ACTION == 'EXPORT_EDIT' || $ACTION == 'EXPORT_COPY')
{
?><input type="hidden" name="PROFILE_ID" value="<? echo intval($PROFILE_ID); ?>"><?
}
?>
<h3><?=GetMessage("SETTINGS_INFOBLOCK");?></h3>
<font class="text"><?=GetMessage("EXPORT_CATALOGS");?><br><br></font>
<?
if (!isset($IBLOCK_EXPORT) || !is_array($IBLOCK_EXPORT))
{
$IBLOCK_EXPORT = array();
}
$iblockPropertiesName = Array(
"article" => GetMessage("PROPERTY_ARTICLE_HEADER_NAME"),
"manufacturer" => GetMessage("PROPERTY_MANUFACTURER_HEADER_NAME"),
"color" => GetMessage("PROPERTY_COLOR_HEADER_NAME"),
"size" => GetMessage("PROPERTY_SIZE_HEADER_NAME"),
"weight" => GetMessage("PROPERTY_WEIGHT_HEADER_NAME"),
"length" => GetMessage("PROPERTY_LENGTH_HEADER_NAME"),
"width" => GetMessage("PROPERTY_WIDTH_HEADER_NAME"),
"height" => GetMessage("PROPERTY_HEIGHT_HEADER_NAME"),
);
$iblockFieldsName = Array(
"weight" => Array("code" => "catalog_size" , "name" => GetMessage("SELECT_WEIGHT_PROPERTY_NAME"), 'unit' => 'mass'),
"length" => Array("code" => "catalog_length" , "name" => GetMessage("SELECT_LENGTH_PROPERTY_NAME"), 'unit' => 'length'),
"width" => Array("code" => "catalog_width" , "name" => GetMessage("SELECT_WIDTH_PROPERTY_NAME"), 'unit' => 'length'),
"height" => Array("code" => "catalog_height" , "name" => GetMessage("SELECT_HEIGHT_PROPERTY_NAME"), 'unit' => 'length'),
);
$iblockPropertiesHint = Array(
"article" => Array("ARTICLE", "ART", "ARTNUMBER", "ARTICUL", "ARTIKUL"),
"manufacturer" => Array("MANUFACTURER", "PROISVODITEL", "PROISVOD", "PROISV"),
"color" => Array("COLOR", "CVET"),
"size" => Array("SIZE", "RAZMER"),
"weight" => Array("WEIGHT", "VES", "VEC"),
"length" => Array("LENGTH", "DLINA"),
"width" => Array("WIDTH", "SHIRINA"),
"height" => Array("HEIGHT", "VISOTA"),
);
$units = Array(
'length' => Array(
'mm' => GetMessage("UNIT_MEASUREMENT_MM"),
'cm' => GetMessage("UNIT_MEASUREMENT_CM"),
'm' => GetMessage("UNIT_MEASUREMENT_M"),
),
'mass' => Array(
'mg' => GetMessage("UNIT_MEASUREMENT_MG"),
'g' => GetMessage("UNIT_MEASUREMENT_G"),
'kg' => GetMessage("UNIT_MEASUREMENT_KG"),
)
);
$hintUnit = Array(
'length' => 'mm',
'mass' => 'g'
);
$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 ($iblock = $db_res->Fetch())
{
if ($arCatalog = CCatalog::GetByIDExt($iblock["ID"]))
{
if($arCatalog['CATALOG_TYPE'] == "D" || $arCatalog['CATALOG_TYPE'] == "X" || $arCatalog['CATALOG_TYPE'] == "P")
{
$propertiesSKU = null;
if ($arCatalog['CATALOG_TYPE'] == "X" || $arCatalog['CATALOG_TYPE'] == "P")
{
$iblockOffer = CCatalogSKU::GetInfoByProductIBlock($iblock["ID"]);
$db_properties = CIBlock::GetProperties($iblockOffer['IBLOCK_ID'], Array());
while($prop = $db_properties->Fetch())
$propertiesSKU[] = $prop;
$oldPropertySKU = null;
if (isset($IBLOCK_PROPERTY_SKU[$iblock['ID']])) {
foreach ($iblockPropertiesName as $key => $prop) {
$oldPropertySKU[$key] = $IBLOCK_PROPERTY_SKU[$iblock['ID']][$key];
}
}
$oldPropertyUnitSKU = null;
if (isset($IBLOCK_PROPERTY_UNIT_SKU[$iblock['ID']])) {
foreach ($iblockPropertiesName as $key => $prop) {
$oldPropertyUnitSKU[$key] = $IBLOCK_PROPERTY_UNIT_SKU[$iblock['ID']][$key];
}
}
}
$propertiesProduct = null;
$db_properties = CIBlock::GetProperties($iblock['ID'], Array());
while($prop = $db_properties->Fetch())
$propertiesProduct[] = $prop;
$oldPropertyProduct = null;
if (isset($IBLOCK_PROPERTY_PRODUCT[$iblock['ID']])) {
foreach ($iblockPropertiesName as $key => $prop) {
$oldPropertyProduct[$key] = $IBLOCK_PROPERTY_PRODUCT[$iblock['ID']][$key];
}
}
$oldPropertyUnitProduct = null;
if (isset($IBLOCK_PROPERTY_UNIT_PRODUCT[$iblock['ID']])) {
foreach ($iblockPropertiesName as $key => $prop) {
$oldPropertyUnitProduct[$key] = $IBLOCK_PROPERTY_UNIT_PRODUCT[$iblock['ID']][$key];
}
}
$arSiteList = array();
$rsSites = CIBlock::GetSite($iblock["ID"]);
while ($arSite = $rsSites->Fetch())
{
$arSiteList[] = $arSite["SITE_ID"];
}
if (count($IBLOCK_EXPORT) != 0)
$boolExport = (in_array($iblock['ID'], $IBLOCK_EXPORT));
else
$boolExport = true;
$arIBlockList[] = array(
'ID' => $iblock['ID'],
'NAME' => $iblock['NAME'],
'IBLOCK_TYPE_ID' => $iblock['IBLOCK_TYPE_ID'],
'IBLOCK_EXPORT' => $boolExport,
'PROPERTIES_SKU' => $propertiesSKU,
'PROPERTIES_PRODUCT' => $propertiesProduct,
'OLD_PROPERTY_SKU_SELECT' => $oldPropertySKU,
'OLD_PROPERTY_UNIT_SKU_SELECT' => $oldPropertyUnitSKU,
'OLD_PROPERTY_PRODUCT_SELECT' => $oldPropertyProduct,
'OLD_PROPERTY_UNIT_PRODUCT_SELECT' => $oldPropertyUnitProduct,
'SITE_LIST' => '('.implode(' ',$arSiteList).')',
);
if ($boolExport)
$intCountChecked++;
$intCountAvailIBlock++;
}
}
}
if (count($IBLOCK_EXPORT) != 0) {
if ($intCountChecked == $intCountAvailIBlock)
$boolAll = true;
} else {
$intCountChecked = $intCountAvailIBlock;
$boolAll = true;
}
?>
<font class="text" style="font-weight: bold;"><?=GetMessage("CHECK_ALL_INFOBLOCKS");?></font>
<input
style="vertical-align: middle;"
type="checkbox"
name="icml_export_all"
id="icml_export_all"
value="Y"
onclick="checkAll(this,<? echo $intCountAvailIBlock; ?>);"
<? echo ($boolAll ? ' checked' : ''); ?>>
</br>
</br>
<div>
<? $checkBoxCounter = 0;?>
<? foreach ($arIBlockList as $key => $arIBlock):?>
<div>
<div>
<font class="text" style="font-weight: bold;"><? echo htmlspecialcharsex("[".$arIBlock["IBLOCK_TYPE_ID"]."] ".$arIBlock["NAME"]." ".$arIBlock['SITE_LIST']); ?></font>
<input
type="checkbox"
name="IBLOCK_EXPORT[<?=$arIBlock["ID"]?>]"
id="IBLOCK_EXPORT<?=++$checkBoxCounter?>"
value="<?=$arIBlock["ID"]?>"
<? if ($arIBlock['IBLOCK_EXPORT']) echo " checked"; ?>
onclick="checkOne(this,<? echo $intCountAvailIBlock; ?>);"
>
</div>
<br>
<div id="IBLOCK_EXPORT_TABLE<?=$checkBoxCounter?>">
<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>
<? 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>
<? endif;?>
</tr>
</thead>
<tbody>
<? foreach ($iblockPropertiesName as $key => $property): ?>
<? $productSelected = false;?>
<tr class="adm-list-table-row">
<td class="adm-list-table-cell">
<? echo htmlspecialcharsex($property); ?>
</td>
<td class="adm-list-table-cell">
<select
style="width: 200px;"
id="IBLOCK_PROPERTY_PRODUCT_<?=$key?><?=$arIBlock["ID"]?>"
name="IBLOCK_PROPERTY_PRODUCT_<?=$key?>[<?=$arIBlock["ID"]?>]"
class="property-export"
onchange="propertyChange(this);">
<option value=""></option>
<?if (version_compare(SM_VERSION, '14.0.0', '>=') && array_key_exists($key, $iblockFieldsName) && $arIBlock['PROPERTIES_SKU'] == null) :?>
<optgroup label="<?=GetMessage("SELECT_FIELD_NAME");?>">
<? foreach ($iblockFieldsName as $keyField => $field): ?>
<? if ($keyField == $key): ?>
<option value="<?=$field['code'];?>"
<?
if ($arIBlock['OLD_PROPERTY_PRODUCT_SELECT'] != null) {
if ($field['code'] == $arIBlock['OLD_PROPERTY_PRODUCT_SELECT'][$key] ) {
echo " selected";
$productSelected = true;
}
} else {
foreach ($iblockPropertiesHint[$key] as $hint) {
if ($field['code'] == $hint ) {
echo " selected";
$productSelected = true;
break;
}
}
}
?>
>
<?=$field['name'];?>
</option>
<? endif; ?>
<? endforeach;?>
</optgroup>
<optgroup label="<?=GetMessage("SELECT_PROPERTY_NAME");?>">
<?endif; ?>
<? foreach ($arIBlock['PROPERTIES_PRODUCT'] as $prop): ?>
<option value="<?=$prop['CODE'] ?>"
<?
if ($arIBlock['OLD_PROPERTY_PRODUCT_SELECT'] != null) {
if ($prop["CODE"] == $arIBlock['OLD_PROPERTY_PRODUCT_SELECT'][$key] ) {
echo " selected";
$productSelected = true;
}
} else {
foreach ($iblockPropertiesHint[$key] as $hint) {
if ($prop["CODE"] == $hint ) {
echo " selected";
$productSelected = true;
break;
}
}
}
?>
>
<?=$prop["NAME"];?>
</option>
<? endforeach;?>
<?if (version_compare(SM_VERSION, '14.0.0', '>=') && array_key_exists($key, $iblockFieldsName)){?>
</optgroup>
<?}?>
</select>
<?if (array_key_exists($key, $iblockFieldsName)) :?>
<select
style="width: 100px; margin-left: 50px;"
id="IBLOCK_PROPERTY_UNIT_PRODUCT_<?=$key?><?=$arIBlock["ID"]?>"
name="IBLOCK_PROPERTY_UNIT_PRODUCT_<?=$key?>[<?=$arIBlock["ID"]?>]"
>
<? foreach ($units as $unitTypeName => $unitType): ?>
<? if ($unitTypeName == $iblockFieldsName[$key]['unit']): ?>
<? foreach ($unitType as $keyUnit => $unit): ?>
<option value="<?=$keyUnit;?>"
<?
if ($arIBlock['OLD_PROPERTY_UNIT_PRODUCT_SELECT'] != null) {
if ($keyUnit == $arIBlock['OLD_PROPERTY_UNIT_PRODUCT_SELECT'][$key] ) {
echo " selected";
}
} else {
if ($keyUnit == $hintUnit[$unitTypeName]) {
echo " selected";
}
}
?>
>
<?=$unit?>
</option>
<? endforeach;?>
<?endif; ?>
<? endforeach;?>
</select>
<?endif; ?>
</td>
<? if ($arIBlock['PROPERTIES_SKU'] != null): ?>
<td class="adm-list-table-cell">
<select
style="width: 200px;"
id="IBLOCK_PROPERTY_SKU_<?=$key?><?=$arIBlock["ID"]?>"
name="IBLOCK_PROPERTY_SKU_<?=$key?>[<?=$arIBlock["ID"]?>]"
class="property-export"
onchange="propertyChange(this);">
<option value=""></option>
<?if (version_compare(SM_VERSION, '14.0.0', '>=') && array_key_exists($key, $iblockFieldsName)) :?>
<optgroup label="<?=GetMessage("SELECT_FIELD_NAME");?>">
<? foreach ($iblockFieldsName as $keyField => $field): ?>
<? if ($keyField == $key) :?>
<option value="<?=$field['code'];?>"
<?
if (!$productSelected) {
if ($arIBlock['OLD_PROPERTY_SKU_SELECT'] != null) {
if ($field['code'] == $arIBlock['OLD_PROPERTY_SKU_SELECT'][$key] ) {
echo " selected";
}
} else {
foreach ($iblockPropertiesHint[$key] as $hint) {
if ($field['code'] == $hint ) {
echo " selected";
break;
}
}
}
}
?>
>
<?=$field['name'];?>
</option>
<? endif; ?>
<? endforeach;?>
</optgroup>
<optgroup label="<?=GetMessage("SELECT_PROPERTY_NAME");?>">
<? endif; ?>
<? foreach ($arIBlock['PROPERTIES_SKU'] as $prop): ?>
<option value="<?=$prop['CODE'] ?>"
<?
if (!$productSelected) {
if ($arIBlock['OLD_PROPERTY_SKU_SELECT'] != null) {
if ($prop["CODE"] == $arIBlock['OLD_PROPERTY_SKU_SELECT'][$key] ) {
echo " selected";
}
} else {
foreach ($iblockPropertiesHint[$key] as $hint) {
if ($prop["CODE"] == $hint ) {
echo " selected";
break;
}
}
}
}
?>
>
<?=$prop["NAME"];?>
</option>
<? endforeach;?>
<? if (version_compare(SM_VERSION, '14.0.0', '>=') && array_key_exists($key, $iblockFieldsName)) : ?>
</optgroup>
<? endif; ?>
</select>
<?if (array_key_exists($key, $iblockFieldsName)) :?>
<select
style="width: 100px; margin-left: 50px;"
id="IBLOCK_PROPERTY_UNIT_SKU_<?=$key?><?=$arIBlock["ID"]?>"
name="IBLOCK_PROPERTY_UNIT_SKU_<?=$key?>[<?=$arIBlock["ID"]?>]"
>
<? foreach ($units as $unitTypeName => $unitType): ?>
<? if ($unitTypeName == $iblockFieldsName[$key]['unit']): ?>
<? foreach ($unitType as $keyUnit => $unit): ?>
<option value="<?=$keyUnit;?>"
<?
if ($arIBlock['OLD_PROPERTY_UNIT_SKU_SELECT'] != null) {
if ($keyUnit == $arIBlock['OLD_PROPERTY_UNIT_SKU_SELECT'][$key] ) {
echo " selected";
}
} else {
if ($keyUnit == $hintUnit[$unitTypeName]) {
echo " selected";
}
}
?>
>
<?=$unit?>
</option>
<? endforeach;?>
<?endif; ?>
<? endforeach;?>
</select>
<?endif; ?>
</td>
<? endif;?>
</tr>
<? endforeach;?>
</tbody>
</table>
<br>
<br>
</div>
</div>
<? endforeach;?>
</div>
<input type="hidden" name="count_checked" id="count_checked" value="<? echo $intCountChecked; ?>">
<br>
<h3><?=GetMessage("SETTINGS_EXPORT");?></h3>
<font class="text"><?=GetMessage("FILENAME");?><br><br></font>
<input type="text" name="SETUP_FILE_NAME"
value="<?=htmlspecialcharsbx(strlen($SETUP_FILE_NAME) > 0 ?
$SETUP_FILE_NAME :
(COption::GetOptionString(
'catalog',
'export_default_path',
'/bitrix/catalog_export/'))
.'intarocrm'/* .mt_rand(0, 999999) */.'.xml'
); ?>" size="50">
<br>
<br>
<font class="text"><?=GetMessage("LOAD_PURCHASE_PRICE");?>&nbsp;</font>
<input type="checkbox" name="LOAD_PURCHASE_PRICE" value="Y" <?= $LOAD_PURCHASE_PRICE == 'Y' ? 'checked' : '' ?>>
<br>
<br>
<br>
<font class="text"><?=GetMessage("BASE_PRICE");?>&nbsp;</font>
<select name="price-types" class="typeselect">
<option value=""></option>
<?php foreach($arResult['PRICE_TYPES'] as $priceType): ?>
<option value="<?php echo $priceType['ID']; ?>"
<?php if($priceType['ID'] == $basePriceId) echo 'selected'; ?>>
<?php echo $priceType['NAME']; ?>
</option>
<?php endforeach; ?>
</select>
<br>
<br>
<br>
<?if ($ACTION=="EXPORT_SETUP" || $ACTION == 'EXPORT_EDIT' || $ACTION == 'EXPORT_COPY'):?>
<font class="text"><?=GetMessage("PROFILE_NAME");?><br><br></font>
<input
type="text"
name="SETUP_PROFILE_NAME"
value="<?echo htmlspecialchars($SETUP_PROFILE_NAME)?>"
size="50">
<br>
<br>
<br>
<?endif;?>
<script type="text/javascript" src="/bitrix/js/main/jquery/jquery-1.7.min.js"></script>
<script type="text/javascript">
function checkAll(obj,cnt)
{
for (i = 0; i < cnt; i++)
{
if (obj.checked)
BX.removeClass('IBLOCK_EXPORT_TABLE'+(i+1),"iblock-export-table-display-none");
}
var table = BX(obj.id.replace('IBLOCK_EXPORT','IBLOCK_EXPORT_TABLE'));
if (obj.checked)
BX.removeClass(table,"iblock-export-table-display-none");
var 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 (i = 0; i < cnt; i++)
{
BX('IBLOCK_EXPORT_TABLE'+(i+1)).style.opacity = state.opacity/100;
}
},
complete : function() {
for (i = 0; i < cnt; i++)
{
if (!obj.checked)
BX.addClass('IBLOCK_EXPORT_TABLE'+(i+1),"iblock-export-table-display-none");
}
}
});
easing.animate();
var boolCheck = obj.checked;
for (i = 0; i < cnt; i++)
{
BX('IBLOCK_EXPORT'+(i+1)).checked = boolCheck;
}
BX('count_checked').value = (boolCheck ? cnt : 0);
};
function checkOne(obj,cnt)
{
var table = BX(obj.id.replace('IBLOCK_EXPORT','IBLOCK_EXPORT_TABLE'));
if (obj.checked)
BX.removeClass(table,"iblock-export-table-display-none");
var 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();
var boolCheck = obj.checked;
var intCurrent = parseInt(BX('count_checked').value);
intCurrent += (boolCheck ? 1 : -1);
BX('icml_export_all').checked = (intCurrent < cnt ? false : true);
BX('count_checked').value = intCurrent;
};
function propertyChange(obj)
{
if (BX(obj.id).value !== 'none') {
if (obj.id.indexOf("SKU") !== -1)
BX(obj.id.replace('SKU','PRODUCT')).value = 'none';
else
BX(obj.id.replace('PRODUCT','SKU')).value = 'none';
}
};
</script>
<?//Следующие переменные должны быть обязательно установлены?>
<?=bitrix_sessid_post();?>
<?
$vals = "LOAD_PURCHASE_PRICE,SETUP_FILE_NAME,IBLOCK_EXPORT";
foreach ($iblockProperties as $val) {
$vals .= ",IBLOCK_PROPERTY_SKU_" . $val;
$vals .= ",IBLOCK_PROPERTY_UNIT_SKU_" . $val;
$vals .= ",IBLOCK_PROPERTY_PRODUCT_" . $val;
$vals .= ",IBLOCK_PROPERTY_UNIT_PRODUCT_" . $val;
}
?>
<input type="hidden" name="lang" value="<?echo LANGUAGE_ID ?>">
<input type="hidden" name="ACT_FILE" value="<?echo htmlspecialcharsbx($_REQUEST["ACT_FILE"]) ?>">
<input type="hidden" name="ACTION" value="<?echo htmlspecialcharsbx($ACTION) ?>">
<input type="hidden" name="STEP" value="<?echo intval($STEP) + 1 ?>">
<input type="hidden" name="SETUP_FIELDS_LIST" value="<? echo $vals ?>">
<input type="submit" value="<?echo ($ACTION=="EXPORT")?GetMessage("CET_EXPORT"):GetMessage("CET_SAVE")?>">
</form>
<?
}
elseif ($STEP==2)
{
COption::SetOptionString($MODULE_ID, $CRM_CATALOG_BASE_PRICE, htmlspecialchars(trim($_POST['price-types'])));
$FINITE = true;
}
?>

View file

@ -1,14 +0,0 @@
<?php
CModule::AddAutoloadClasses(
'intaro.intarocrm', // module name
array (
'RestNormalizer' => 'classes/general/RestNormalizer.php',
'RetailCrm\RestApi' => 'classes/general/RestApi.php',
'RetailCrm\Response\ApiResponse' => 'classes/general/Response/ApiResponse.php',
'ICrmOrderActions' => 'classes/general/ICrmOrderActions.php',
'ICMLLoader' => 'classes/general/ICMLLoader.php',
'ICrmOrderEvent' => 'classes/general/events/ICrmOrderEvent.php',
'RetailCrm\Exception\InvalidJsonException' => 'classes/general/Exception/InvalidJsonException.php',
'RetailCrm\Exception\CurlException' => 'classes/general/Exception/CurlException.php',
)
);

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -1,261 +0,0 @@
<?php
IncludeModuleLangFile(__FILE__);
$MODULE_ID = 'intaro.intarocrm';
$CRM_API_HOST_OPTION = 'api_host';
$api_host = COption::GetOptionString($MODULE_ID, $CRM_API_HOST_OPTION, 0);
//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'
);
?>
<style type="text/css">
input[name="update"] {
right:2px;
position: absolute !important;
top:3px;
}
</style>
<script type="text/javascript" src="/bitrix/js/main/jquery/jquery-1.7.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('input[name="update"]').live('click', function() {
$('input[name="step"]').val(2);
BX.showWait();
var updButton = this;
// hide next step button
$(updButton).css('opacity', '0.5').attr('disabled', 'disabled');
var handlerUrl = $(this).parents('form').attr('action');
var data = $(this).parents('form').serialize() + '&ajax=1';
$.ajax({
type: 'POST',
url: handlerUrl,
data: data,
dataType: 'json',
success: function(response) {
if(response.success) {
$.each(response.result, function(i,item){
$('select[name="' + i + '"]').replaceWith(item);
});
}
BX.closeWait();
$(updButton).css('opacity', '1').removeAttr('disabled');
$('input[name="step"]').val(3);
if(!response.success)
alert('<?php echo GetMessage('MESS_5'); ?>');
},
error: function () {
BX.closeWait();
$(updButton).css('opacity', '1').removeAttr('disabled');
$('input[name="step"]').val(3);
alert('<?php echo GetMessage('MESS_5'); ?>');
}
});
return false;
});
$('input[name="delivery-types-export"]').click(function() {
if($(this).val() === 'true')
$('tr.delivery-types').hide('slow');
else if($(this).val() === 'false')
$('tr.delivery-types').show('slow');
});
});
</script>
<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" style="position:relative;">
<b><?php echo GetMessage('STEP_NAME'); ?></b>
<input type="submit" name="update" value="<?php echo GetMessage('UPDATE_CATS'); ?>" class="adm-btn-save">
</td>
</tr>
<tr align="center">
<td colspan="2"><b><?php echo GetMessage('INFO_1'); ?></b></td>
</tr>
<tr align="center">
<td colspan="2"><?php echo GetMessage('INFO_2') . " " . "<a href='". $api_host ."/admin/statuses' target=_blank>" . GetMessage('URL_1') . "</a>" . " " . 'retailCRM.'; ?></td>
</tr>
<tr align="center">
<td colspan="2"><?php echo GetMessage('INFO_3'); ?></td>
</tr>
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('DELIVERY_TYPES_LIST'); ?></b></td>
</tr>
<tr class="heading">
<td width="50%" class="adm-detail-content-cell-l">
<label><input type="radio" name="delivery-types-export" value="true" checked> <?php echo GetMessage('DELIV_TYPES_EXPORT'); ?></label>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<label><input type="radio" name="delivery-types-export" value="false"> <?php echo GetMessage('DELIV_TYPES_EXPORT_F'); ?></label>
</td>
</tr>
<?php foreach($arResult['bitrixDeliveryTypesList'] as $bitrixDeliveryType): ?>
<tr class="delivery-types" style="display: none;">
<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 $APPLICATION->ConvertCharset($orderStatusGroup['name'], 'utf-8', SITE_CHARSET); ?>">
<?php foreach($orderStatusGroup['statuses'] as $payment): ?>
<?php if(isset($arResult['paymentList'][$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 endif; ?>
<?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,188 +0,0 @@
<?php
if (!check_bitrix_sessid())
return;
IncludeModuleLangFile(__FILE__);
$defaultOrderProps = array(
1 => array(
'fio' => 'FIO',
'index' => 'ZIP',
'text' => 'ADDRESS',
'phone' => 'PHONE',
'email' => 'EMAIL'
),
2 => array(
'fio' => 'FIO',
'index' => 'ZIP',
'text' => 'ADDRESS',
'phone' => 'PHONE',
'email' => 'EMAIL'
)
);
?>
<script type="text/javascript" src="/bitrix/js/main/jquery/jquery-1.7.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('input.addr').change(function(){
splitName = $(this).attr('name').split('-');
orderType = splitName[2];
if(parseInt($(this).val()) === 1)
$('tr.address-detail-' + orderType).show('slow');
else if(parseInt($(this).val()) === 0)
$('tr.address-detail-' + orderType).hide('slow');
});
$('tr.contragent-type select').change(function(){
splitName = $(this).attr('name').split('-');
contragentType = $(this).val();
orderType = splitName[2];
$('tr.legal-detail-' + orderType).hide();
$('.legal-detail-title-' + orderType).hide();
$('tr.legal-detail-' + orderType).each(function(){
if($(this).hasClass(contragentType)){
$(this).show();
$('.legal-detail-title-' + orderType).show();
}
});
});
});
</script>
<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="4">
<input type="hidden" name="continue" 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 class="heading">
<td colspan="2"><b><?php echo GetMessage('ORDER_PROPS'); ?></b></td>
</tr>
<tr align="center">
<td colspan="2"><b><?php echo GetMessage('INFO_2'); ?></b></td>
</tr>
<?php foreach($arResult['bitrixOrderTypesList'] as $bitrixOrderType): ?>
<tr class="heading">
<td colspan="2"><b><?php echo GetMessage('ORDER_TYPE_INFO') . ' ' . $bitrixOrderType['NAME']; ?></b></td>
</tr>
<tr class="contragent-type">
<td width="50%" class="adm-detail-content-cell-l">
<?php echo GetMessage('CONTRAGENT_TYPE'); ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="contragent-type-<?php echo $bitrixOrderType['ID']; ?>" class="typeselect">
<?php foreach ($arResult['contragentType'] as $contragentType): ?>
<option value="<?php echo $contragentType["ID"]; ?>" <?php if ($optionsContragentType[$bitrixOrderType['ID']] == $contragentType['ID']) echo 'selected'; ?>>
<?php echo $contragentType["NAME"]; ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php $countProps = 0; foreach($arResult['orderProps'] as $orderProp): ?>
<?php if($orderProp['ID'] == 'text'): ?>
<tr class="heading">
<td colspan="2" style="background-color: transparent;">
<b>
<label><input class="addr" type="radio" name="address-detail-<?php echo $bitrixOrderType['ID']; ?>" value="0" <?php if(count($defaultOrderProps[$bitrixOrderType['ID']]) < 6) echo "checked"; ?>><?php echo GetMessage('ADDRESS_SHORT'); ?></label>
<label><input class="addr" type="radio" name="address-detail-<?php echo $bitrixOrderType['ID']; ?>" value="1" <?php if(count($defaultOrderProps[$bitrixOrderType['ID']]) > 5) echo "checked"; ?>><?php echo GetMessage('ADDRESS_FULL'); ?></label>
</b>
</td>
</tr>
<?php endif; ?>
<tr <?php if ($countProps > 3) echo 'class="address-detail-' . $bitrixOrderType['ID'] . '"'; if(($countProps > 3) && (count($defaultOrderProps[$bitrixOrderType['ID']]) < 6)) echo 'style="display:none;"';?>>
<td width="50%" class="adm-detail-content-cell-l" name="<?php echo $orderProp['ID']; ?>">
<?php echo $orderProp['NAME']; ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="order-prop-<?php echo $orderProp['ID'] . '-' . $bitrixOrderType['ID']; ?>" class="typeselect">
<option value=""></option>
<?php foreach ($arResult['arProp'][$bitrixOrderType['ID']] as $arProp): ?>
<option value="<?php echo $arProp['CODE']; ?>" <?php if ($defaultOrderProps[$bitrixOrderType['ID']][$orderProp['ID']] == $arProp['CODE']) echo 'selected'; ?>>
<?php echo $arProp['NAME']; ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php $countProps++; endforeach; ?>
<?if (isset($arResult['customFields']) && count($arResult['customFields']) > 0):?>
<tr class="heading custom-detail-title">
<td colspan="2" style="background-color: transparent;">
<b>
<?=GetMessage("ORDER_CUSTOM"); ?>
</b>
</td>
</tr>
<?foreach($arResult['customFields'] as $customFields):?>
<tr class="custom-detail-<?=$customFields['ID'];?>">
<td width="50%" class="" name="">
<?=$customFields['NAME']; ?>
</td>
<td width="50%" class="">
<select name="custom-fields-<?=$customFields['ID'] . '-' . $bitrixOrderType['ID']; ?>" class="typeselect">
<option value=""></option>
<?foreach ($arResult['arProp'][$bitrixOrderType['ID']] as $arProp):?>
<option value="<?=$arProp['CODE']?>" <?php if ($optionsCustomFields[$bitrixOrderType['ID']][$customFields['ID']] == $arProp['CODE']) echo 'selected'; ?>>
<?=$arProp['NAME']; ?>
</option>
<?endforeach;?>
</select>
</td>
</tr>
<?endforeach;?>
<?endif;?>
<tr class="heading legal-detail-title-<?php echo $bitrixOrderType['ID'];?>" style="display:none">
<td colspan="2" style="background-color: transparent;">
<b>
<?php echo GetMessage("ORDER_LEGAL_INFO"); ?>
</b>
</td>
</tr>
<?php foreach($arResult['legalDetails'] as $legalDetails): ?>
<tr class="legal-detail-<?php echo $bitrixOrderType['ID'];?> <?php foreach($legalDetails['GROUP'] as $gr) echo $gr . ' ';?>" style="display:none">
<td width="50%" class="adm-detail-content-cell-l">
<?php echo $legalDetails['NAME']; ?>
</td>
<td width="50%" class="adm-detail-content-cell-r">
<select name="legal-detail-<?php echo $legalDetails['ID'] . '-' . $bitrixOrderType['ID']; ?>" class="typeselect">
<option value=""></option>
<?php foreach ($arResult['arProp'][$bitrixOrderType['ID']] as $arProp): ?>
<option value="<?php echo $arProp['CODE']; ?>" <?php if ($optionsLegalDetails[$bitrixOrderType['ID']][$legalDetails['ID']] == $arProp['CODE']) echo 'selected'; ?>>
<?php echo $arProp['NAME']; ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
<?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; visible: none;">
<input type="submit" name="back" value="<?php echo GetMessage("MOD_PREV_STEP"); ?>" class="adm-btn-save">
</div>
</div>
</form>
</div>

View file

@ -1,607 +0,0 @@
<?php
if(!check_bitrix_sessid()) return;
IncludeModuleLangFile(__FILE__);
__IncludeLang(GetLangFileName($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/intaro.intarocrm/lang/", "/icml_export_setup.php"));
?>
<h3><?=GetMessage("EXPORT_CATALOGS_INFO");?></h3>
<?php
if(isset($arResult['errCode']) && $arResult['errCode'])
echo CAdminMessage::ShowMessage(GetMessage($arResult['errCode']));
global $oldValues;
if (!empty($oldValues)) {
$IBLOCK_EXPORT = $oldValues['IBLOCK_EXPORT'];
$IBLOCK_PROPERTY_SKU = $oldValues['IBLOCK_PROPERTY_SKU'];
$IBLOCK_PROPERTY_UNIT_SKU = $oldValues['IBLOCK_PROPERTY_UNIT_SKU'];
$IBLOCK_PROPERTY_PRODUCT = $oldValues['IBLOCK_PROPERTY_PRODUCT'];
$IBLOCK_PROPERTY_UNIT_PRODUCT = $oldValues['IBLOCK_PROPERTY_UNIT_PRODUCT'];
$SETUP_FILE_NAME = $oldValues['SETUP_FILE_NAME'];
$SETUP_PROFILE_NAME = $oldValues['SETUP_PROFILE_NAME'];
}
?>
<style type="text/css">
.iblock-export-table-display-none {
display: none;
}
</style>
<form method="post" action="<?php echo $APPLICATION->GetCurPage(); ?>" >
<h3><?=GetMessage("SETTINGS_INFOBLOCK");?></h3>
<font class="text"><?=GetMessage("EXPORT_CATALOGS");?><br><br></font>
<?
if (!isset($IBLOCK_EXPORT) || !is_array($IBLOCK_EXPORT))
{
$IBLOCK_EXPORT = array();
}
$iblockPropertiesName = Array(
"article" => GetMessage("PROPERTY_ARTICLE_HEADER_NAME"),
"manufacturer" => GetMessage("PROPERTY_MANUFACTURER_HEADER_NAME"),
"color" => GetMessage("PROPERTY_COLOR_HEADER_NAME"),
"size" => GetMessage("PROPERTY_SIZE_HEADER_NAME"),
"weight" => GetMessage("PROPERTY_WEIGHT_HEADER_NAME"),
"length" => GetMessage("PROPERTY_LENGTH_HEADER_NAME"),
"width" => GetMessage("PROPERTY_WIDTH_HEADER_NAME"),
"height" => GetMessage("PROPERTY_HEIGHT_HEADER_NAME"),
);
$iblockFieldsName = Array(
"weight" => Array("code" => "catalog_size" , "name" => GetMessage("SELECT_WEIGHT_PROPERTY_NAME"), 'unit' => 'mass'),
"length" => Array("code" => "catalog_length" , "name" => GetMessage("SELECT_LENGTH_PROPERTY_NAME"), 'unit' => 'length'),
"width" => Array("code" => "catalog_width" , "name" => GetMessage("SELECT_WIDTH_PROPERTY_NAME"), 'unit' => 'length'),
"height" => Array("code" => "catalog_height" , "name" => GetMessage("SELECT_HEIGHT_PROPERTY_NAME"), 'unit' => 'length'),
);
$iblockPropertiesHint = Array(
"article" => Array("ARTICLE", "ART", "ARTNUMBER", "ARTICUL", "ARTIKUL"),
"manufacturer" => Array("MANUFACTURER", "PROISVODITEL", "PROISVOD", "PROISV"),
"color" => Array("COLOR", "CVET"),
"size" => Array("SIZE", "RAZMER"),
"weight" => Array("WEIGHT", "VES", "VEC"),
"length" => Array("LENGTH", "DLINA"),
"width" => Array("WIDTH", "SHIRINA"),
"height" => Array("HEIGHT", "VISOTA"),
);
$units = Array(
'length' => Array(
'mm' => GetMessage("UNIT_MEASUREMENT_MM"),
'cm' => GetMessage("UNIT_MEASUREMENT_CM"),
'm' => GetMessage("UNIT_MEASUREMENT_M"),
),
'mass' => Array(
'mg' => GetMessage("UNIT_MEASUREMENT_MG"),
'g' => GetMessage("UNIT_MEASUREMENT_G"),
'kg' => GetMessage("UNIT_MEASUREMENT_KG"),
)
);
$hintUnit = Array(
'length' => 'mm',
'mass' => 'g'
);
$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 ($iblock = $db_res->Fetch())
{
if ($arCatalog = CCatalog::GetByIDExt($iblock["ID"]))
{
if($arCatalog['CATALOG_TYPE'] == "D" || $arCatalog['CATALOG_TYPE'] == "X" || $arCatalog['CATALOG_TYPE'] == "P")
{
$propertiesSKU = null;
if ($arCatalog['CATALOG_TYPE'] == "X" || $arCatalog['CATALOG_TYPE'] == "P")
{
$iblockOffer = CCatalogSKU::GetInfoByProductIBlock($iblock["ID"]);
$db_properties = CIBlock::GetProperties($iblockOffer['IBLOCK_ID'], Array());
while($prop = $db_properties->Fetch())
$propertiesSKU[] = $prop;
$oldPropertySKU = null;
if (isset($IBLOCK_PROPERTY_SKU[$iblock['ID']])) {
foreach ($iblockPropertiesName as $key => $prop) {
$oldPropertySKU[$key] = $IBLOCK_PROPERTY_SKU[$iblock['ID']][$key];
}
}
$oldPropertyUnitSKU = null;
if (isset($IBLOCK_PROPERTY_UNIT_SKU[$iblock['ID']])) {
foreach ($iblockPropertiesName as $key => $prop) {
$oldPropertyUnitSKU[$key] = $IBLOCK_PROPERTY_UNIT_SKU[$iblock['ID']][$key];
}
}
}
$propertiesProduct = null;
$db_properties = CIBlock::GetProperties($iblock['ID'], Array());
while($prop = $db_properties->Fetch())
$propertiesProduct[] = $prop;
$oldPropertyProduct = null;
if (isset($IBLOCK_PROPERTY_PRODUCT[$iblock['ID']])) {
foreach ($iblockPropertiesName as $key => $prop) {
$oldPropertyProduct[$key] = $IBLOCK_PROPERTY_PRODUCT[$iblock['ID']][$key];
}
}
$oldPropertyUnitProduct = null;
if (isset($IBLOCK_PROPERTY_UNIT_PRODUCT[$iblock['ID']])) {
foreach ($iblockPropertiesName as $key => $prop) {
$oldPropertyUnitProduct[$key] = $IBLOCK_PROPERTY_UNIT_PRODUCT[$iblock['ID']][$key];
}
}
$arSiteList = array();
$rsSites = CIBlock::GetSite($iblock["ID"]);
while ($arSite = $rsSites->Fetch())
{
$arSiteList[] = $arSite["SITE_ID"];
}
if (count($IBLOCK_EXPORT) != 0)
$boolExport = (in_array($iblock['ID'], $IBLOCK_EXPORT));
else
$boolExport = true;
$arIBlockList[] = array(
'ID' => $iblock['ID'],
'NAME' => $iblock['NAME'],
'IBLOCK_TYPE_ID' => $iblock['IBLOCK_TYPE_ID'],
'IBLOCK_EXPORT' => $boolExport,
'PROPERTIES_SKU' => $propertiesSKU,
'PROPERTIES_PRODUCT' => $propertiesProduct,
'OLD_PROPERTY_SKU_SELECT' => $oldPropertySKU,
'OLD_PROPERTY_UNIT_SKU_SELECT' => $oldPropertyUnitSKU,
'OLD_PROPERTY_PRODUCT_SELECT' => $oldPropertyProduct,
'OLD_PROPERTY_UNIT_PRODUCT_SELECT' => $oldPropertyUnitProduct,
'SITE_LIST' => '('.implode(' ',$arSiteList).')',
);
if ($boolExport)
$intCountChecked++;
$intCountAvailIBlock++;
}
}
}
if (count($IBLOCK_EXPORT) != 0) {
if ($intCountChecked == $intCountAvailIBlock)
$boolAll = true;
} else {
$intCountChecked = $intCountAvailIBlock;
$boolAll = true;
}
?>
<font class="text" style="font-weight: bold;"><?=GetMessage("CHECK_ALL_INFOBLOCKS");?></font>
<input
style="vertical-align: middle;"
type="checkbox"
name="icml_export_all"
id="icml_export_all"
value="Y"
onclick="checkAll(this,<? echo $intCountAvailIBlock; ?>);"
<? echo ($boolAll ? ' checked' : ''); ?>>
</br>
</br>
<div>
<? $checkBoxCounter = 0;?>
<? foreach ($arIBlockList as $key => $arIBlock):?>
<div>
<div>
<font class="text" style="font-weight: bold;"><? echo htmlspecialcharsex("[".$arIBlock["IBLOCK_TYPE_ID"]."] ".$arIBlock["NAME"]." ".$arIBlock['SITE_LIST']); ?></font>
<input
type="checkbox"
name="IBLOCK_EXPORT[<?=$arIBlock["ID"]?>]"
id="IBLOCK_EXPORT<?=++$checkBoxCounter?>"
value="<?=$arIBlock["ID"]?>"
<? if ($arIBlock['IBLOCK_EXPORT']) echo " checked"; ?>
onclick="checkOne(this,<? echo $intCountAvailIBlock; ?>);"
>
</div>
<br>
<div id="IBLOCK_EXPORT_TABLE<?=$checkBoxCounter?>">
<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>
<? 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>
<? endif;?>
</tr>
</thead>
<tbody>
<? foreach ($iblockPropertiesName as $key => $property): ?>
<? $productSelected = false;?>
<tr class="adm-list-table-row">
<td class="adm-list-table-cell">
<? echo htmlspecialcharsex($property); ?>
</td>
<td class="adm-list-table-cell">
<select
style="width: 200px;"
id="IBLOCK_PROPERTY_PRODUCT_<?=$key?><?=$arIBlock["ID"]?>"
name="IBLOCK_PROPERTY_PRODUCT_<?=$key?>[<?=$arIBlock["ID"]?>]"
class="property-export"
onchange="propertyChange(this);">
<option value=""></option>
<?if (version_compare(SM_VERSION, '14.0.0', '>=') && array_key_exists($key, $iblockFieldsName) && $arIBlock['PROPERTIES_SKU'] == null) :?>
<optgroup label="<?=GetMessage("SELECT_FIELD_NAME");?>">
<? foreach ($iblockFieldsName as $keyField => $field): ?>
<? if ($keyField == $key): ?>
<option value="<?=$field['code'];?>"
<?
if ($arIBlock['OLD_PROPERTY_PRODUCT_SELECT'] != null) {
if ($field['code'] == $arIBlock['OLD_PROPERTY_PRODUCT_SELECT'][$key] ) {
echo " selected";
$productSelected = true;
}
} else {
foreach ($iblockPropertiesHint[$key] as $hint) {
if ($field['code'] == $hint ) {
echo " selected";
$productSelected = true;
break;
}
}
}
?>
>
<?=$field['name'];?>
</option>
<? endif; ?>
<? endforeach;?>
</optgroup>
<optgroup label="<?=GetMessage("SELECT_PROPERTY_NAME");?>">
<?endif; ?>
<? foreach ($arIBlock['PROPERTIES_PRODUCT'] as $prop): ?>
<option value="<?=$prop['CODE'] ?>"
<?
if ($arIBlock['OLD_PROPERTY_PRODUCT_SELECT'] != null) {
if ($prop["CODE"] == $arIBlock['OLD_PROPERTY_PRODUCT_SELECT'][$key] ) {
echo " selected";
$productSelected = true;
}
} else {
foreach ($iblockPropertiesHint[$key] as $hint) {
if ($prop["CODE"] == $hint ) {
echo " selected";
$productSelected = true;
break;
}
}
}
?>
>
<?=$prop["NAME"];?>
</option>
<? endforeach;?>
<?if (version_compare(SM_VERSION, '14.0.0', '>=') && array_key_exists($key, $iblockFieldsName)){?>
</optgroup>
<?}?>
</select>
<?if (array_key_exists($key, $iblockFieldsName)) :?>
<select
style="width: 100px; margin-left: 50px;"
id="IBLOCK_PROPERTY_UNIT_PRODUCT_<?=$key?><?=$arIBlock["ID"]?>"
name="IBLOCK_PROPERTY_UNIT_PRODUCT_<?=$key?>[<?=$arIBlock["ID"]?>]"
>
<? foreach ($units as $unitTypeName => $unitType): ?>
<? if ($unitTypeName == $iblockFieldsName[$key]['unit']): ?>
<? foreach ($unitType as $keyUnit => $unit): ?>
<option value="<?=$keyUnit;?>"
<?
if ($arIBlock['OLD_PROPERTY_UNIT_PRODUCT_SELECT'] != null) {
if ($keyUnit == $arIBlock['OLD_PROPERTY_UNIT_PRODUCT_SELECT'][$key] ) {
echo " selected";
}
} else {
if ($keyUnit == $hintUnit[$unitTypeName]) {
echo " selected";
}
}
?>
>
<?=$unit?>
</option>
<? endforeach;?>
<?endif; ?>
<? endforeach;?>
</select>
<?endif; ?>
</td>
<? if ($arIBlock['PROPERTIES_SKU'] != null): ?>
<td class="adm-list-table-cell">
<select
style="width: 200px;"
id="IBLOCK_PROPERTY_SKU_<?=$key?><?=$arIBlock["ID"]?>"
name="IBLOCK_PROPERTY_SKU_<?=$key?>[<?=$arIBlock["ID"]?>]"
class="property-export"
onchange="propertyChange(this);">
<option value=""></option>
<?if (version_compare(SM_VERSION, '14.0.0', '>=') && array_key_exists($key, $iblockFieldsName)) :?>
<optgroup label="<?=GetMessage("SELECT_FIELD_NAME");?>">
<? foreach ($iblockFieldsName as $keyField => $field): ?>
<? if ($keyField == $key) :?>
<option value="<?=$field['code'];?>"
<?
if (!$productSelected) {
if ($arIBlock['OLD_PROPERTY_SKU_SELECT'] != null) {
if ($field['code'] == $arIBlock['OLD_PROPERTY_SKU_SELECT'][$key] ) {
echo " selected";
}
} else {
foreach ($iblockPropertiesHint[$key] as $hint) {
if ($field['code'] == $hint ) {
echo " selected";
break;
}
}
}
}?>
>
<?=$field['name'];?>
</option>
<? endif; ?>
<? endforeach;?>
</optgroup>
<optgroup label="<?=GetMessage("SELECT_PROPERTY_NAME");?>">
<? endif; ?>
<? foreach ($arIBlock['PROPERTIES_SKU'] as $prop): ?>
<option value="<?=$prop['CODE'] ?>"
<?
if (!$productSelected) {
if ($arIBlock['OLD_PROPERTY_SKU_SELECT'] != null) {
if ($prop["CODE"] == $arIBlock['OLD_PROPERTY_SKU_SELECT'][$key] ) {
echo " selected";
}
} else {
foreach ($iblockPropertiesHint[$key] as $hint) {
if ($prop["CODE"] == $hint ) {
echo " selected";
break;
}
}
}
}
?>
>
<?=$prop["NAME"];?>
</option>
<? endforeach;?>
<? if (version_compare(SM_VERSION, '14.0.0', '>=') && array_key_exists($key, $iblockFieldsName)) : ?>
</optgroup>
<? endif; ?>
</select>
<?if (array_key_exists($key, $iblockFieldsName)) :?>
<select
style="width: 100px; margin-left: 50px;"
id="IBLOCK_PROPERTY_UNIT_SKU_<?=$key?><?=$arIBlock["ID"]?>"
name="IBLOCK_PROPERTY_UNIT_SKU_<?=$key?>[<?=$arIBlock["ID"]?>]"
>
<? foreach ($units as $unitTypeName => $unitType): ?>
<? if ($unitTypeName == $iblockFieldsName[$key]['unit']): ?>
<? foreach ($unitType as $keyUnit => $unit): ?>
<option value="<?=$keyUnit;?>"
<?
if ($arIBlock['OLD_PROPERTY_UNIT_SKU_SELECT'] != null) {
if ($keyUnit == $arIBlock['OLD_PROPERTY_UNIT_SKU_SELECT'][$key] ) {
echo " selected";
}
} else {
if ($keyUnit == $hintUnit[$unitTypeName]) {
echo " selected";
}
}
?>
>
<?=$unit?>
</option>
<? endforeach;?>
<?endif; ?>
<? endforeach;?>
</select>
<?endif; ?>
</td>
<? endif;?>
</tr>
<? endforeach;?>
</tbody>
</table>
<br>
<br>
</div>
</div>
<? endforeach;?>
</div>
<input type="hidden" name="count_checked" id="count_checked" value="<? echo $intCountChecked; ?>">
<br>
<font class="text"><?=GetMessage("FILENAME");?><br><br></font>
<input type="text" name="SETUP_FILE_NAME"
value="<?=htmlspecialcharsbx(strlen($SETUP_FILE_NAME) > 0 ?
$SETUP_FILE_NAME :
(COption::GetOptionString(
'catalog',
'export_default_path',
'/bitrix/catalog_export/'))
.'intarocrm'/* .mt_rand(0, 999999) */.'.xml'
); ?>" size="50">
<br>
<br>
<br>
<font class="text"><?=GetMessage("LOAD_PERIOD");?><br><br></font>
<input type="radio" name="TYPE_LOADING" value="none" onclick="checkProfile(this);"><?=GetMessage("NOT_LOADING");?><Br>
<input type="radio" name="TYPE_LOADING" value="cron" onclick="checkProfile(this);"><?=GetMessage("CRON_LOADING");?><Br>
<input type="radio" name="TYPE_LOADING" value="agent" checked onclick="checkProfile(this);"><?=GetMessage("AGENT_LOADING");?><Br>
<br>
<br>
<font class="text"><?=GetMessage("LOAD_NOW");?>&nbsp;</font>
<input id="load-now" type="checkbox" name="LOAD_NOW" value="now" checked >
<br>
<br>
<font class="text"><?=GetMessage("BASE_PRICE");?>&nbsp;</font>
<select name="price-types" class="typeselect">
<option value=""></option>
<?php foreach($arResult['PRICE_TYPES'] as $priceType): ?>
<option value="<?php echo $priceType['ID']; ?>"
<?php if($priceType['BASE'] == 'Y') echo 'selected'; ?>>
<?php echo $priceType['NAME']; ?>
</option>
<?php endforeach; ?>
</select>
<br>
<br>
<br>
<div id="profile-field" >
<font class="text"><?=GetMessage("PROFILE_NAME");?>&nbsp;</font>
<input
type="text"
name="SETUP_PROFILE_NAME"
value="<?= ($SETUP_PROFILE_NAME ? $SETUP_PROFILE_NAME: GetMessage("PROFILE_NAME_EXAMPLE"));?>"
size="30">
<br>
<br>
<br>
</div>
<script type="text/javascript" src="/bitrix/js/main/jquery/jquery-1.7.min.js"></script>
<script type="text/javascript">
function checkAll(obj,cnt)
{
for (i = 0; i < cnt; i++)
{
if (obj.checked)
BX.removeClass('IBLOCK_EXPORT_TABLE'+(i+1),"iblock-export-table-display-none");
}
var table = BX(obj.id.replace('IBLOCK_EXPORT','IBLOCK_EXPORT_TABLE'));
if (obj.checked)
BX.removeClass(table,"iblock-export-table-display-none");
var 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 (i = 0; i < cnt; i++)
{
BX('IBLOCK_EXPORT_TABLE'+(i+1)).style.opacity = state.opacity/100;
}
},
complete : function() {
for (i = 0; i < cnt; i++)
{
if (!obj.checked)
BX.addClass('IBLOCK_EXPORT_TABLE'+(i+1),"iblock-export-table-display-none");
}
}
});
easing.animate();
var boolCheck = obj.checked;
for (i = 0; i < cnt; i++)
{
BX('IBLOCK_EXPORT'+(i+1)).checked = boolCheck;
}
BX('count_checked').value = (boolCheck ? cnt : 0);
};
function checkOne(obj,cnt)
{
var table = BX(obj.id.replace('IBLOCK_EXPORT','IBLOCK_EXPORT_TABLE'));
if (obj.checked)
BX.removeClass(table,"iblock-export-table-display-none");
var 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();
var boolCheck = obj.checked;
var intCurrent = parseInt(BX('count_checked').value);
intCurrent += (boolCheck ? 1 : -1);
BX('icml_export_all').checked = (intCurrent < cnt ? false : true);
BX('count_checked').value = intCurrent;
};
function propertyChange(obj)
{
if (BX(obj.id).value !== 'none') {
if (obj.id.indexOf("SKU") !== -1)
BX(obj.id.replace('SKU','PRODUCT')).value = 'none';
else
BX(obj.id.replace('PRODUCT','SKU')).value = 'none';
}
};
function checkProfile(obj)
{
if (obj.value !== 'none')
$('#profile-field').show();
else
$('#profile-field').hide();
};
</script>
<?//Следующие переменные должны быть обязательно установлены?>
<?=bitrix_sessid_post();?>
<input type="hidden" name="lang" value="<?php echo LANG; ?>">
<input type="hidden" name="id" value="intaro.intarocrm">
<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" 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>

View file

@ -1,6 +0,0 @@
<?
$arModuleVersion = array(
"VERSION" => "1.1.0",
"VERSION_DATE" => "2015-03-03 16:21:38"
);

View file

@ -1,2 +0,0 @@
<?php
$MESS["ROOT_CATEGORY_FOR_CATALOG"] = "Корневой раздел для каталога \"%s\"";

View file

@ -1,2 +0,0 @@
<?php
$MESS["PRODUCT_CANCEL"] = "Товар в статусе отмены";

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,33 +0,0 @@
<?php
$MESS ['INTARO_MODULE_NAME'] = 'retailCRM';
$MESS ['MODULE_DESCRIPTION'] = 'Модуль интеграции с retailCRM - специализированной CRM для e-commerce';
$MESS ['MODULE_PARTNER_NAME'] = 'Интаро Софт';
$MESS ['MODULE_PARTNER_URI'] = 'http://www.retailcrm.ru';
$MESS ['MODULE_INSTALL_TITLE'] = 'Установка модуля';
$MESS ['MODULE_UNINSTALL_TITLE'] = 'Удаление модуля';
$MESS ['CANCELED'] = 'Флаг «Отменен»';
$MESS ['ERR_SALE'] = 'Отсутствует модуль sale! Дальнейшая установка невозможна.';
$MESS ['ERR_IBLOCK'] = 'Отсутствует модуль iblock! Дальнейшая установка невозможна.';
$MESS ['ERR_CATALOG'] = 'Отсутствует модуль catalog! Дальнейшая установка невозможна.';
$MESS ['INTAROCRM_CURL_ERR'] = 'Для работы модуля интеграции с retailCRM требуется PHP-расширение CURL.';
$MESS ['ERR_ARTICLE_IBLOCK'] = 'Не установлены артикулы';
$MESS ['DATE_TIMEZONE_ERR'] = 'Не указана временная зона в настройках php.';
$MESS ['ORDER_PROPS'] = 'Настройки соответствия полей заказа retailCRM свойствам заказа 1С-Битрикс';
$MESS ['FIO'] = 'Ф.И.О.';
$MESS ['ZIP'] = 'Индекс';
$MESS ['ADDRESS'] = 'Адрес (строкой)';
$MESS ['PHONE'] = 'Телефон';
$MESS ['EMAIL'] = 'E-mail';
$MESS ['COUNTRY'] = 'Страна';
$MESS ['REGION'] = 'Область / Край';
$MESS ['CITY'] = 'Город';
$MESS ['STREET'] = 'Улица';
$MESS ['BUILDING'] = 'Строение';
$MESS ['FLAT'] = 'Квартира';
$MESS ['INTERCOMCODE'] = 'Домофон';
$MESS ['FLOOR'] = 'Этаж';
$MESS ['BLOCK'] = 'Подъезд';
$MESS ['HOUSE'] = 'Строение / корпус';
$MESS ['ADDRESS_SHORT'] = 'Краткий адрес';
$MESS ['ADDRESS_FULL'] = 'Детальный адрес';

View file

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

View file

@ -1,67 +0,0 @@
<?php
$MESS ['ICRM_OPTIONS_GENERAL_TAB'] = 'Общие настройки';
$MESS ['ICRM_OPTIONS_IMPORT_TAB'] = 'Настройки импорта';
$MESS ['ICRM_OPTIONS_ORDER_PROPS_TAB'] = 'Cоответствия полей свойств заказа';
$MESS ['ICRM_CONN_SETTINGS'] = 'Настройка соединения';
$MESS ['ICRM_API_HOST'] = 'Адрес retailCRM:';
$MESS ['ICRM_API_KEY'] = 'Ключ авторизации:';
$MESS ['ICRM_SITES'] = 'Активные сайты';
$MESS ['ICRM_OPTIONS_CATALOG_TAB'] = 'Настройка справочников';
$MESS ['DELIVERY_TYPES_LIST'] = 'Способы доставки';
$MESS ['PAYMENT_TYPES_LIST'] = 'Способы оплаты';
$MESS ['PAYMENT_STATUS_LIST'] = 'Статусы';
$MESS ['ORDER_TYPES_LIST'] = 'Типы заказа';
$MESS ['CONTRAGENTS_TYPES_LIST'] = 'Тип контрагента';
$MESS ['PAYMENT_LIST'] = 'Оплата';
$MESS ['PAYMENT_Y'] = 'Оплачен';
$MESS ['PAYMENT_N'] = 'Не оплачен';
$MESS ['LEGAL_DETAIL'] = 'Юридические и банковские реквизиты';
$MESS ['ORDER_CUSTOM'] = 'Кастомные поля';
$MESS ['ORDER_UPLOAD'] = 'Повторная выгрузка заказов';
$MESS ['ORDER_NUMBERS'] = 'Номера заказов: ';
$MESS ['ORDER_UPLOAD_INFO'] = 'Для загрузки всех заказов нажмите кнопку «Начать выгрузку». Или перечислите необходимые ID заказов через запятую, интервалы через тире. Например: 1, 3, 5-10, 12, 13... и т.д.';
$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'] = 'Флаг «Отменен»';
$MESS ['INFO_1'] = ' Задайте соответствие между справочниками 1C-Битрикс и справочниками retailCRM.';
$MESS ['ICRM_OPTIONS_ORDER_DISCHARGE_TAB'] = 'Режим выгрузки заказов';
$MESS ['ORDER_DISCH'] = 'Режим выгрузки заказов';
$MESS ['DISCHARGE_AGENT'] = 'Выгрузка заказов с помощью агента';
$MESS ['DISCHARGE_EVENTS'] = 'Выгрузка заказов по событию';
$MESS ['INFO_2'] = ' Задайте соответствие между полями заказа 1C-Битрикс и retailCRM.';
$MESS ['ORDER_PROPS'] = 'Настройки соответствия полей заказа retailCRM свойствам заказа 1С-Битрикс';
$MESS ['FIO'] = 'Ф.И.О.';
$MESS ['ZIP'] = 'Индекс';
$MESS ['ADDRESS'] = 'Адрес (строкой)';
$MESS ['PHONE'] = 'Телефон';
$MESS ['EMAIL'] = 'E-mail';
$MESS ['COUNTRY'] = 'Страна';
$MESS ['REGION'] = 'Область / Край';
$MESS ['CITY'] = 'Город';
$MESS ['STREET'] = 'Улица';
$MESS ['BUILDING'] = 'Строение';
$MESS ['FLAT'] = 'Квартира';
$MESS ['INTERCOMCODE'] = 'Домофон';
$MESS ['FLOOR'] = 'Этаж';
$MESS ['BLOCK'] = 'Подъезд';
$MESS ['HOUSE'] = 'Строение / корпус';
$MESS ['ADDRESS_SHORT'] = 'Краткий адрес';
$MESS ['ADDRESS_FULL'] = 'Детальный адрес';
$MESS ['UPDATE_DELIVERY_SERVICES'] = 'Выгрузка служб доставок';
$MESS ['MESS_1'] = 'Произошла ошибка при выгрузке одной или нескольких служб доставок, попробуйте еще раз. Если проблема повторилась, обратитесь в Интаро Софт.';
$MESS ['MESS_2'] = 'Произошла ошибка сервера, обратитесь в Интаро Софт.';
$MESS ['ORDER_TYPES_LIST_CUSTOM'] = 'Внимание! Используется не стандартное соответвие типов заказов.';

File diff suppressed because it is too large Load diff

View file

@ -1,87 +0,0 @@
<?php
if (!CModule::IncludeModule("intaro.intarocrm")) return;
if (!CModule::IncludeModule("sale")) return;
class RestApiSite extends \IntaroCrm\RestApi
{
public function sitesList()
{
$url = $this->apiUrl.'reference/sites';
$result = $this->curlRequest($url);
return $result;
}
}
$mid = 'intaro.intarocrm';
$CRM_API_HOST_OPTION = 'api_host';
$CRM_API_KEY_OPTION = 'api_key';
$CRM_CONTRAGENT_TYPE = 'contragent_type';
$CRM_SITES_LIST= 'sites_list';
$api_host = COption::GetOptionString($mid, $CRM_API_HOST_OPTION, 0);
$api_key = COption::GetOptionString($mid, $CRM_API_KEY_OPTION, 0);
$api = new RestApiSite($api_host, $api_key);
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/intaro.intarocrm/classes/general/agent.php')) {
unlink($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/intaro.intarocrm/classes/general/agent.php');
}
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/intaro.intarocrm/classes/general/Exception/ApiException.php')) {
unlink($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/intaro.intarocrm/classes/general/Exception/ApiException.php');
}
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/retailcrm')) {
removeDirectory($_SERVER['DOCUMENT_ROOT'] . '/retailcrm');
}
//sites
$rsSites = CSite::GetList($by, $sort, array('ACTIVE' => 'Y'));
while ($ar = $rsSites->Fetch()){
$arSites[] = $ar;
}
if(count($arSites)>1){
try {
$sitesList = $api->sitesList();
} catch (\IntaroCrm\Exception\CurlException $e) {
ICrmOrderActions::eventLog(
'intaro.crm/updater.php', 'RetailCrm\RestApi::sitesList::CurlException',
$e->getCode() . ': ' . $e->getMessage()
);
return;
}
foreach ($arResult['arSites'] as $arSites) {
$siteListArr[$arSites['LID']] = $sitesList[0]['code'];
}
COption::SetOptionString($mid, $CRM_SITES_LIST, serialize(ICrmOrderActions::clearArr($siteListArr)));
}
//contragents type list
$dbOrderTypesList = CSalePersonType::GetList(
array(
"SORT" => "ASC",
"NAME" => "ASC"
),
array(
"ACTIVE" => "Y",
),
false,
false,
array()
);
$orderTypesList = array();
while ($arOrderTypesList = $dbOrderTypesList->Fetch()){
$orderTypesList[] = $arOrderTypesList;
}
$contragentTypeArr = array();
foreach ($orderTypesList as $orderType) {
$contragentTypeArr[$orderType['ID']] = 'individual';
}
COption::SetOptionString($mid, $CRM_CONTRAGENT_TYPE, serialize(ICrmOrderActions::clearArr($contragentTypeArr)));
function removeDirectory($dir) {
if ($objs = glob($dir."/*")) {
foreach($objs as $obj) {
is_dir($obj) ? removeDirectory($obj) : unlink($obj);
}
}
rmdir($dir);
}

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

@ -1,11 +1,24 @@
<?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;
/**
* Response from retailCRM API
* Class ApiResponse
*
* @category RetailCRM
* @package RetailCRM\Response
*/
class ApiResponse implements \ArrayAccess
{
@ -15,6 +28,14 @@ class ApiResponse implements \ArrayAccess
// 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;
@ -56,7 +77,11 @@ class ApiResponse implements \ArrayAccess
/**
* Allow to access for the property throw class method
*
* @param string $name
* @param string $name method name
* @param mixed $arguments method parameters
*
* @throws \InvalidArgumentException
*
* @return mixed
*/
public function __call($name, $arguments)
@ -74,7 +99,10 @@ class ApiResponse implements \ArrayAccess
/**
* Allow to access for the property throw object property
*
* @param string $name
* @param string $name property name
*
* @throws \InvalidArgumentException
*
* @return mixed
*/
public function __get($name)
@ -87,8 +115,13 @@ class ApiResponse implements \ArrayAccess
}
/**
* @param mixed $offset
* @param mixed $value
* Offset set
*
* @param mixed $offset offset
* @param mixed $value value
*
* @throws \BadMethodCallException
* @return void
*/
public function offsetSet($offset, $value)
{
@ -96,7 +129,12 @@ class ApiResponse implements \ArrayAccess
}
/**
* @param mixed $offset
* Offset unset
*
* @param mixed $offset offset
*
* @throws \BadMethodCallException
* @return void
*/
public function offsetUnset($offset)
{
@ -104,7 +142,10 @@ class ApiResponse implements \ArrayAccess
}
/**
* @param mixed $offset
* Check offset
*
* @param mixed $offset offset
*
* @return bool
*/
public function offsetExists($offset)
@ -113,15 +154,28 @@ class ApiResponse implements \ArrayAccess
}
/**
* @param mixed $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");
throw new InvalidArgumentException("Property \"$offset\" not found");
}
return $this->response[$offset];
}
/**
* @return array
*/
public function getResponseBody()
{
return $this->response;
}
}

View file

@ -1,79 +1,26 @@
<?php
/**
* RestNormalizer
*
* Copyright (c) 2015, Dmitry Mamontov <d.slonyara@gmail.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Dmitry Mamontov nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package restnormalizer
* @author Dmitry Mamontov <d.slonyara@gmail.com>
* @copyright 2015 Dmitry Mamontov <d.slonyara@gmail.com>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.0.0
* @category RetailCRM
* @package RetailCRM
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
/**
/**
* RestNormalizer - The main class
*
* @author Dmitry Mamontov <d.slonyara@gmail.com>
* @copyright 2015 Dmitry Mamontov <d.slonyara@gmail.com>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @version Release: 1.0.0
* @link https://github.com/dmamontov/restnormalizer/
* @since Class available since Release 1.0.0
* @category RetailCRM
* @package RetailCRM
*/
class RestNormalizer
{
/**
* Cleanup of null values
* @var boolean
* @access public
*/
public $clear = true;
/**
* Sorted file validation
* @var array
* @access private
*/
private $validation = array();
/**
* File validation
* @var array
* @access private
*/
private $originalValidation = array();
private $validation = [];
private $originalValidation = [];
private $server;
/**
* Class constructor
@ -86,23 +33,7 @@ class RestNormalizer
if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) {
date_default_timezone_set(@date_default_timezone_get());
}
}
/**
* Installation file validation
* @param string $file The path to the file validation
* @return void
* @access public
* @final
*/
final public function setValidation($file)
{
if (is_null($file) || is_file($file) === false
|| json_decode(file_get_contents($file)) === null
|| $this->parseConfig($file) === false) {
ICrmOrderActions::eventLog('RestNormalizer', 'intaro.intarocrm', 'Incorrect file normalize.');
return false;
}
$this->server = \Bitrix\Main\Context::getCurrent()->getServer()->getDocumentRoot();
}
/**
@ -130,8 +61,19 @@ class RestNormalizer
* @access public
* @final
*/
final public function normalize($data, $key = false)
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);
}
@ -143,7 +85,8 @@ class RestNormalizer
}
if (!is_array($data) || count($data) < 1) {
ICrmOrderActions::eventLog('RestNormalizer', 'intaro.intarocrm', 'Incorrect data array.');
RCrmActions::eventLog('RestNormalizer', 'intaro.retailcrm', 'Incorrect data array.');
return false;
}
@ -160,25 +103,26 @@ class RestNormalizer
*/
final private function formatting($data, $skip = false)
{
$formatted = array();
$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) {
} 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);
}
if ($formatted[ $code ] === null || $formatted[ $code ] == '' || count($formatted[ $code ]) < 1) {
//Удаление пустых переменных, кроме значений равных 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 = array();
$formatted = [];
break;
}
}
@ -188,7 +132,7 @@ class RestNormalizer
if ($skip === false) {
foreach ($this->validation as $code => $valid) {
if (isset($valid['required']) && $valid['required'] === true && isset($formatted[ $code ]) === false) {
ICrmOrderActions::eventLog('RestNormalizer', 'intaro.intarocrm', "NOT VALID: $code");
RCrmActions::eventLog('RestNormalizer', 'intaro.retailcrm', "NOT VALID: $code");
}
}
@ -247,14 +191,15 @@ class RestNormalizer
$data = trim((string) $data);
if (isset($validation['default']) && is_string($validation['default']) && trim($validation['default']) != ''
&& ($data == '' || is_string($data) === false)) {
&& ($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']) {
} elseif (isset($validation['max']) && mb_strlen($data) > $validation['max']) {
$data = mb_substr($data, 0, $validation['max']);
}
@ -375,7 +320,8 @@ class RestNormalizer
} 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'])) {
&& isset($validation['default']) && in_array($validation['default'], $validation['values'])
) {
$data = $validation['default'];
} elseif (in_array($data, $validation['values']) === false) {
return null;
@ -397,10 +343,16 @@ class RestNormalizer
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');
? $this->multiConvert($value)
: $APPLICATION->ConvertCharset($value, SITE_CHARSET, 'utf-8')
;
}
return $data;
} else {
return $APPLICATION->ConvertCharset($data, SITE_CHARSET, 'utf-8');
@ -409,4 +361,4 @@ class RestNormalizer
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

@ -13,12 +13,13 @@
<field id="city">Город</field>
<field id="index">Индекс</field>
<field id="street">Улица</field>
<field id="building">Строение</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="house">Строение</field>
<field id="housing">Корпус</field>
<field id="legalName" group="legal-entity, enterpreneur">Полное наименование</field>
<field id="legalAddress" group="legal-entity, enterpreneur">Адрес регистрации (Юридический адрес)</field>
@ -29,13 +30,13 @@
<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>
</options>

View file

@ -19,6 +19,10 @@
"number": {
"type": "string"
},
"birthday": {
"type": "datetime",
"format": "Y-m-d"
},
"site": {
"type": "string"
},
@ -76,6 +80,9 @@
"type": "bool",
"default": false
},
"subscribed": {
"type": "string"
},
"commentary": {
"type": "string"
},
@ -132,6 +139,80 @@
},
"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": {
@ -142,10 +223,27 @@
"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,
@ -189,6 +287,9 @@
"site": {
"type": "string"
},
"countryIso": {
"type": "string"
},
"call": {
"type": "bool",
"default": false
@ -203,6 +304,18 @@
"managerComment": {
"type": "string"
},
"weight": {
"type": "double"
},
"length": {
"type": "int"
},
"width": {
"type": "int"
},
"height": {
"type": "int"
},
"paymentDetail": {
"type": "string"
},
@ -260,6 +373,14 @@
"bankAccount": {
"type": "string"
},
"shipmentDate": {
"type": "datetime",
"format": "Y-m-d"
},
"shipped": {
"type": "bool",
"default": false
},
"orderType": {
"type": "string"
},
@ -272,12 +393,28 @@
"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"
},
@ -293,8 +430,8 @@
"quantity": {
"type": "double",
"default": 1,
"min": 1,
"decimals": 1
"min": 0,
"decimals": 3
},
"properties": {
"type": "skip"
@ -312,7 +449,7 @@
"type": "double",
"default": 0,
"min": 0,
"decimals": 1
"decimals": 2
},
"code": {
"type": "string"
@ -366,6 +503,9 @@
"house": {
"type": "string"
},
"housing": {
"type": "string"
},
"metro": {
"type": "string"
},
@ -374,6 +514,54 @@
},
"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();
}

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