Про эталонный справочник, JWT-авторизацию, требования КИИ и почему 1С-Битрикс вместо Laravel

В 2022 году мы получили задачу: автоматизировать заказы запчастей для 40+ дилеров. Вызов был не в объёме данных (50,000 SKU), а в разнородности систем дилеров и требованиях безопасности КИИ.

Через 18 месяцев 65% заказов пошли через портал без участия операторов. REST API интегрирован с 28 дилерами (70% сети). Время оформления заказа сократилось с 45 минут до 7.

Под катом — архитектурные решения, почему эталонный справочник важнее REST API, и как обойти ограничения КИИ.

Техническое задание в двух абзацах

Задача: веб-портал для заказа запчастей с интеграцией в 1С дилеров.

Контекст: Сельхозпроизводитель из Ростова-на-Дону — группа из 13 предприятий на 11 производственных площадках в 5 странах. Продуктовая линейка: 150+ моделей и модификаций, 24 типа техники. Дилерская сеть: 40+ партнеров на территории РФ (по данным из ТЗ).

Целевая аудитория: две группы клиентов — небольшие сельхозкомпании (до 30 единиц техники) и крупные агрохолдинги (свыше 30 единиц техники).

Бизнес-проблемы из ТЗ:

  • Отсутствие веб-каталога запчастей

  • Нет удобного поиска для 50,000 SKU

  • Невозможнос��ь быстро сформировать заказ

  • Нет отслеживания статусов заказов

Ограничения КИИ: запрещены западные фреймворки, облачные сервисы за пределами РФ, npm-пакеты без аудита.

Требования: визуализация каталога, поиск по артикулу/модели/серийному номеру, REST API для real-time остатков, автоматическая передача заказов в 1С, личный кабинет для управления парком техники. Оформление заказа без регистрации (гостевой checkout).

Архитектура: шесть уровней интеграции

┌─────────────────────────────────────────────────────────┐
│ Уровень 1: Корпоративные системы завода                │
│ ┌──────────┐  ┌──────────┐                             │
│ │ SEARCH   │  │ SAP CRM  │                             │
│ │(составы) │  │(дилеры)  │                             │
│ └────┬─────┘  └────┬─────┘                             │
│      │             │                                    │
└──────┼─────────────┼────────────────────────────────────┘
       │             │
       ▼             ▼
┌─────────────────────────────────────────────────────────┐
│ Уровень 2: Интеграционный мост                          │
│ ┌──────────────────────────────────────┐                │
│ │ PPM (сельхозпроизводитель)                 │                │
│ │ API Workbench (Docware)              │                │
│ └──────────────────┬───────────────────┘                │
└────────────────────┼────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────┐
│ Уровень 3: Электронный каталог                          │
│ ┌──────────────────────────────────────┐                │
│ │ PartsPublisher (Docware)             │                │
│ │ БД запчастей + визуализация         │                │
│ └──────────────────┬───────────────────┘                │
└────────────────────┼────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────┐
│ Уровень 4: CMS портала                                  │
│ ┌──────────────────────────────────────┐                │
│ │ 1С-Битрикс                           │                │
│ │ + Эталонный справочник запчастей     │                │
│ └──────────────────┬───────────────────┘                │
└────────────────────┼────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────┐
│ Уровень 5: REST API                                     │
│ ┌──────────────────────────────────────┐                │
│ │ JWT auth + 5 методов                 │                │
│ └──────────────────┬───────────────────┘                │
└────────────────────┼────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────┐
│ Уровень 6: Системы ди��еров                              │
│ ┌──────────┐  ┌──────────┐  ┌──────────┐               │
│ │ 1С:УТ 11 │  │ 1С:ERP   │  │ Custom   │               │
│ │  (60%)   │  │  (25%)   │  │  (15%)   │               │
│ └──────────┘  └──────────┘  └──────────┘               │
└─────────────────────────────────────────────────────────┘

Уровень 1-2: От завода к PartsPublisher

SEARCH — внутренняя система завода. Хранит составы изделий (какие детали в каких узлах), групповые замены, иллюстрации с хотспотами, привязку к серийным номерам. Выгружает файлы раз в сутки:

SOSTAV.txt — составы изделий. Структура: Module (модуль), Part (деталь), RU_number (российский номер), RU_name (название на русском), Quantity (количество), MU (единица измерения), Pos (позиция), STARTDATE/ENDDATE (даты начала/окончания использования), FE/BF (флаги), EN_number/EN_name (английские версии), плюс 46 полей для опций (Option1...Option46) для привязки к модификациям техники.

