Commit graph

2 commits

Author SHA1 Message Date
nns 929d0b6a38 test(s32): stage-ui-catalog-import spec + финал в progress-doc
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Playwright 1/1 passed против test.admin.food-market.kz после полной
заливки МойСклада в Демо-магазин:

- /catalog/products под demo-admin — 30 894 записей в шапке списка.
- Поиск по частичному названию «шоколад» → хотя бы одна строка.
- Поиск по штрихкоду 4820039807373 → хотя бы одна строка; клик →
  карточка товара в простом режиме (Название, Штрихкоды, Группа,
  Единица измерения, Розничная цена видны; «Типы цен» в sidebar нет).

Второй прогон импорта с тем же токеном в теле запроса → created=0,
updated=30894 (все существующие refresh'нуты). Идемпотентность по
MoySkladExternalId подтверждена.

Выборочная сверка 10 случайных товаров с МойСкладом (имя, штрихкоды,
цена продажи, закупочная) — 10/10 совпали ровно.

Token checks:
- Organizations.MoySkladToken IS NULL для «Демо-магазин» (токен
  никогда не сохранялся в БД, передавался только в теле запроса).
- /tmp/ms-token после импорта shred -u — локально ничего не осталось.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-10-04 23:46:11 +05:00
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