Перейти к основному содержимому

Модуль МойСклад: устройство

Как этим пользоваться — в разделе для склада. Здесь — что внутри.

Состав

apps/backend/src/modules/moysklad-integration:

ФайлОтветственность
client.tsHTTP-клиент JSON API МойСклад
credentials.tsшифрование реквизитов (AES, ключ MOYSKLAD_ENCRYPTION_KEY)
service.tsмодульный сервис Medusa
retry-schedule.tsрасписание повторов
stock-sync-report.tsотчёт о цикле синхронизации остатков
models/moysklad-connection-config.tsподключение: реквизиты, флаг активности
models/moysklad-order-sync.tsсостояние отправки конкретного заказа

Реквизиты — токен либо логин/пароль — хранятся в базе в зашифрованном виде, не в переменных окружения. В окружении лежит только ключ шифрования; его смена делает сохранённые реквизиты нечитаемыми.

Ключ сопоставления

Товары сопоставляются по коду номенклатуры: SKU варианта Medusa ищется как filter=code=<sku> в /entity/product. Не по названию и не по артикулу. Вариант без SKU в синхронизации не участвует.

Остатки: jobs/moysklad-stock-sync.ts

Каждые 15 минут. Постранично (200 записей) собираются варианты и их уровни запаса, тянутся остатки из МойСклад и записываются в стандартный inventory Medusa.

Дополнительно вычитаются количества из заказов сайта за последние 48 часов (STOCK_RESERVATION_WINDOW_MS): МойСклад ещё не знает об этих заказах, пока сотрудник их не провёл, и без вычитания остаток был бы завышен.

:::note Статус наличия нигде не хранится Он всегда вычисляется из стандартного inventory: остаток > 0 → «в наличии»; остаток 0 при разрешённом backorder → «под заказ»; иначе «нет в наличии». Отдельного поля со статусом не существует, и заводить его не нужно. :::

Заказы: подписчики + повторы

subscribers/moysklad-order-placed.ts отправляет заказ сразу при оформлении; subscribers/moysklad-order-canceled.ts помечает отмену. Задача jobs/moysklad-order-sync-retry.ts раз в минуту добирает то, что не прошло.

Расписание повторов фиксированное — 1 мин, 5 мин, 30 мин, 2 ч, 12 ч, то есть 6 попыток всего вместе с первой, синхронной. Дальше заказ остаётся в статусе error и ждёт ручного повтора из админки.

Запись syncing, брошенная упавшим процессом, считается заброшенной через 10 минут (STALE_SYNCING_MINUTES) и снова становится доступной для повтора — иначе она зависла бы навсегда.

:::warning Отмена отслеживается отдельно от создания У moysklad_order_sync два независимых набора полей: status/attempts для создания и cancellation_status/cancellation_attempts/cancellation_updated_at для отмены. Так повтор отмены не сбрасывает status уже отправленного заказа и не выглядит как «заказ не синхронизирован». Своя временная метка у отмены нужна, чтобы сверка на стороне создания не сбрасывала проверку срока повтора. :::

Что не синхронизируется

Цены, названия, изображения и категории живут в Medusa и в МойСклад не ездят. Из МойСклад берутся только остатки; в МойСклад уходят только заказы.

Грабли реального API

Реальный API строже моков — по заголовкам, ключу сопоставления и лимитам. Подробности и другие особенности интеграций — docs/known-quirks.md.