MATERIAL.txt — материалы и детали с атрибутами.

SUBS.txt — замены деталей (групповые, локальные, глобальные).

IMAGES.txt — список иллюстраций с хотспотами для визуализации узлов.

SERNUM.txt — серийные номера техники с привязкой к модификациям.

SAP CRM — данные о дилерах. Интеграция через SOAP Web Service (метод ZwsPartners). Возвращает структуру EtPartner с полями:

Partner (номер партнёра), Crdat (дата создания), Addrnumber (номер адреса), NameOrg1/NameOrg2 (названия организации), Country (код страны), Landx (название страны), Subject (регион), Region (область/край), City (город), PostlCod1 (индекс), Street (улица), HouseNo (номер дома), ClientTel (телефон), SmtpAddr (email), UriSrch (сайт), Zzzlongitude/Zzzlatitude (GPS-координаты склада).

GPS-координаты критичны для функции "определение ближайшего дилера по геопозиции клиента".

PPM — интеграционный мост от производителя. Забирает файлы из SEARCH и данные из SAP, трансформирует в формат PartsPublisher, вызывает API Workbench (библиотека Docware) для импорта. Автозапуск раз в сутки, есть ручной режим.

Уровень 3: PartsPublisher

PartsPublisher (Docware) — не просто БД, а специализированная система для автокаталогов. Умеет:

Работать с разными типами замен — групповые (деталь А → деталь Б для всех моделей), локальные (только для конкретной модификации), глобальные (на всю линейку), односторонние/двухсторонние.

Визуализировать узлы с хотспотами — клик на деталь на схеме → карточка детали с артикулом, названием, ценой, сроками доставки.

Фильтровать по серийным номерам — вводишь номер машины → система определяет модификацию → показывает только совместимые детали (критично для снижения ошибок подбора).

Функциональность из ТЗ: общий фильтр по узлам, поиск по названию узла, выбор версии узла (принадлежность к конкретной технике), масштабирование изображений, печать схемы узла, добавление в корзину прямо со схемы.

Это готовая система с логикой, которую иначе пришлось бы писать руками.

Уровень 4: 1С-Битрикс и эталонный справочник

Выбор CMS был ограничен требованиями КИИ. Западные фреймворки запрещены. Рассматривали российские решения: 1С-Битрикс, ModX, собственную разработку на чистом PHP.

Выбрали 1С-Битрикс по причинам:

Соответствие требованиям КИИ (российское ПО, сертификат ФСТЭК). Готовый REST API framework — не нужно писать с нуля. Документация на русском, большое комьюнити. Критично для дилеров — много 1С-программистов знают Битрикс.

Минусы есть — легаси в ядре, странные архитектурные решения, нет нормального DI. Но плюсы перевесили.

Эталонный справочник — ключевой элемент интеграции. У 40+ дилеров разная структура БД в 1С. Одна запчасть у всех записана по-разному. Нельзя заставить дилеров унифицировать базы — политически невозможно. Нельзя использовать AI/ML для сопоставления — 10-15% ошибок неприемлемы в B2B.

Решение: единая номенклатура в Битрикс с уникальными кодами rsm_id. Дилер один раз сопоставляет свои позиции с эталоном. При передаче остатков отправляет только rsm_id + quantity. Битрикс сопоставляет с эталоном и обновляет остаток. Если rsm_id нет в справочнике — игнорируется.

Сопоставление — разовая работа на 2-3 дня программиста 1С. Дальше всё автоматом.

Уровень 5-6: REST API и 1С дилеров

У дилеров три типа конфигураций: 1С:Управление торговлей 11 (60%), 1С:ERP 2.0 (25%), кастомные на базе 8.3 (15%). API должен работать со всеми.

Принцип — минимализм. Пять методов закрыли 95% задач.

REST API: пять методов

1. Авторизация JWT

POST /api/token/get/
Content-Type: application/json

{
  "login": "dealer_krasnodar",
  "password": "secret"
}

Ответ:

json

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6ImFjY2VzcyJ9...",
  "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6InJlZnJlc2gifQ..."
}

access_token живёт 24 часа, refresh_token — 60 дней. Обновление через POST /api/token/refresh/ с refresh_token в заголовке.

2. Передача остатков

POST /api/remains/?store_id=23
Authorization: Bearer {access_token}
Content-Type: application/json

[
  {
    "rsm_id": "101054915",
    "quantity": 100
  },
  {
    "rsm_id": "101054916",
    "quantity": 0
  }
]

