food-market/docs/catalog-import-progress.md
nns 864d492c93 feat(s32): MoySklad-импорт — upsert по external id, merge по barcode, skip archived, UOM-mapping
Для полной заливки каталога МойСклада в «Демо-магазин» на стейдже
переделал импорт по требованию «идемпотентный + без дублей».

Схема:
- Phase32a_MoySkladExternalId: VARCHAR(64) на products и product_groups
  + partial-unique index (OrgId, MoySkladExternalId) WHERE IS NOT NULL.
  NULL разрешён — товары, созданные вручную, без MS id.

Клиент (MoySkladClient):
- Auto-detect Basic vs Bearer: МойСклад принимает оба, но сторонние
  проекты (sklad на prod-vm) используют Base64(login:password). Строку
  распознаём как base64 с ':' в декоде → ставим Basic, иначе Bearer.
- StreamProductsAsync принимает includeArchived (default true для
  back-compat; импортный путь передаёт false).
- GetAllUomsAsync — грузит справочник единиц измерения один раз.

Сервис (MoySkladImportService):
- MoySkladImportOptions: OverwriteExisting / SkipArchived / MergeByBarcode.
- Resolution order: MS id → barcode → article. Первый найденный
  апдейтится, не плодит дубль.
- Группы — upsert по MS id; pre-существующие группы без MS id с тем же
  именем в том же родителе — подхватываются (MS id проставляется).
- Товары из архива MoySklad (archived=true) полностью пропускаются
  (счётчик SkippedArchivedInSource в результате).
- Barcode-дубли внутри MoySklad: первый встреченный выигрывает, остальные
  пропускаются с записью в Errors (счётчик SkippedDuplicateBarcodeInSource).
- UOM: MS uom.id → MS uom.code → наш локальный Code. Весовые товары
  (weighed=true) всегда ставятся в «кг».
- Расширенный MoySkladImportResult: Created / MergedByBarcode /
  SkippedArchivedInSource / SkippedDuplicateBarcodeInSource / GroupsUpdated.

Контроллер (MoySkladImportController):
- ImportRequest получает SkipArchived (default true), MergeByBarcode
  (default true). Токен по-прежнему принимается в body и НЕ сохраняется
  в Organizations.MoySkladToken, если передан в теле запроса.
- Финальный Message прогресса собирает все счётчики.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-10-04 23:22:14 +05:00

2.4 KiB
Raw Blame History

Catalog import МойСклад → «Демо-магазин» (stage)

Решение владельца. Стенд закрыт basic-auth'ом на gateway от интернета (внутренняя сеть 192.168.1.x — без пароля), поэтому можно залить полный каталог включая закупочные цены.

Токен МойСклада. /var/www/sklad/appsettings.Production.json, ключ MoySklad:Token, забирается через ssh + sudo на prod-vm. В логи / коммиты / docs / отчёты токен никогда не попадает. Передаётся только через env-переменную или stdin.

Границы. Не трогаем проект sklad, прод admin.food-market.kz, global.json, deploy/*/nginx.

Чек-лист

  • 1. Аудит текущего MoySklad-импорта + добор недостающих полей для «полной карточки» (товары, группы, ед. изм., штрихкоды, цены продажи/закупки, весовой признак, мин. остаток, артикул, фото) — сверка полей против API МойСклад 1.2.
  • 2. Импорт в «Демо-магазин» на стейдже без дублей: upsert по внешнему id МойСклада; merge по штрихкоду; дубли штрихкодов в самом МойСкладе — первый пропускаем в отчёт; группы — тоже без дублей; архивные товары МойСклада не льём.
  • 3. Токен у организации стенда после импорта удалить (или импорт без сохранения токена — тоже ок).
  • 4. Отчёт: группы/товары created/updated/merged/skipped + выборочная сверка 10 карточек с МойСкладом.
  • 5. Playwright-проверка каталога Демо-магазина изнутри сети: открывается, поиск по названию и штрихкоду работает, карточка показывает поля простого режима; повторный запуск импорта → 0 новых.

Протокол выполнения

(заполняется построчно)