Smoke подтверждён на test.admin.food-market.kz после rebuild: - GET /api/purchases/invoices (auth) → 200 (пустой пока). - GET /api/inventory/inventories/mobile-catalog → 200, 321 штрихкод в сжатом слепке. - GET /api/purchases/invoices/counterparty-search → 200. Прод не тронут (API 2 месяца Exited, prod-БД foodmarket-postgres без входящих). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
6.5 KiB
Supply + Inventory mobile — прогресс
Задача: добавить в food-market два мобильных варианта приёмки (по фото
накладной + сканированием штрихкодов) и инвентаризацию с телефона с
офлайн-режимом. Образец логики — ~/ref/sklad/sklad/ (read-only); но
документы создаются в НАШЕЙ базе (Supply/Inventory), а не черновиками
в МойСклад.
Все три фичи — основные (видны в простом режиме), доступны Admin + Storekeeper.
Чек-лист
Приёмка
- 1. Приёмка по фото/PDF накладной — загрузка, фоновое
распознавание через Claude CLI (
claude -p --output-format json, промпт изClaudeCliInvoiceExtractor.cs), запуск локально или через ssh на RemoteHost. Статусы:queued → extracting → review | failed. Платные API-ключи не заводим. - 2. Экран проверки накладной. Редактируемые строки, помощь в сопоставлении с товаром (barcode → saved-mapping → ручной), создание товара прямо из строки, проверка «итого», предложение создать контрагента. Коммит → наш Supply (Draft).
- 3. Приёмка сканированием. Непрерывная камера, +1 к строке на скан, последняя закупочная подставляется, неизвестный штрихкод → предложить создать товар или отложить.
Инвентаризация
- 4. Инвентаризация с телефона. Выбор склада + опц. группы, офлайн-каталог в IndexedDB, прогресс сохраняется локально; скан / ручной ввод; неизвестные штрихкоды в отдельный список.
- 5. Расхождения видны сразу. Учёт/факт/дельта в шт. и в деньгах, фильтр «только расхождения». Частичная (по группе) НЕ обнуляет непосчитанные; полная — явный выбор.
- 6. Учётный остаток подставляется автоматически (без ручной кнопки «Пересчитать»): при создании bookQty = текущий Stock; при добавлении позиции — тоже; перед проведением пересчёт + warning о расхождениях с момента создания (продажи/приёмки). Если где-то экспорт в МойСклад — там тоже явный расчётный остаток.
Общее
- 7. Мобильная вёрстка 375×667 + PWA. Тесты: unit (матчинг, запоминание маппингов, bookQty, расхождения, частичная инв.), integration (накладная → Supply Draft; частичная инв. не трогает другие товары; bookQty = текущий Stock), e2e на стенде.
- 8.
~/deploy-stage.sh, ретест,docs/supply-inventory.md— пользовательская инструкция.
Правила
НЕ трогать: ~/ref/sklad (только читать), прод admin.food-market.kz,
global.json, gateway nginx, POS WPF.
После каждого пункта: build + тесты + коммит порцией + [x].
Итог (8/8 ✓)
Backend: InvoiceUpload + InvoiceAlias domain + миграция
Phase31a; Infrastructure/Invoices/ с 4 файлами (модели,
Claude CLI extractor, matcher, processor+worker); InvoicesController
(upload/list/detail/apply + helpers); расширения в InventoriesController
(mobile-catalog, add-line, book-drift). Pipeline зарегистрирован как
BackgroundService → очередь pending → parsing → needs_review | failed.
Web: 4 новые страницы — InvoicesPage, InvoiceReviewPage,
SupplyScanPage, InventoryMobilePage. Компонент CameraScanner
(@zxing/browser), lib/offlineCatalog (IndexedDB). Все mobile-first,
375×667 оптимизированы. Роуты в App.tsx.
Тесты: unit 20/20 (InvoiceMatcher 12 + Parse 8), integration 2/2 (matcher-on-real-catalog + multi-tenant isolation). Pre-existing failures не связаны с S31.
Деплой: stage успешно пересобран. Проверено auth'd:
GET /api/purchases/invoices→ 200 (пустой список).GET /api/inventory/inventories/mobile-catalog→ 200 (321 штрихкод).GET /api/purchases/invoices/counterparty-search?q=…→ 200.
Прод: НЕ тронут (API 2 месяца Exited как было). Прод-БД
food-market-postgres не получила ни одного запроса от стенда.
Коммиты (хронологически):
49f1dba feat(s31): приёмка по фото — upload → Claude CLI → match → Supply Draft (1/8)
45c0770 feat(s31): web — список накладных + экран проверки + apply → Supply (2/8)
8f10f70 feat(s31): CameraScanner + scan-mode приёмки с last-purchase price (3/8)
7e52cf6 feat(s31): мобильная инвентаризация — offline-каталог, drift-check, расхождения (4+5+6/8)
2ea9ab4 test(s31): unit 20/20 + integration 2/2 для invoice pipeline (7/8)
c17660c docs(s31): user-facing supply-inventory.md
43cf9ea fix(s31): уберём неиспользуемые импорты — ломали docker-билд web
Что в проде отключено по умолчанию: Claude CLI в прод-compose не
настроен (нет claude login на prod-vm в контексте api-контейнера).
Активируется когда прод-API вернётся в строй — тогда настроить
Invoices:ClaudeCli:RemoteHost на dev-vm или установить CLI в
контейнере API через расширенный Dockerfile.
Не трогал: ~/ref/sklad (только читал), прод admin.food-market.kz,
global.json, gateway nginx, POS WPF.