Критично: передаётся свободный остаток (физический минус резерв). Если остаток стал 0 — ноль тоже передать, иначе висит старое значение.

Лимиты из документации API:

  • Минимум: 1 запись за запрос (иначе ошибка "Too small request: min 1 record per request")

  • Максимум: 1000 записей за запрос (иначе "Too big request: max 1000 records per request")

  • store_id — обязательный параметр (без него ошибка "Необходимо явно указать ID склада")

Частота обновления: минимум раз в день, оптимально каждый час.

Формат ответа при успехе:

json

{
  "result": "updated 1 records",
  "skipped": ["101054916"]
}

Массив skipped содержит коды rsm_id, которые не были обновлены (нет в эталонном справочнике).

3. Получение заказов

GET /api/orders/?datetimeFrom=2023-06-01T09:12:33&skip=0&limit=100
Authorization: Bearer {access_token}

Параметры запроса (все опциональные):

  • datetimeFrom — дата начала выборки (формат: 2023-06-01T09:12:33)

  • skip — количество заказов для пропуска (для пагинации, по умолчанию 0)

  • limit — лимит заказов (по умолчанию 100, максимум 100)

Без параметров возвращает последние 100 заказов.

Структура ответа:

json

[
  {
    "id": "1",
    "type": "CLIENT",
    "is_order": true,
    "is_bid": false,
    "is_paid": false,
    "items": [
      {
        "rsm_id": "102897669",
        "quantity": 1,
        "price": 100000,
        "total_price": 100000,
        "status": "NEW",
        "quantity_from_home": 1,
        "quantity_from_other_dealer": 0,
        "target_dealer": null
      }
    ],
    "client_inn": "123456789200",
    "delivery_type": "DELIVERY",
    "delivery_address": "г Краснодар, ул Северная, д 125",
    "status": "N",
    "service_text": "Заявка на сервис",
    "total_price": 100000,
    "bill_requested": true,
    "specification_requested": true
  }
]

Важные поля:

  • type — тип заказа: CLIENT (от конечного клиента) или DEALER (от другого дилера)

  • is_order — полноценный заказ с оплатой (true) или заявка без оплаты (false)

  • items.quantity_from_home — доступно на вашем складе

  • items.quantity_from_other_dealer — нужно заказать у другого дилера

  • items.target_dealer — у какого дилера заказано недостающее количество

  • Цены в копейках (100000 = 1000 рублей)

Статусы позиций в заказе:

  • NEW — ожидает обработки

  • RESERV — зарезервирован

  • TRANSIT — в транзите

  • DELIVERED — готов к выдаче

  • REJECTED — отменён

  • ISSUED — выдан

Статусы заказа:

  • N — в обработке

  • A — принят

  • C — подтверждён (и далее по цепочке)

1С забирает заказы каждый час, создаёт документ "Заказ покупателя", резервирует товар.

4. Обновление статусов и данных заказа

POST /api/orders/
Authorization: Bearer {access_token}
Content-Type: application/json

[
  {
    "id": "1",
    "is_paid": true,
    "items": [
      {
        "rsm_id": "101400963",
        "quantity": 7,
        "price": 100000,
        "status": "RESERV"
      }
    ],
    "delivery_type": "DELIVERY",
    "delivery_address": "г Краснодар, ул Северная, д 321",
    "service_text": "Комментарий дилера"
  }
]

Можно изменить:

  • Статусы позиций (items[].status)

  • Цены (items[].price)

  • Количество (items[].quantity)

  • Флаг оплаты (is_paid)

  • Адрес доставки (delivery_address)

  • Комментарий (service_text)

Нельзя изменить:

  • id (но нужно передавать для идентификации заказа)

  • type (CLIENT/DEALER)

  • client_inn

  • total_price (считается автоматически)

Общий статус заказа выставляется автоматически на основе статусов всех позиций.

Ответ при успехе:

json

{
  "result": "order updated"
}

5. Передача документов

Загрузка счетов:

POST /api/bills/
Authorization: Bearer {access_token}
Content-Type: multipart/form-data

id: 125
file_1: test.pdf
file_2: sample.pdf

Загрузка спецификаций:

POST /api/specifications/
Authorization: Bearer {access_token}
Content-Type: multipart/form-data

id: 125
file_1: specification.pdf

Можно загрузить несколько файлов сразу. Старые файлы перезаписываются.

Ответ: {"result": "Сохранено файлов: 2"}

Получение списка документов: GET /api/bills/?id=125

Клиент видит документы только после запроса (флаги bill_requested/specification_requested).

