h1. Журнал работ агента h2. 2026-02-27 — Управляемая смена пароля пользователей в /clients/ * Изменение: в @clients/index.php@ добавлена нормализация флага @users[].change_password@ (алиасы @CHANGE_PASSWORD@/@changePassword@; значения @Да/Нет@, @true/false@, @1/0@, @yes/no@). * Изменение: для существующих пользователей пароль меняется только при непустом @users[].password@ и разрешающем @change_password@; в обновление @CUser@ добавляются @PASSWORD@/@CONFIRM_PASSWORD@. * Изменение: если передан @password@, но @change_password@ отсутствует или запрещает смену, пароль не меняется и в ответ добавляется warning @password_update_skipped_by_flag@. * Изменение: в @data.users[]@ добавлено поле @password_status@ со значениями @created@, @updated@, @not_requested@, @skipped@. * Документация: обновлены apidoc-блок @/clients/@ в @clients/index.php@ и раздел @POST /clients/@ в @docs/reference/api-details.textile@. h2. Как проверить * Отправить @POST /rest1c/clients/@ для существующего пользователя с @password@ и @change_password=\"Да\"@, убедиться, что в @data.users[]@ возвращается @password_status=updated@. * Отправить @POST /rest1c/clients/@ для существующего пользователя с @password@ и @change_password=\"Нет\"@, убедиться, что пароль не меняется и возвращается warning @password_update_skipped_by_flag@ с @password_status=not_requested@. * Отправить @POST /rest1c/clients/@ с @change_password=\"Да\"@ и пустым @password@, убедиться, что пароль не меняется, @password_status=skipped@, без warning. * Отправить @POST /rest1c/clients/@ для нового пользователя и убедиться, что в @data.users[]@ возвращается @status=created@ и @password_status=created@. h2. 2026-02-03 — Проксирование выгрузки заказов через localhost rest1c * Изменение: обработчик @OnSaleOrderSaved@ в @infoFiles/init.php@ теперь проксирует выгрузку заказа в локальный REST1C через @/order/export_list.php@, без прямого использования @OrderService@ в Bitrix. * Изменение: добавлены проверки @API_URL@/@TOKEN@ (с fallback на @http://localhost/rest1c@) и логирование HTTP-статуса ответа прокси. * Причина: устранение ошибки @OrderService autoload failed@ при попытке выгрузки заказа из Bitrix. h2. Как проверить * Создать новый заказ в Bitrix и убедиться, что в логах появляются стадии @queued@ → @request_prepared@ → @request_completed@ без ошибки @OrderService autoload failed@. * Проверить, что запрос уходит на @http://localhost/rest1c/order/export_list.php@ и возвращает @status=success@ при корректных @API_URL@/@TOKEN@. h2. 2026-02-02 — Разделение email-уведомлений и событий Restboard * Изменение: отправка email вынесена в отдельный метод @NotificationService::sendEmail()@, отправка событий Restboard — в @NotificationService::sendRestboardEvent()@. * Изменение: автоуведомления в @BaseApi@ теперь отправляют email и Restboard независимо, чтобы отключение email не влияло на Restboard. * Изменение: уведомления о взаимодействии с 1С в @BaseService::notifyOneCInteraction()@ отправляют email и Restboard раздельно. h2. Как проверить * Выполнить любой публичный endpoint с @AUTO_NOTIFY_DISABLE=true@ и убедиться, что email не отправляется, но в логах присутствует @Restboard response@. * Выполнить запрос с @AUTO_NOTIFY_DISABLE=false@ и убедиться, что отправлены и email, и событие Restboard. h2. 2026-02-02 — Настройка Loki/Alloy для логов проекта * Изменение: добавлен файл @config.alloy@ с источниками логов проекта (@errors/*.log@ и @storage/logs/*.log@) и отправкой в Loki; уровень логирования установлен в @debug@ и используется @ALLOY_HOST@. * Документация: добавлена инструкция @docs/how-to/loki-project-logs.textile@ и ссылка в индексе @docs/rest1c-api.textile@. h2. Как проверить * Перезапустить Alloy/agent с @config.alloy@ и убедиться, что сбор логов стартует без ошибок. * В Loki выполнить запрос по меткам @job=rest1c-api@ и проверить наличие строк из путей проекта. h2. 2026-02-02 — Защита воркеров RabbitMQ от пропущенного heartbeat * Изменение: в @products/Rabbit.php@ добавлена периодическая проверка heartbeat во время idle‑ожидания и после обработки сообщений; при пропуске heartbeat выполняется переподключение. * Изменение: в @discounts/rabbit.php@ и @discounts/Manual_Start.php@ добавлена проверка heartbeat после обработки сообщений и в цикле ожидания. * Документация: обновлён раздел @docs/how-to/troubleshooting.textile@ с симптомами и рекомендациями по @AMQPHeartbeatMissedException@. h2. Как проверить * Запустить @php products/Rabbit.php@ на окружении с @RABBITMQ_HEARTBEAT=30@ и убедиться, что логов @AMQPHeartbeatMissedException@ нет при длительном простое. * Запустить @php discounts/rabbit.php@ и @php discounts/Manual_Start.php@, дождаться idle‑таймаута и проверить, что heartbeat‑проверки не приводят к фатальным ошибкам. h2. 2026-01-30 — Поиск скидок по HL15 с использованием XML_ID пользователя * Изменение: в @infoFiles/template.php@ при поиске клиентской скидки добавлен запрос HL15 по @UF_USER@ (XML_ID пользователя), если поиск по @UF_USERID@ не дал результата. * Изменение: в @infoFiles/saleactiondiscountfromdirectory.php@ поиск HL15 дополняется фильтром по @UF_USER@ (XML_ID пользователя), а возврат XML_ID пользователя переносится на последний шаг. * Изменение: в выборке HL15 используется подтверждённый набор полей (@UF_CONTRAGENT@/@UF_CONTRAGENTID@/@UF_USER@/@UF_USERID@), без ссылок на несуществующие поля. * Причина: скидки не находились, когда HL15 заполнен только XML_ID пользователя, без @UF_USERID@. h2. Как проверить * Авторизоваться пользователем с заполненным @UF_XML_ID@ и записью HL15 по @UF_USER@, открыть каталог и убедиться, что скидка подтянулась. * В корзине убедиться, что скидка применяется через правило @DiscountFromDirectory@ для того же пользователя. h2. 2026-01-29 — Актуализация документации /sync.php и удаление лишних файлов * Изменение: @docs/sync-concept.textile@ и @docs/reference/sync-concept.textile@ приведены в соответствие с @sync.php@ (поддерживаемые сущности, формат ответа, debug/zip). * Изменение: удалены лишние файлы @.env.examlpe@ и @systemd/rest1c-errors-cleaner.*@. h2. Как проверить * Сравнить apidoc-блок @/sync.php@ с документами @docs/sync-concept.textile@ и @docs/reference/sync-concept.textile@. * Выполнить @git status -sb@ и убедиться, что удалённые файлы отражены как D. h2. 2026-01-29 — Анализ дубликатов HL_CONSIGNEE по result.csv * Наблюдение: в @infoFiles/result.csv@ 521 значение @UF_XML_ID@ с количеством > 1. * Наблюдение: суммарный избыток строк (cnt-1) = 40221. * Пример топ-значений: @e44a60cb-57c1-11ea-840f-e41f13bc544a@ (651), @e0f26a9e-c4e9-11ee-a865-0cc47afa42be@ (611), @5187cfe5-a163-11e4-8b65-e41f13bc5448@ (566). h2. Как проверить * Открыть @infoFiles/result.csv@ и убедиться, что заголовок @UF_XML_ID,cnt@ и строки соответствуют результату SQL. * Пересчитать агрегаты командой @python3@ и проверить @total_rows@, @min_cnt@, @max_cnt@. h2. 2026-01-29 — Защита от дубликатов HL32 (идемпотентная запись по UF_XML_ID) * Изменение: при записи в HL32 эндпоинт @/clients/@ выполняет обновление существующей записи по @UF_XML_ID@ вместо создания новой. * Изменение: при обнаружении нескольких записей с одинаковым @UF_XML_ID@ логируется предупреждение, но запись не дублируется. h2. Как проверить * Отправить два запроса @/clients/@ с одним и тем же @UF_XML_ID@ и убедиться, что в HL32 не растёт количество записей по этому идентификатору. * Проверить лог @HL32: запись обновлена@ и отсутствие @HL32: запись создана@ на повторном запросе. h2. 2026-01-29 — Множественные связи пользователя с контрагентами (HL15) * Причина: при обработке пользователей в @/clients/@ существующие активные связи HL15 с другими контрагентами деактивировались, что оставляло только последнюю организацию. * Изменение: деактивация старых связок пользователя (роль @UL+@) отключена, чтобы поддерживать несколько активных контрагентов. * Документация: добавлено описание поведения в @docs/reference/api-details.textile@ и apidoc-блоке @clients/index.php@. h2. Как проверить * Отправить один запрос @/clients/@, где один и тот же пользователь передан в двух компаниях, и убедиться, что в HL15 обе связки активны. * Зайти под пользователем и убедиться, что выбор организаций доступен. h2. 2026-01-29 — Деактивация связок пользователя с компанией при пустом users[] * Причина: при удалении пользователя из компании связь в HL15 не деактивировалась, так как список users отсутствовал/был пуст. * Изменение: если в @/clients/@ передан пустой массив @users[]@, все связи UL+ с текущей компанией деактивируются. * Документация: уточнено поведение в @docs/reference/api-details.textile@ и apidoc-блоке @clients/index.php@. h2. Как проверить * Отправить @/clients/@ с @users: []@ для компании и убедиться, что все связи UL+ для @UF_CONTRAGENTID@ деактивированы. * Отправить @/clients/@ с одним пользователем и убедиться, что активна только его связка по текущей компании. h2. 2026-01-28 — Prefix и source в запросе Orders/Create к 1С * Изменение: параметр @source@ в query берётся из @ONEC_ORDERS_SOURCE@, а @prefix@ — из @ORDER_PREFIX@ (либо из входных данных, если @ORDER_PREFIX@ не задан). * Изменение: в тело запроса @prefix@ записывается согласно @ORDER_PREFIX@, при этом поля @Source@/@Sourse@ очищаются. * Причина: исключено некорректное подставление @prefix@ значением @source@ при создании заказа. h2. Как проверить * Установить @ONEC_ORDERS_SOURCE=backdev.b2b-ecobalt.ru@ и @ORDER_PREFIX=Arg@. * Отправить тестовый заказ через @Orders/Create@ и убедиться, что query содержит @source=backdev.b2b-ecobalt.ru@ и @prefix=Arg@, а в JSON-теле @prefix@ равен @Arg@. h2. 2026-01-28 — Разбор файлов "Запрос клиентов_RobotWebsite" (29 уникальных XML_ID) * Наблюдение: в наборе файлов @infoFiles/backend_b2b_ecobalt/28-01-2026 *_Запрос клиентов_RobotWebsite.txt@ зафиксировано 30 запросов, каждый содержит ровно один @clients[].XML_ID@. * Наблюдение: всего 30 запросов, но 29 уникальных XML_ID из-за повтора @f5b84e9a-ae41-11eb-80ed-0cc47afa42be@ в файлах @28-01-2026 08-01-43_Запрос клиентов_RobotWebsite.txt@ и @28-01-2026 08-02-25_Запрос клиентов_RobotWebsite.txt@. * Вывод: причина "29 определённых XML_ID" — это уникальный набор из серии одиночных запросов RobotWebsite, где один клиент запрошен дважды. h2. Как проверить * Просмотреть блок "Тело запроса" в каждом файле @28-01-2026 *_Запрос клиентов_RobotWebsite.txt@ и убедиться, что @clients@ содержит ровно один @XML_ID@. * Сопоставить повторы и убедиться, что @f5b84e9a-ae41-11eb-80ed-0cc47afa42be@ встречается дважды. h2. 2026-01-28 — Проверка логов /clients и возможных внутренних источников повторов * Наблюдение: в @infoFiles/errors@ есть две записи обработки одного и того же XML_ID @f5b84e9a-ae41-11eb-80ed-0cc47afa42be@: @errors_post-rest1c-clients-index_20260128_091947_821468_pid1439067_4135.log@ и @errors_post-rest1c-clients-index_20260128_092040_447911_pid1439047_259a.log@. * Наблюдение: обе обработки завершены статусом @success@ без ошибок, то есть повтор не вызван ошибками сервера. * Анализ кода: - @sync.php@ вызывает @/clients/@ только в режиме clients reload (items[].reload=on) или при отсутствии payload (запрос в 1С). - @deliverypoint/index.php@ вызывает @/clients/@ при автосоздании пользователя, если user отсутствует и есть client_xml_id из 1С. - @deliverypoint/Rabbit.php@ — воркер очереди торговых точек, не инициирует запросы RobotWebsite. * Вывод: повторный запрос конкретного XML_ID, по логам, приходит извне (RobotWebsite), а не как ретрай из /clients/ (ошибок нет) и не как внутренний вызов из deliverypoint/sync (нет признаков иного источника в логах). h2. Как проверить * Сопоставить временные метки в @errors_post-rest1c-clients-index_20260128_091947_821468_pid1439067_4135.log@ и @errors_post-rest1c-clients-index_20260128_092040_447911_pid1439047_259a.log@ и убедиться, что это два отдельных запроса. * При необходимости — проверить входящие JSON-потоки в @/home/bitrix/www/rest1c/storage/requests/@ для указанных файлов логов. h2. 2026-01-28 — Source в запросах заказов к 1С * Изменение: в запросы к 1С по заказам добавлен query-параметр @source@ (адрес сайта) для методов @Orders/Create@, @Orders/InfoFull@ и @Orders/List@. * Изменение: значение @source@ берётся из @ONEC_ORDERS_SOURCE@, затем @ONEC_SOURCE@ или домена @API_URL@. * Документация: обновлён справочник @docs/reference/api-details.textile@. h2. Как проверить * Вызвать @/order/create.php@ и убедиться по логам, что запрос в 1С содержит query-параметр @source@. * Вызвать @/order/info_full.php@ и проверить, что @source@ добавляется в GET-запрос @Orders/InfoFull@. * Вызвать @/order/list.php@ и проверить, что @source@ присутствует в запросе @Orders/List@. h2. 2026-01-29 — Инвентаризация правил округления (по запросу) * Контекст: зафиксированы актуальные места в репозитории, где описаны правила округления цен для корзины/витрины. * Источник: @infoFiles/saleactiondiscountfromdirectory.php@ — функции @roundBasePrice()@ и @roundDiscountedPrice()@ задают округление базовой и скидочной цены в PHP. * Источник: @infoFiles/component.js@ — функции @roundClientPrice()@ и @roundDiscountedPrice()@ задают клиентское округление в JS. * Примечание: явная реализация @Prices::roundClientPrice()@ в PHP в репозитории не найдена; вероятно, это внешний модуль или историческое имя для текущей логики. h2. Как проверить * Открыть @infoFiles/saleactiondiscountfromdirectory.php@ и сверить правила округления в @roundBasePrice()@/@roundDiscountedPrice()@. * Открыть @infoFiles/component.js@ и сверить правила округления в @roundClientPrice()@/@roundDiscountedPrice()@. h2. 2026-01-27 — Округление базовой цены до скидки и стандартное округление скидочной цены * Изменение: скидка применяется к предварительно округлённой базовой цене (< 10 ₽ → вверх до 0.01, 10–100 ₽ → вверх до 0.1, > 100 ₽ → вверх до целого рубля). * Изменение: скидочная цена округляется по стандартным правилам до 2 знаков после запятой. * Изменение: правила согласованы в JS (витрина) и PHP (корзина/скидки). * Изменение: для неавторизованных пользователей отображается округлённая базовая цена. * Изменение: в JS добавлен устойчивый парсинг цен с запятой (24,60) для корректного расчёта скидки в каталоге. * Изменение: подбор скидки в витрине учитывает разные поля идентификатора товара (SKU/товар), чтобы совпадать с корзиной. * Изменение: при отсутствии клиентской скидки корзина принудительно использует округлённую базовую цену, игнорируя скидки Bitrix. h2. Как проверить * Для цены 123,38 ₽ и скидки 17 % убедиться, что база округляется до 124 ₽, итог — 102,92 ₽. * Для цены 49,83 ₽ и скидки 17 % убедиться, что база округляется до 49,9 ₽, итог — 41,42 ₽. * В гостевом режиме убедиться, что базовая цена отображается уже округлённой. * При отсутствии клиентской скидки убедиться, что корзина показывает ту же цену, что каталог. h2. 2026-01-27 — Контракт products в /sync.php: full всегда, missing ⇒ загрузка из 1С * Изменение: для @entities.products@ полный снимок применяется всегда, значение @full@ игнорируется. * Изменение: отсутствующие на сайте товары больше не считаются ошибкой @not_found@; для них запрашиваются данные в 1С и ставятся задачи в очередь. * Изменение: добавлены метрики @found_count@/@missing_count@/@missing_queued@/@missing_failed@ в ответе @/sync.php@. * Изменение: реализована mark-and-sweep-логика на основе свойства @REST1C_SYNC_ID@ (при отсутствии свойства используется fallback без маркировки). * Изменение: добавлен debug-флаг (@debug=1@ или @X-Debug: 1@) для вывода сводки ответа 1С по products. * Документация: обновлены apidoc @/sync.php@ и справочники @docs/reference/sync-concept.textile@ и @docs/reference/api-details.textile@. h2. Как проверить * Отправить @/sync.php@ с @entities.products.items[]@, включающим один существующий и один отсутствующий XML_ID; убедиться, что @status=success@ и в ответе заполнены @missing_*@ метрики. * Проверить, что отсутствующий XML_ID ставится в очередь RabbitMQ (воркер получает задачу на загрузку из 1С). * При наличии свойства @REST1C_SYNC_ID@ в инфоблоке товаров убедиться, что после запроса оно заполнено текущим @request_id@ и выключаются товары, не попавшие в снимок. h2. 2026-01-27 — Парсинг ответа 1С Products/Info с обёрткой entities.products.items * Изменение: при запросе товаров из 1С добавлена поддержка формата ответа @entities.products.items@ (и @data.entities.products.items@), чтобы не терять данные при нестандартной обёртке. h2. Как проверить * Выполнить запрос к 1С @get_products/Info@, который возвращает обёртку @entities.products.items@, и убедиться, что товары попадают в обработку /sync.php (debug показывает returned > 0). h2. 2026-01-26 — Обновление email при конфликте логина в /clients * Изменение: при дубле логина пользователя в @/clients/@ выполняется попытка обновить @EMAIL@ существующего пользователя и, при наличии отдельного пользователя по XML_ID клиента, обновляется @EMAIL@ у него. * Изменение: добавлено логирование успешного/ошибочного обновления @EMAIL@ для разбора конфликтов. h2. Как проверить * Отправить @/clients/@ с пользователем, чей логин уже существует, и убедиться в логах, что @EMAIL@ обновлён у найденного пользователя. * При наличии пользователя с XML_ID клиента и отличающимся @EMAIL@ проверить, что его email также обновлён и предупреждение @user_exists@ остаётся в ответе. h2. 2026-01-26 — Заполнение UF_USER/UF_CONTRAGENT в HL15 для /clients * Изменение: при обработке пользователей и менеджеров в @/clients/@ в HL15 дополнительно сохраняются @UF_USER@ (XML_ID пользователя/менеджера) и @UF_CONTRAGENT@ (XML_ID контрагента). h2. Как проверить * Отправить @/clients/@ с @users[].XML_ID@ и @UF_XML_ID@ компании и убедиться, что в HL15 заполнены @UF_USER@ и @UF_CONTRAGENT@. * Отправить @/clients/@ с @managers[].MANAGER_XML_ID@ и проверить, что в HL15 у менеджерской записи заполнен @UF_USER@. h2. 2026-01-26 — Приоритет XML_ID над LOGIN при обновлении пользователя * Изменение: если пользователь найден по XML_ID, обновление поля @LOGIN@ не выполняется, чтобы не блокировать обновления из-за конфликтов логина. * Изменение: предупреждение @login_conflict@ больше не создаётся в сценариях, где совпадение найдено по XML_ID. h2. Как проверить * Отправить @/clients/@ с пользователем, у которого XML_ID найден, но логин совпадает с другим пользователем, и убедиться, что warning @login_conflict@ не появляется. * Проверить в логах, что обновление по XML_ID выполнено без попытки изменить @LOGIN@. h2. 2026-01-26 — Приоритет сопоставления пользователей: XML_ID -> LOGIN -> EMAIL * Изменение: при обработке пользователей в @/clients/@ поиск выполняется с приоритетом XML_ID, затем LOGIN, затем EMAIL. * Изменение: при совпадении по LOGIN/EMAIL обновление поля @LOGIN@ не выполняется, чтобы сохранить приоритет и не создавать конфликтов. h2. Как проверить * Отправить @/clients/@ с пользователем, у которого XML_ID не найден, но логин совпадает с существующим — должен быть выбран пользователь по LOGIN. * Отправить @/clients/@ с пользователем, у которого логин не найден, но email совпадает — должен быть выбран пользователь по EMAIL. h2. 2026-01-26 — XML_ID точки доставки при выгрузке заказов * Изменение: для выгрузки заказов в 1С поле @delivery_address@ формируется как XML_ID точки доставки (по HL-справочнику с поиском по @USER_ID@ + @ADDRESS@); при отсутствии соответствия выгрузка завершается ошибкой. * Документация: обновлены apidoc для @/order/syncord_getnew.php@ и справочник @docs/reference/api-details.textile@. h2. Как проверить * Выгрузить заказ через @/order/syncord_getnew.php@ или @/order/export_list.php@ и убедиться, что @delivery_address@ содержит XML_ID точки доставки. * Проверить случай без записи в HL: выгрузка завершается ошибкой о недостающем XML_ID точки доставки. h2. 2026-01-26 — Очередь выгрузки заказов по статусам демона * Изменение: очередь выгрузки в @admin.php@ формируется по статусам, аналогично демону (исключения @ORDER_STATUS_DAEMON_EXCLUDE@, лимит @ORDER_STATUS_DAEMON_LIMIT@, возраст @ORDER_STATUS_DAEMON_MAX_AGE_MINUTES@). * Изменение: при запуске «Передать новые заказы» из admin.php используется тот же статусный отбор, для внешних вызовов @syncord_getnew.php@ логика не меняется. * Документация: обновлена инструкция @docs/how-to/orders-export-queue.textile@. h2. Как проверить * Убедиться, что заказ со статусом не из списка исключений и свежей датой попадает в очередь. * Нажать «Передать новые заказы» в admin.php и проверить выгрузку в 1С. h2. 2026-01-26 — Все заказы для перевыгрузки в админке * Изменение: добавлен раздел «Все заказы для перевыгрузки» в @admin.php@, который показывает последние заказы без фильтрации по статусам и позволяет вручную выгрузить любой заказ. * Изменение: в @OrderService@getExportableOrders добавлен режим @all@ с лимитом и возрастом из переменных демона. * Документация: обновлена инструкция @docs/how-to/orders-export-queue.textile@. h2. Как проверить * Перейти в раздел «Все заказы для перевыгрузки» и убедиться, что отображаются последние заказы. * Нажать «Выгрузить» для произвольного заказа и проверить отправку в 1С. h2. 2026-01-26 — Таблица всех заказов в админке * Изменение: добавлен раздел «Все заказы (таблица)» с колонками ID, дата, статус, сумма, PUSH_1C, контрагент, email, адрес. * Изменение: добавлен поиск по номеру и пагинация по 20 заказов. * Документация: обновлена инструкция @docs/how-to/orders-export-queue.textile@. h2. Как проверить * Открыть «Все заказы (таблица)» и убедиться, что загружены 20 последних заказов. * Выполнить поиск по номеру и проверить, что отображается конкретный заказ. * Нажать «Выгрузить» в строке таблицы и проверить отправку в 1С. h2. 2026-01-26 — Подробные ошибки 1С при выгрузке заказа * Изменение: в ответ админки добавлены детали ошибки 1С: HTTP статус и тело ответа, если они доступны. h2. Как проверить * Нажать «Выгрузить» для заказа и убедиться, что при ошибке отображается HTTP статус и ответ 1С. h2. 2026-01-26 — Проверка XML_ID и цена заказа при выгрузке * Изменение: при формировании payload выгрузки используется фактическая цена позиции корзины. * Изменение: если у позиций нет @PRODUCT_XML_ID@, выгрузка прерывается с ошибкой. h2. Как проверить * Выгрузить заказ с заполненными XML_ID и убедиться, что цена берётся из корзины. * Выгрузить заказ с отсутствующим XML_ID и убедиться, что отображается ошибка о позиции без XML_ID. h2. 2026-01-26 — Запрос данных заказа из 1С в таблице * Изменение: в таблице «Все заказы» добавлена кнопка «Запросить», которая обращается к @Orders/InfoFull@ и показывает ответ в admin.php. h2. Как проверить * В таблице нажать «Запросить» и убедиться, что выводится ответ 1С по заказу. h2. 2026-01-26 — Техотчёт и fallback XML_ID при выгрузке * Изменение: если XML_ID позиции отсутствует в корзине, выполняется попытка чтения XML_ID из каталога по ID товара; при отсутствии — возвращается ошибка. * Изменение: технический отчёт по выгрузке создаётся даже при ошибках формирования payload. * Изменение: для запросов @Orders/InfoFull@ добавлен технический отчёт в @storage/order_info@. h2. Как проверить * Выгрузить заказ с отсутствующим XML_ID в корзине и убедиться, что XML_ID подтягивается из каталога или возвращается ошибка. * Проверить наличие отчёта по выгрузке при ошибке формирования payload. * Нажать «Запросить» и убедиться, что отчёт @order_info_*.json@ доступен для скачивания. h2. 2026-01-26 — Очередь выгрузки заказов в админке * Изменение: в @admin.php@ добавлена карточка «Очередь выгрузки в 1С» со списком заказов по условиям выгрузки и ручной отправкой по клику. * Изменение: технический отчёт по отправке (путь, заголовки, тело, ответ) сохраняется в @storage/order_exports/order_export_.json@ и доступен для скачивания. * Изменение: логика формирования очереди и payload вынесена в @OrderService@ и используется в @order/syncord_getnew.php@ и @order/export_list.php@. * Документация: добавлена инструкция @docs/how-to/orders-export-queue.textile@ и ссылка в индексе. h2. Как проверить * Откройте @/admin.php@, перейдите в «Заказы» и убедитесь, что очередь выгрузки отображает подходящие заказы. * Нажмите «Выгрузить» для одного заказа и убедитесь, что результат успешный и свойство @PUSH_1C@ выставлено. * Скачайте технический отчёт и проверьте поля @request.path@, @request.headers@, @request.body@, @response.body@. h2. 2026-01-26 — Менеджеры при ARGUMENT=false: поиск в IBlock без префикса M * Изменение: в @clients/index.php@ при @ARGUMENT=false@ менеджеры ищутся в @MANAGERS_IBLOCK_ID@ по @MANAGER_XML_ID@ без префикса @M@; проверки @CUser@ и записи менеджеров в HL15 отключены. * Изменение: в @managers/index.php@ нормализация @xml_id@ с префиксом @M@ выполняется только при @ARGUMENT=true@. * Документация: добавлено пояснение в @docs/reference/api-details.textile@. h2. Как проверить * Установить @ARGUMENT=false@ и @MANAGERS_IBLOCK_ID@, отправить @/clients/@ с @MANAGER_XML_ID@ без префикса @M@. * Убедиться, что ошибки @Менеджер M... не найден@ отсутствуют, а лог содержит поиск по @MANAGERS_IBLOCK_ID@ без проверки @CUser@. h2. 2026-01-26 — Документация HL32 * Изменение: добавлено описание HL32 (Consignee) в @docs/reference/configuration.textile@ и упоминание фиксации статуса клиента в @docs/reference/api-details.textile@. * Дополнение: добавлена настройка @HL_CONSIGNEE_ID@ (legacy @HL32_ID@, default 32) в .env и мастер. h2. Как проверить * Открыть раздел «Bitrix: инфоблоки и HL-блоки» и убедиться, что HL32 описан с @HL_CONSIGNEE_ID@/@HL32_ID@ и ссылкой на @clients/HL32.xml@. * Проверить блок @/clients/@ в @docs/reference/api-details.textile@ — есть пункт про запись в HL32. * Убедиться, что в мастере .env доступно поле @HL_CONSIGNEE_ID@ и оно попадает в сгенерированный .env. h2. 2026-01-25 — HL14/HL15 при ARGUMENT=false: Bitrix CUser + HL15 * Изменение: разделены флаги HL-логики и создания пользователей. При заданных HL14/HL15 HL-логика включена, но пользователи создаются через CUser только при @ARGUMENT=true@. * Дополнение: при @ARGUMENT=false@ и заданных HL14/HL15 в @/clients/@ проставляется связь с компанией через HL15 и, при наличии, @UF_PERSONAL_MANAGER@ по менеджеру из IBlock. h2. Как проверить * Установить @ARGUMENT=false@, @HL_CONTRAGENTS_ID@/@HL_ACCESS_RIGHTS_ID@ и отправить клиентов с users/managers. * Убедиться, что пользователи создаются через CUser, а записи HL15 появляются и содержат @UF_USERID@/@UF_CONTRAGENTID@. * Проверить заполнение @UF_PERSONAL_MANAGER@, если в IBlock менеджеров есть элемент с @MANAGER_XML_ID@. h2. 2026-01-25 — Автовключение HL-логики при заданных HL14/HL15 * Изменение: в @clients/index.php@ HL-логика включается автоматически, если заданы @HL_CONTRAGENTS_ID@/@HL_ACCESS_RIGHTS_ID@ (или legacy @HL14_ID@/@HL15_ID@), независимо от @ARGUMENT@. * Логирование: добавлен журналируемый факт автопереопределения при @ARGUMENT=false@. h2. Как проверить * Установить @HL_CONTRAGENTS_ID@ и @HL_ACCESS_RIGHTS_ID@ при @ARGUMENT=false@, вызвать @/clients/@ и проверить наличие записи в логах о включении режима Argument. * Убедиться, что при отсутствии HL-переменных режим Argument управляется значением @ARGUMENT@. h2. 2026-01-25 — Разрешение конфликта composer.lock * Источник для восстановления: @infoFiles/composer.lock@. * Действие: заменён @composer.lock@ на эталон из @infoFiles@ для устранения конфликтных маркеров. * Решение: использовать файл из @infoFiles@ как согласованную версию в контуре CentOS7. h2. 2026-01-25 — Анализ загрузки clients через ZIP * Факт: входной файл @incoming_get-rest1c-clients-index_20260125_112909_824600_pid1253_e0ad.json@ содержит ZIP-архив, а не JSON. * Проверка: архив содержит один файл .txt с JSON (UTF-8, с BOM). * Гипотеза ошибки @invalid_input@: ошибка чтения ZIP/JSON на стороне сервера (ZipArchive/парсинг/пустой поток). h2. Как проверить * Сравнить @composer.lock@ с @infoFiles/composer.lock@ и убедиться, что файлы идентичны. * Запустить @composer install@ и убедиться, что предупреждений о конфликтных маркерах нет. * Убедиться, что ZIP читается на сервере и не падает разбор JSON потока (см. логи). h2. 2026-01-25 — Диагностика JSON-ошибки (clients ZIP) * Изменение: при ошибке JSON в потоковом режиме логируется @json_last_error_msg@ и путь к файлу. * Цель: быстро выявлять причину @Неверный формат JSON@ в логах без изменения контракта ответа. h2. Как проверить (дополнение) * Отправить ZIP и проверить, что в логах есть @json_error@ и путь к распакованному JSON. h2. 2026-01-25 — Увеличение лимита времени для /clients * Изменение: установлен лимит выполнения 600 секунд через @set_time_limit@ в @clients/index.php@. * Цель: избежать @Maximum execution time@ при потоковой обработке больших ZIP. h2. Как проверить (дополнение 2) * Отправить ZIP на @/rest1c/clients/@ и убедиться, что в логах нет @Maximum execution time@. h2. 2026-01-25 — Логирование таймингов без debug * Изменение: тайминги и сводка обработки логируются всегда, даже без @X-Debug@. * Цель: диагностировать узкие места при 503/Timeout без изменения ответа. h2. Как проверить (дополнение 3) * Отправить ZIP без @X-Debug@ и найти в логах запись @clients timings summary@. h2. 2026-01-25 — Обработка дублей пользователей * Изменение: при ошибке создания пользователя с существующим логином фиксируется warning и возвращается существующий user_id. * Добавлено кэширование поиска пользователей по email/login. * Цель: не падать с ошибкой при дублях и ускорить обработку. h2. Как проверить (дополнение 4) * Отправить ZIP с повторяющимися логинами и убедиться, что ошибки создания не переводят результат в fail, а попадают в warnings. h2. 2026-01-25 — Обход конфликтов логинов при обновлении * Изменение: обновление поля LOGIN пропускается, если логин занят другим пользователем. * Добавлен warning @login_conflict@ с контекстом manager/user_id. h2. 2026-01-25 — Смягчение ошибок при дубле без user_id * Изменение: если логин занят и существующий user_id не найден, создание пользователя пропускается с warning, без legacy_error. * В debug добавляется статус пользователя @skipped@. h2. 2026-01-25 — Декомпозиция processing_ms по этапам * Изменение: добавлены тайминги этапов (client_process, users, managers, hl32, discount_collect, users_only) и логирование @client stage timings@ при @X-Debug@. * Цель: выявить самые медленные операции внутри processing_ms. h2. Как проверить (дополнение 5) * Выполнить запрос с @X-Debug@ и найти в логах записи @client stage timings@ и итоговые поля timings.*. h2. 2026-01-25 — Батчирование скидок clients при публикации * Изменение: скидки клиентов публикуются в human-очередь батчами по @RABBITMQ_HUMAN_DISCOUNT_BATCH@ (по умолчанию 1000). * Цель: сократить число publish и ускорить discount_publish_ms. h2. 2026-01-25 — Отдельный батч для скидок clients * Изменение: добавлен параметр @RABBITMQ_HUMAN_DISCOUNT_BATCH_CLIENTS@ для размера батча в @/clients/@. * Цель: снизить нагрузку на @discounts/Manual_Start.php@ без отката батчирования. h2. 2026-01-25 — Ключ скидок по UF_CLIENT_XML_ID * Изменение: обработчики скидок используют ключ @UF_CLIENT_XML_ID@ + @UF_PRODUCT@ и уникальный индекс @uf_client_product@. * Обновление: документация и примеры HL-структуры приведены к использованию @UF_CLIENT_XML_ID@. h2. Как проверить (дополнение 6) * Выполнить @SHOW INDEX FROM discount;@ и убедиться, что есть @uf_client_product@, а @uf_user_product@ отсутствует. * Запустить @php discounts/Manual_Start.php@ и убедиться, что нет ошибок @Unknown column@. h2. 2026-01-26 — Анализ логов bin_error (order status daemon / 1C) * Факт: ошибки @Mysql query error: (2006) MySQL server has gone away@ в order status daemon. * Факт: повторяющиеся ошибки @ONEC_POST_BASE_URL/ONEC_GET_BASE_URL/ONEC_BASE_URL is not set@ приводят к @Failed to load order from 1C@. * Факт: часть запросов в 1C возвращает @502 Bad gateway@ при @GET .../Orders/InfoFull/?Number=ARG48@, что также завершает загрузку заказа ошибкой. * Вывод: причины — разрыв соединения с MySQL и некорректная/отсутствующая настройка URL 1C, а также недоступность 1C-эндпоинта. h2. Как проверить * Проверить доступность MySQL и таймауты соединений во время работы демона. * Убедиться, что в @.env@ заданы @ONEC_POST_BASE_URL@/@ONEC_GET_BASE_URL@ (или @ONEC_BASE_URL@). * Повторить запрос к 1C и убедиться, что 502 исчезает (проверка доступности внешнего сервиса). h2. 2026-01-26 — Снимок документации API 1С * Изменение: сохранен текстовый экспорт документации 1С в @infoFiles/rest1c_onec_api.txt@ для последующего анализа и сопоставления контрактов. h2. Как проверить * Открыть @infoFiles/rest1c_onec_api.txt@ и убедиться, что в файле присутствуют разделы по заказам, товарам и клиентам. h2. 2026-01-26 — Скидки корзины: округление и UF_CLIENT_XML_ID * Изменение: обработчик скидок из справочника использует UF_CLIENT_XML_ID вместо UF_USER. * Изменение: цены и скидки округляются через @Prices::roundClientPrice()@, скидка пересчитывается после округления. * Изменение: добавлен fallback определения client_xml_id из полей пользователя (@UF_XML_ID@/@XML_ID@), если не найден контрагент. * Изменение: дефолтные HL-блоки скорректированы под окружение b2test — компании HL12, права пользователей HL13 (с fallback на HL14/HL15). * Изменение: добавлен разбор полей HL13 @UF_USER_ID@/@UF_CONTRACTOR_XML_ID@/@UF_CONTRACTOR_ID@ при поиске скидки. * Изменение: в шаблоне каталога скидки подгружаются по @UF_CLIENT_XML_ID@ (HL12/HL13), APC-кэш привязан к client_xml_id. * Изменение: во фронтовом компоненте добавлено клиентское округление цены (ceil до 0.1 при цене < 100, иначе до рубля). h2. Как проверить * Выбрать пользователя с заполненным контрагентом и скидкой в HL38 (UF_CLIENT_XML_ID + UF_PRODUCT). * Добавить товар в корзину и убедиться, что цена округлена по правилу (до 0.1 или до рубля вверх). * Проверить, что @DISCOUNT_PRICE@ соответствует разнице @BASE_PRICE@ и итоговой цены после округления. h2. 2026-01-27 — Отказ от префиксов M/U и поиск через HL15 * Изменение: в @/clients/@ поиск пользователей и менеджеров выполняется по HL15 (@UF_USER@ + роль @UL+@/@MANAGER@), префиксы @U@/@M@ не добавляются; legacy-префиксы поддерживаются и нормализуются при сохранении. * Изменение: в @/managers/@ XML_ID менеджеров нормализуются без префикса; legacy-префиксы учитываются при обработке и обновляются в Bitrix. * Изменение: в @/deliverypoint/@ и админ-инструментах принят legacy-префикс @U@ для поиска, но XML_ID приводится к формату без префикса. * Документация: обновлены описания @/clients/@ и @/deliverypoint/@ в reference. h2. Как проверить * Отправить @/clients/@ с @users[].XML_ID@ и @managers[].MANAGER_XML_ID@ без префиксов и убедиться, что в HL15 заполнены @UF_USER@ без @U@/@M@. * Повторить запрос с legacy-префиксами (@U@/@M@) и убедиться, что в HL15 и @CUser.XML_ID@ сохраняются нормализованные значения. * Отправить @/deliverypoint/@ с @user_xml_id@, содержащим @U@, и проверить, что в Bitrix у пользователя XML_ID обновлён без префикса. h2. 2026-01-28 — Анализ повторяющихся запросов клиентов и пользователей после синхронизации * Факт: в логах @infoFiles/backend_b2b_ecobalt@ синхронизация клиентов и пользователей завершилась со статусом @success@, ошибки не зафиксированы. * Факт: те же XML_ID запрашиваются сайтом повторно по точечным запросам, несмотря на их присутствие в отправляемых данных синхронизации. * Вывод: повторение запросов инициируется логикой сайта/портала (постобработка или дозагрузка деталей), а не ошибкой синхронизации Rest1C-API. * Риск: если сайт не сохраняет результат точечных запросов или считает данные неполными, запросы будут повторяться каждые 2 часа. h2. Как проверить * Сопоставить XML_ID из @28-01-2026 08-01-28 Синхронизация клиентов Отправляемые данные.txt@ и @28-01-2026 08-01-28 Синхронизация пользователей портала Отправляемые данные.txt@ с файлами @*_Запрос клиентов_RobotWebsite.txt@ и @*_Запрос пользователей портала_RobotWebsite.txt@. * Проверить логи сайта в момент @28.01.2026 08:01:32–08:02:00@ на предмет ошибок сохранения данных, пришедших от 1С. h2. 2026-01-28 — Анализ ошибок clients за 7 дней (infoFiles/Clients Errors) * Факт: во всех 7 файлах логов повторяются две группы ошибок: @Нет данных пользователей@ и @Нет менеджеров@ для конкретных @UF_XML_ID@. * Факт: иных типов ошибок (exception/invalid/fail) в логах не обнаружено. * Вывод: источник ошибок — неполные данные в загрузке клиентов (отсутствуют массивы users/managers для ряда контрагентов), а не сбой обработки на стороне API. h2. Как проверить * Открыть любой файл @errors_post-rest1c-clients-index_*.log@ и найти записи @Нет данных пользователей@/@Нет менеджеров@. * Сопоставить проблемные @UF_XML_ID@ с входным payload синхронизации клиентов и убедиться, что для этих контрагентов нет @users[]@ или @managers[]@. h2. 2026-01-30 — Блокировка отметки выгрузки и фильтр пустых ответов 1С * Изменение: отключена установка свойства @PUSH_1C@ при отметке выгрузки, обработчик @/order/syncord_set1cok.php@ больше не изменяет заказы. * Изменение: при синхронизации заказов обновление пропускается, если 1С вернула пустую структуру без ключевых данных. h2. Как проверить * Отправить запрос в @/order/syncord_set1cok.php@ и убедиться, что ответ содержит сообщение об отключённой отметке, а @PUSH_1C@ не изменяется. * Выполнить @/order/sync.php@ для заказа с пустым ответом 1С и убедиться, что в отчёте есть ошибка и локальный заказ не обновлён. h2. 2026-01-30 — Ошибки 1С при Orders/Create: fail, расширенные errors и событие Restboard * Изменение: при ошибках 1С на @/order/create.php@ и @/order/export_list.php@ возвращается @status = "fail"@, а расширенная ошибка 1С сохраняется в @errors@. * Изменение: добавлено отдельное логирование и событие Restboard с типом @invalid 1C response@; ошибки помечаются как требующие повторной попытки позже. h2. Как проверить * Вызвать @/order/create.php@ так, чтобы 1С вернула ошибку (400), и убедиться, что ответ содержит @status = "fail"@ и текст ошибки 1С в @errors@. * Проверить логи: запись @Invalid 1C response@ и событие Restboard с типом @invalid 1C response@. h2. 2026-01-28 — Логирование проксирования в /sync.php * Изменение: добавлено логирование всех проксирований из @sync.php@ в @/clients/@ и @/deliverypoint/@ с указанием причины (reload/sync/fallback) и контекста (request_id, количество элементов, источник payload). * Цель: видеть факт дозапросов после sync и повод, по которому выполняется проксирование. h2. Как проверить * Выполнить @/sync.php@ с @entities.clients.items[].reload=true@ и убедиться, что в логах есть запись @Clients reload proxy: вызов /clients/@. * Выполнить @/sync.php@ с @entities.users.items[].reload=true@ и убедиться, что в логах есть записи @Users reload proxy: вызов /deliverypoint/@ (и при fallback — @Users reload proxy (fallback): вызов /deliverypoint/@). * Выполнить @/sync.php@ в режиме @delivery_points.async=false@ и убедиться, что в логах есть запись @Delivery points sync proxy: вызов /deliverypoint/@. h2. 2026-01-28 — Проверка причин reload по логам /sync.php * Факт: в логах @infoFiles/errors/errors_post-rest1c-sync_20260128_0919*.log@ значения @reload_tasks@ равны @0@ для всех сущностей. * Факт: в логах @errors_post-rest1c-sync_latest.log@ нет записей о reload/proxy, только ответ Restboard 401. * Вывод: по доступным debug-логам 28.01.2026 reload в @/sync.php@ не выполнялся. h2. Как проверить * Открыть @errors_post-rest1c-sync_20260128_091934_243686_pid1439051_6753.log@ и убедиться, что @reload_tasks@ = 0 для clients. * Открыть @errors_post-rest1c-sync_20260128_091934_543385_pid1439064_9866.log@ и убедиться, что @reload_tasks@ = 0 для users. h2. 2026-01-28 — Админка: автопереход к результату "Запросить" в таблице заказов * Изменение: форма "Запросить" в таблице заказов сохраняет якорь @#orders-table@, а результат выводится с авто‑скроллом к блоку ответа. * Цель: сразу показывать ответ 1С после POST, даже если пользователь находится выше по странице. h2. Как проверить * Открыть @/admin.php#panel-orders@, нажать "Запросить" в таблице заказов. * Убедиться, что после перезагрузки страница позиционируется на блоке результата и он виден без ручного скролла. h2. 2026-01-28 — Уведомления: защита от отсутствия PHPMailer * Изменение: если PHPMailer не установлен/недоступен, отправка email пропускается с логированием, а Restboard продолжает работать. * Причина: административные запросы к 1С вызывали fatal error "Class PHPMailer not found". h2. Как проверить * На окружении без PHPMailer выполнить "Запросить" в панели заказов и убедиться, что ответ формируется без fatal error. * Проверить лог: есть запись о пропуске email и попытка отправки события в Restboard. h2. 2026-01-30 — Смешанные пакеты /clients с полными данными и скидками * Изменение: если у клиента нет users/managers, но есть discounts, секции users/managers пропускаются с warning независимо от режима. * Изменение: если у клиента нет users/managers и нет discounts, это считается ошибкой (поведение сохранено). * Документация: обновлено описание @/clients/@ в @docs/reference/api-details.textile@ и apidoc-блоке @clients/index.php@. h2. Как проверить * Отправить @/clients/@ с двумя клиентами: первый с полными данными (users/managers), второй только с @discounts[]@ и @UF_XML_ID@. Убедиться, что по второму клиенту добавлены warnings @section_skipped@, а запрос не падает в @fail@ из-за отсутствия users/managers. * Отправить @/clients/@ с клиентом без users/managers и без discounts. Убедиться, что в ответе есть ошибка @Нет данных пользователей@/@Нет менеджеров@ и статус @fail@ или @partial_success@. h2. 2026-01-30 — Восстановление документации /managers/ * Документация: расширено описание @/managers/@ в @docs/reference/api-details.textile@ (параметры, ответы, примеры, проверка). * Документация: приведён apidoc-блок @managers/index.php@ к стандартному формату ответа (@status/data/errors@) и добавлен флаг @full@. h2. Как проверить * Открыть @docs/reference/api-details.textile@ и убедиться, что раздел @/managers/@ содержит примеры запроса/ответа и блок "Как проверить". * Сгенерировать apidoc и убедиться, что описание @/managers/@ содержит @data.success[]@ и @errors[]@. h2. 2026-01-30 — Включение managers в сборку apidoc * Документация: в @scripts/build-apidoc.sh@ добавлен каталог @managers@ в список входов apidoc. * Документация: в apidoc-блоке @managers/index.php@ параметры помечены как опциональные для корректной сборки без warning'ов. h2. Как проверить * Запустить @bash scripts/build-apidoc.sh@ и убедиться, что в @apidoc/index.html@ присутствует раздел @/managers/@. h2. 2026-01-30 — Поле пароля для /managers/ * Изменение: добавлено поле @managers[].password@ для регистрации менеджера с заданным паролем. * Документация: обновлён раздел @/managers/@ в @docs/reference/api-details.textile@ и apidoc-блок @managers/index.php@. h2. Как проверить * Отправить @/managers/@ с @managers[].password@ и убедиться, что учётная запись создаётся с указанным паролем. h2. 2026-01-30 — Отправка пароля менеджеру * Изменение: после успешной регистрации пароль отправляется на email менеджера. * Документация: добавлено описание в @docs/reference/api-details.textile@. h2. Как проверить * Зарегистрировать менеджера и убедиться, что письмо с паролем приходит на его email. h2. 2026-02-02 — Проверка правил отправки сообщений в Restboard * Факт: базовая отправка в Restboard выполняется через @src/Service/RestboardService.php@, метод @sendEvent@, с обязательным полем @status@ и допустимыми значениями @success/error/inprogress/warning@. * Факт: если @RESTBOARD_SITE@ не задан, событие не отправляется, в лог пишется причина, выполнение не прерывается. * Факт: токен берётся из @RESTBOARD_TOKEN@, иначе fallback на @API_TOKEN@/@TOKEN@, и передаётся в заголовке @X-Restboard-Token@. * Факт: @details@ может передаваться массивом и сериализуется в JSON, @time@ заполняется по умолчанию. * Факт: уведомления через @NotificationService@ нормализуют статусы (@fail@ → @error@, @partial@ → @warning@) и дублируют события в Restboard. h2. Как проверить * Задать @RESTBOARD_SITE@ и вызвать любой публичный endpoint (например, @/sync.php@) так, чтобы он отправил событие, затем проверить лог @Restboard response@. * Очистить @RESTBOARD_SITE@ и убедиться, что в логах есть запись @Restboard disabled: RESTBOARD_SITE not configured@ без падения обработки. h2. 2026-02-02 — Отключение симлинков _latest.log * Изменение: в @src/Logging/LogPathResolver.php@ отключено создание симлинков @*_latest.log@ при формировании уникального файла обмена. * Причина: симлинки больше не требуются для работы логирования. h2. Как проверить * Выполнить любой обмен и убедиться, что создаётся уникальный лог-файл, но файлы вида @*_latest.log@ не появляются. h2. 2026-02-02 — Добавление сущности orders в /sync.php * Изменение: в @/sync.php@ добавлена сущность @orders@ с обработкой списка @items[].XML_ID@. * Логика: для каждого XML_ID выполняется запрос в 1С через @Orders/InfoFull@ и синхронизация заказа в Bitrix. * Документация: обновлены @docs/reference/sync-concept.textile@, @docs/reference/api-details.textile@ и обзор эндпоинтов. h2. Как проверить * Отправить в @/sync.php@ JSON с @entities.orders.items[]@ и убедиться, что в ответе появились метрики @orders.processed/requested/synced/errors@. * Проверить лог @Начало обработки /sync.php@ и наличие записи @Orders/InfoFull@ с переданными XML_ID. h2. 2026-02-02 — Инструмент правки XML_ID заказов в admin.php * Изменение: в @admin.php@ добавлен инструмент «Правка XML_ID заказов (GUID из 1С)». * Логика: по списку ID или периоду запрашивается @Orders/InfoFull@, извлекается GUID заказа и обновляется @XML_ID@ в Bitrix. * Поддерживается @dry-run@ и фильтр «только bx_». * Документация: добавлен how-to @docs/how-to/orders-xml-id-fix.textile@ и ссылка в индекс. h2. Как проверить * В @admin.php@ → «Операции с заказами» запустить инструмент в @Dry-run@ на 1–2 заказах и убедиться, что GUID подставлен в отчёт. * Повторить без @Dry-run@ и проверить, что XML_ID заказа изменён и отчёт содержит статус @updated@. h2. 2026-02-03 — Подключение Bitrix для правки XML_ID заказов * Изменение: в @admin.php@ добавлена функция @ensureBitrixSale()@ и вызов перед обработкой правки XML_ID заказов. * Результат: при запуске инструмента корректно подключается Bitrix prolog и модуль @sale@, исключается ошибка @Class "Bitrix\\Main\\Loader" not found@. h2. Как проверить * Открыть @admin.php@ → «Операции с заказами» → «Правка XML_ID заказов». * Запустить в режиме @Dry-run@ и убедиться, что отчёт формируется без ошибки @Class "Bitrix\\Main\\Loader" not found@. h2. 2026-02-03 — Диапазоны ID для правки XML_ID заказов * Изменение: в поле «Список заказов» поддержан ввод диапазона в формате @id 1-100@ (включительно). * Результат: инструмент принимает диапазоны и расширяет их в список ID перед запросами в 1С. h2. Как проверить * В @admin.php@ → «Операции с заказами» → «Правка XML_ID заказов» ввести @id 101-103@ и включить @Dry-run@. * Убедиться, что в отчёте присутствуют записи для заказов @101@, @102@, @103@. h2. 2026-02-03 — Исправление парсинга дат в правке XML_ID заказов * Проблема: вызов @Bitrix\\Main\\Type\\DateTime::createFromFormat()@ отсутствует в версии Bitrix и приводит к ошибке. * Изменение: дата собирается через @DateTimeImmutable::createFromFormat()@ и конвертируется в @Bitrix\\Main\\Type\\DateTime::createFromPhp()@. h2. Как проверить * В @admin.php@ → «Операции с заказами» задать диапазон дат и запустить @Dry-run@. * Убедиться, что инструмент не падает с ошибкой @createFromFormat@ и формирует отчёт. h2. 2026-02-03 — Диапазоны без префикса id для правки XML_ID заказов * Изменение: парсер списка заказов принимает диапазон в формате @1-100@ без префикса @id@. * Результат: запись @1-100@ разворачивается в список ID от 1 до 100. h2. Как проверить * В @admin.php@ → «Операции с заказами» → «Правка XML_ID заказов» ввести @1-3@ и включить @Dry-run@. * Убедиться, что в отчёте присутствуют записи для заказов @1@, @2@, @3@. h2. 2026-02-04 — GUID в запросах Orders/InfoFull и внутренних сценариях * Изменение: @order/info_full.php@ принимает @GUID@/@guid@ и использует его для запроса в 1С без префикса. * Изменение: @OrderService::getInfoFull()@ определяет GUID и передаёт его в query-параметре @GUID@, для номера продолжает использовать @Number@ с @ORDER_PREFIX@. * Изменение: синхронизация и проверка заказов принимают GUID и загружают локальный заказ по @XML_ID@. h2. Как проверить * Вызвать @/order/info_full.php@ с @GUID@ и убедиться, что ответ приходит из 1С. * В @/order/check.php@ передать @orders.number@ в формате GUID и убедиться, что запрос к 1С выполняется без префикса. h2. 2026-02-05 — Автозаполнение XML_ID заказа по GUID из Orders/Create * Изменение: после успешного @Orders/Create@ сервис обновляет @XML_ID@ заказа в Bitrix по GUID/@XML_ID@ из ответа 1С. * Логика: GUID извлекается из полей @GUID@/@XML_ID@/@xml_id@ и применяется к локальному заказу, если он найден по номеру. h2. Как проверить * Вызвать @/order/create.php@ (или @/order/export_list.php@) и убедиться, что ответ 1С содержит @GUID@. * Проверить, что @XML_ID@ заказа в Bitrix обновился на полученный GUID, а в логах есть запись @Order XML_ID updated from 1C GUID@. h2. 2026-02-05 — Обновление ID_1C после Orders/Create * Изменение: после успешного @Orders/Create@ при наличии @status.xml_id@ в ответе 1С поле @b_sale_order.ID_1C@ обновляется на @status.xml_id@. * Логика: обновление выполняется для одиночного ответа и для массива объектов, без дополнительных запросов в 1С. h2. Как проверить * Вызвать @/order/export_list.php@ или @/order/create.php@ для заказа, по которому 1С возвращает @status.xml_id@. * Проверить, что в @b_sale_order.ID_1C@ записан @status.xml_id@ из ответа 1С. h2. 2026-02-05 — Автосмена STATUS_ID после Orders/Create * Изменение: после успешного @Orders/Create@ при наличии @status.xml_id@ в ответе 1С статус Bitrix (@STATUS_ID@) обновляется на сопоставленный статус 1С. * Логика: используется маппинг по имени статуса и/или XML_ID статуса Bitrix. h2. Как проверить * Отправить заказ через @/order/export_list.php@ или @/order/create.php@. * Убедиться, что @STATUS_ID@ заказа в Bitrix сменился на статус, соответствующий @status.xml_id@ из ответа 1С. h2. 2026-02-05 — Переход на Orders/InfoFull в инструкциях по заказам * Изменение: how-to по запросу заказа обновлён с @Orders/Info@ на @Orders/InfoFull@. * Логика: для GUID используется параметр @GUID@ без префикса, для номера — параметр @Number@. h2. Как проверить * Открыть @docs/how-to/orders-info-request.textile@ и убедиться, что используется @Orders/InfoFull@. h2. 2026-02-05 — Очередь Orders/Create и воркер * Изменение: @/order/create.php@ переводится на постановку заказов в очередь RabbitMQ, ответ теперь @status = "queued"@. * Добавлен CLI-воркер @order/Rabbit.php@ с retry/DLQ для отправки заказов в 1С. * Добавлен systemd-сервис @rest1c-order-create-daemon.service@ для запуска воркера. h2. Как проверить * Вызвать @/order/create.php@ и убедиться, что ответ содержит @status = "queued"@ и @request_id@. * Проверить, что сообщение попадает в очередь @.orders_create.v1@. * Запустить @php order/Rabbit.php@ и убедиться по логам, что заказ отправлен в 1С. h2. 2026-02-05 — Синхронизация заказов по контрагенту и статусам * Изменение: при синхронизации заказа проверяется контрагент (свойство @CONTRAGENT@) и связь пользователя с компанией через HL15. * Изменение: поддержан новый формат статуса из 1С через объект @status{name, xml_id}@ при сохранении строкового поля @Статус@. * Улучшена диагностика /sync.php по заказам (логирование списка XML_ID и заполнение @id_value@ в ошибках). h2. Как проверить * Выполнить @/sync.php@ по заказам и убедиться, что при несоответствии контрагента синхронизация не выполняется. * Проверить, что при наличии @status@ объект корректно маппится в @STATUS_ID@ Bitrix. * Убедиться, что в @errors_ext@ заполнено поле @id_value@. h2. 2026-02-05 — setOrderStage: изменение статуса заказа * Изменение: добавлен endpoint @/order/set_stage.php@ для проксирования изменения статуса заказа в 1С. * Поддержка query-параметров @source@ и @responseFormat=ZIP@ (ZIP с @response.json@). * Изменение: при синхронизации и при @setOrderStage@ в @b_sale_order.ID_1C@ сохраняется последний статус 1С (@status.xml_id@). * Изменение: при запросе @/order/info_full.php@ при наличии @status.xml_id@ обновляется @b_sale_order.ID_1C@ (по GUID/XML_ID или номеру). h2. Как проверить * Отправить запрос на @/order/set_stage.php@ с валидным @token@, @xml_id@ и @status.xml_id@. * Убедиться, что ответ содержит @result = success@. * При @responseFormat=ZIP@ проверить, что возвращается ZIP-архив с @response.json@. * Выполнить запрос @/order/info_full.php@ и проверить запись @ID_1C@ для заказа. h2. 2026-02-09 — Единый entrypoint воркеров и автосинхронизация systemd * Изменение: добавлен единый CLI @bin/worker@ с командами @--task@, @--list@, @--list-instances@ и @--validate-config@. * Изменение: добавлен реестр задач @config/workers.php@ (source of truth для запуска воркеров). * Изменение: добавлен шаблон @systemd/rest1c-worker@.service@ и скрипт @bin/workers-sync-systemd@ для автоподнятия/отключения инстансов. * Изменение: деплойные workflow и composite action обновлены: после обновления кода выполняются @php bin/worker --validate-config@ и синхронизация @workers-sync-systemd --apply@. * Документация: обновлены @docs/reference/configuration.textile@, @docs/reference/endpoints-overview.textile@, @docs/how-to/deploy.textile@, @docs/DEPLOY.textile@; добавлен how-to @docs/how-to/workers-autosync.textile@. h2. Как проверить * Выполнить @php bin/worker --validate-config@ и убедиться, что вывод содержит @OK:@. * Выполнить @php bin/worker --list@ и убедиться, что есть задачи @products@, @orders_create@, @delivery_points@, @discounts@. * Выполнить @bin/workers-sync-systemd --dry-run@ и проверить список действий для unit-инстансов. * На сервере после деплоя проверить @systemctl list-units "rest1c-worker@*.service" --no-pager@. h2. 2026-02-11 — Точный поиск CUser в managers/clients без ложного ID=1 * Изменение: добавлены общие helper-функции @rest1cFindUserByExactCriteria@/@rest1cFindUserByFieldExact@ в @functions.php@ для точного поиска пользователей. * Логика: после @CUser::GetList@ выполняется строгая пост-проверка совпадения фактических значений полей (@XML_ID@, @EMAIL@, @LOGIN@), чтобы исключить ложные попадания. * Изменение: в @managers/index.php@ заменены выборки пользователей по @XML_ID@/@EMAIL@ в сценариях @sync_by_xml_id@, @sync_by_email@, @setXML_ID@, @deactivateManager@. * Изменение: в @clients/index.php@ заменены выборки пользователей по @XML_ID@/@EMAIL@/@LOGIN@ в функциях поиска и в fallback-ветках создания/обновления пользователей. * Совместимость: контракт публичных endpoint'ов не изменён (PATCH-исправление внутренней логики). h2. Как проверить * Отправить @POST /rest1c/managers/@ с менеджером, у которого @xml_id@ ранее приводил к ошибке @admin_user_protected ... (sync_by_xml_id)@, и убедиться, что ложного попадания в @ID=1@ больше нет. * Отправить @POST /rest1c/clients/@ с пользователями/менеджерами и убедиться, что поиск по @XML_ID@/@EMAIL@/@LOGIN@ работает без привязки к системному пользователю. * Проверить логи и убедиться, что при несоответствии фильтра фиксируется warning @CUser::GetList вернул запись с несовпадающим значением поля@. * Выполнить @php -l functions.php@, @php -l managers/index.php@, @php -l clients/index.php@. h2. 2026-02-11 — Исправление prune в workers-sync-systemd * Изменение: в @bin/workers-sync-systemd@ добавлен пропуск шаблонного unit @rest1c-worker@.service@ без инстанса. * Причина: при @set -u@ пустой instance в индексе массива @DESIRED_MAP[]@ вызывал падение @bad array subscript@. * Совместимость: поведение запуска инстансов не изменено; исправлена только обработка prune-цикла. h2. Как проверить * Выполнить @bin/workers-sync-systemd --apply@ на сервере и убедиться, что скрипт завершается без @bad array subscript@. * Проверить, что лишние инстансы по-прежнему отключаются, а активные из @php bin/worker --list-instances@ остаются включёнными. h2. 2026-02-11 — Жёсткая синхронизация LOGIN=EMAIL в clients/managers * Изменение: в @clients/index.php@ для пользователей включён инвариант @LOGIN = EMAIL@ во всех ветках поиска/обновления/создания. * Изменение: в @managers/index.php@ обновление менеджера теперь принудительно выравнивает @LOGIN@ и @EMAIL@; при конфликте email с другой учётной записью возвращается ошибка. * Документация: обновлены apidoc-блоки @/clients/@ и @/managers/@, а также @docs/reference/api-details.textile@. h2. Как проверить * Отправить @POST /rest1c/managers/@ для существующего менеджера с отличающимся @LOGIN@ и убедиться, что после синхронизации @LOGIN == EMAIL@. * Отправить @POST /rest1c/clients/@ для пользователя с отличающимся @LOGIN@ и убедиться, что после синхронизации @LOGIN == EMAIL@. * Смоделировать конфликт (email уже занят чужим login) и убедиться, что в ответе появляется ошибка, а не warning. h2. 2026-02-11 — CUser-синхронизация managers и в ARGUMENT=false * Изменение: в @managers/index.php@ выделена общая функция @syncManagerCUser()@ и подключена в обеих ветках @ARGUMENT=true/false@. * Изменение: legacy-ветка (@ARGUMENT=false@) сохраняет обновление инфоблока (@processManagerLegacy@), но дополнительно синхронизирует @CUser@ (включая инвариант @LOGIN=EMAIL@). * Изменение: @deactivateMissingManagers()@ возвращает список деактивированных XML_ID для последующей диагностики. * Изменение: добавлена диагностика @logLegacyCUserFullSyncMismatches()@ — при @full=true@ в legacy-режиме для отсутствующих менеджеров @CUser@ не деактивируются, а расхождения логируются как предупреждения. * Документация: обновлены apidoc в @managers/index.php@ и описание в @docs/reference/api-details.textile@. h2. Как проверить * При @ARGUMENT=false@ отправить @POST /rest1c/managers/@ и убедиться, что одновременно обновляются и инфоблок менеджеров, и @CUser@. * При @ARGUMENT=false@/@full=true@ убрать менеджера из payload и убедиться, что элемент инфоблока деактивируется, а @CUser@ остаётся активным, при этом в логах есть warning. * Проверить, что при конфликте email с другой учётной записью менеджер получает ошибку синхронизации @CUser@. h2. 2026-02-11 — Поиск managers по LOGIN и пост-синхронизация после регистрации * Изменение: в @syncManagerCUser()@ добавлен fallback-поиск существующего пользователя по @LOGIN@ (если не найден по @EMAIL@). * Изменение: после успешной регистрации менеджера добавлена дополнительная синхронизация полей @EMAIL/LOGIN@, чтобы инвариант @LOGIN=EMAIL@ применялся в рамках одного запроса. * Причина: кейс, когда у существующего пользователя @LOGIN@ совпадал с входным email, но @EMAIL@ отличался, приводил к повторной регистрации вместо обновления. h2. Как проверить * Подготовить пользователя с @LOGIN=email_из_payload@ и отличающимся @EMAIL@, отправить @POST /rest1c/managers/@ и убедиться, что запись обновляется без повторной регистрации. * Отправить @POST /rest1c/managers/@ для нового менеджера и убедиться, что после регистрации @LOGIN@ и @EMAIL@ выровнены в одной операции. h2. 2026-02-11 — Приоритет менеджера над клиентом в managers * Изменение: в @syncManagerCUser()@ добавлен manager-priority режим для конфликтов @XML_ID/LOGIN/EMAIL@. * Логика: конфликтный пользователь переносится на технические реквизиты (@mgr_archived_*@, @manager.local@, технический @XML_ID@), после чего данные менеджера применяются повторно. * Логика: если @XML_ID@ и @LOGIN/EMAIL@ заняты разными пользователями, освобождаются оба конфликта и создаётся/обновляется целевая учётная запись менеджера. * Совместимость: формат ответа endpoint не изменён, изменена бизнес-логика разрешения конфликтов. h2. Как проверить * Подготовить конфликт, где @LOGIN@ занят клиентским пользователем, а @XML_ID@ — другой записью, выполнить @POST /rest1c/managers/@ и убедиться, что менеджер получает входные @XML_ID/LOGIN/EMAIL@. * Проверить, что у конфликтных пользователей после операции установлены технические реквизиты (@mgr_archived_*@, @manager.local@, технический @XML_ID@). h2. 2026-02-13 — Обновление пароля существующего менеджера через /managers/ * Изменение: в @managers/index.php@ функция @buildUserUpdateFields()@ дополнена обработкой @managers[].password@ для существующего @CUser@. * Логика: если @password@ передан и непустой, в обновление пользователя добавляются @PASSWORD@ и @CONFIRM_PASSWORD@. * Совместимость: структура API-ответа не изменена; изменение относится к PATCH-поведению endpoint @/managers/@. * Документация: уточнён apidoc-блок @/managers/@ в @managers/index.php@ и раздел endpoint в @docs/reference/api-details.textile@. h2. Как проверить * Отправить @POST /rest1c/managers/@ для существующего менеджера с полем @password@ и убедиться, что ответ успешный, а учётная запись принимает новый пароль. * Отправить @POST /rest1c/managers/@ для существующего менеджера без @password@ (или с пустым значением) и убедиться, что пароль не изменяется. * Отправить @POST /rest1c/managers/@ для нового менеджера с @password@ и убедиться, что регистрация выполняется с указанным паролем.