Технические решения

Почему не использовали стандартные библиотеки JWT

В 1С-Битрикс нет встроенной поддержки JWT. Рассматривали варианты:

Вариант 1: Библиотека firebase/php-jwt через Composer. Проблема — внешняя зависимость, нужен аудит по КИИ.

Вариант 2: Собственная реализация JWT. Плюсы — полный контроль, нет зависимостей. Минусы — нужно тщательно тестировать криптографию.

Выбрали вариант 2. Реализовали базовый JWT (HS256) без лишних фич. Прошли аудит безопасности.

Обработка ошибок в API

Примеры реальных ошибок из документации:

Неверный токен:

json

{
  "error": "Invalid JWT Token"
}

Слишком мало записей:

json

{
  "error": "Too small request: min 1 record per request"
}

Слишком много записей:

json

{
  "error": "Too big request: max 1000 records per request"
}

Не указан store_id:

json

{
  "error": "Необходимо явно указать ID склада (store_id)"
}

Все ошибки возвращаются в JSON с полем error. Коды ошибок документированы в 35-страничном руководстве для программистов 1С.

Сложности интеграции с 1С

Проблема кодировок

1С работает в Windows-1251. API ждёт UTF-8. Первые выгрузки пришли с кракозябрами.

Решение: проверка кодировки в API + инструкция для 1С-программистов добавить Content-Type: application/json; charset=utf-8 в запрос.

Проблема с резервом

Первая версия: дилеры передавали физические остатки. Проблема: клиент заказал → резерв в 1С → на сайте остаток не изменился → двойное резервирование.

Решение: передавать свободный остаток (физический минус резерв).

Проблема с нулевыми остатками

Дилер настроил выгрузку: передавать только изменения. Если остаток стал 0, он не попадает в выгрузку (значение пустое). На сайте висит старый остаток.

Решение: требование в API передавать изменения даже при quantity = 0.

Мониторинг активности

Интеграция настроена, но остатки не обновляются. Причина: программист забыл включить автозапуск в 1С.

Решение: если дилер не передавал остатки 3 дня — автописьмо на email. Мониторинг активности API обязателен.

Результаты

Метрики внедрения

Разработка велась по трёхверсионной модели из ТЗ: 18 месяцев (Q3 2022 — Q4 2023).

Версия 1 (Q3-Q4 2022): MVP — каталог, гостевой checkout, email дилерам

Версия 2 (Q1-Q2 2023): REST API, личные кабинеты, статусы

Версия 3 (Q3-Q4 2023): Полная автоматизация — CRM интеграция, документы через API

Подключено дилеров: 28 из 40+ (70%) через API, остальные через email.

Качественные изменения

Для клиентов:

  • Самостоятельное оформление заказов через веб-интерфейс

  • Отслеживание статусов в реальном времени

  • Управление парком техники в личном кабинете

  • Проверка совместимости по серийному номеру (снижение ошибок)

Для дилеров:

  • Автоматическая передача заказов в 1С без ручного ввода

  • Real-time актуализация остатков (вместо 1-2 недель)

  • Снижение нагрузки на операторов call-центра

  • Централизованная работа с документами через API

Для завода:

  • Централизованная аналитика по всей дилерской сети

  • Контроль качества обслуживания клиентов

  • Унификация процессов заказа запчастей

Выводы

Требования КИИ — это не ограничение. Нельзя Laravel — берём Битрикс. Нельзя npm-пакеты — пишем свою реализацию JWT. Ограничения заставляют искать решения, иногда более простые.

Данные важнее технологий. API спроектировали за 2 недели. Эталонный справочник делали 3 месяца. Без справочника интеграция не сработала бы. В B2B 80% проблем — это структура данных.

Минимализм в API упрощает внедрение. Пять методов вместо 15. Остальное — потом или вообще не нужно. Чем проще API, тем быстрее дилеры внедряют.

Документация критична. 35-страничное руководство с примерами кода. Программисты дилеров внедряют за 3-5 дней без нашей помощи. Хорошая документация = масштабируемость.

Мониторинг обязателен. Нельзя полагаться, что всё настроили правильно. Автопроверка активности API — must have в B2B.


Теги: #api #restapi #integration #1c #bitrix #b2b #jwt #ecommerce

Автор: Олег Линьков, CEO & Tech Lead Webformula

Мы переводим агромаркетинг с «интуиции» на рельсы Data-Driven & AI. Разрабатываем и внедряем федеративные архитектуры данных и методологию DSAC (Dynamic Seasonally-Adaptive Content).