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
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
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>
104 lines
6.5 KiB
Markdown
104 lines
6.5 KiB
Markdown
# Supply + Inventory mobile — прогресс
|
||
|
||
Задача: добавить в food-market два мобильных варианта приёмки (по фото
|
||
накладной + сканированием штрихкодов) и инвентаризацию с телефона с
|
||
офлайн-режимом. Образец логики — `~/ref/sklad/sklad/` (read-only); но
|
||
документы создаются в НАШЕЙ базе (Supply/Inventory), а не черновиками
|
||
в МойСклад.
|
||
|
||
Все три фичи — основные (видны в простом режиме), доступны Admin +
|
||
Storekeeper.
|
||
|
||
## Чек-лист
|
||
|
||
### Приёмка
|
||
|
||
- [x] 1. **Приёмка по фото/PDF накладной** — загрузка, фоновое
|
||
распознавание через Claude CLI (`claude -p --output-format json`,
|
||
промпт из `ClaudeCliInvoiceExtractor.cs`), запуск локально
|
||
или через ssh на RemoteHost. Статусы: `queued → extracting →
|
||
review | failed`. Платные API-ключи не заводим.
|
||
- [x] 2. **Экран проверки накладной.** Редактируемые строки, помощь в
|
||
сопоставлении с товаром (barcode → saved-mapping → ручной), создание
|
||
товара прямо из строки, проверка «итого», предложение создать
|
||
контрагента. Коммит → наш Supply (Draft).
|
||
- [x] 3. **Приёмка сканированием.** Непрерывная камера, +1 к строке на
|
||
скан, последняя закупочная подставляется, неизвестный штрихкод →
|
||
предложить создать товар или отложить.
|
||
|
||
### Инвентаризация
|
||
|
||
- [x] 4. **Инвентаризация с телефона.** Выбор склада + опц. группы,
|
||
офлайн-каталог в IndexedDB, прогресс сохраняется локально; скан /
|
||
ручной ввод; неизвестные штрихкоды в отдельный список.
|
||
- [x] 5. **Расхождения видны сразу.** Учёт/факт/дельта в шт. и в деньгах,
|
||
фильтр «только расхождения». Частичная (по группе) НЕ обнуляет
|
||
непосчитанные; полная — явный выбор.
|
||
- [x] 6. **Учётный остаток подставляется автоматически** (без ручной
|
||
кнопки «Пересчитать»): при создании bookQty = текущий Stock; при
|
||
добавлении позиции — тоже; перед проведением пересчёт + warning о
|
||
расхождениях с момента создания (продажи/приёмки). Если где-то
|
||
экспорт в МойСклад — там тоже явный расчётный остаток.
|
||
|
||
### Общее
|
||
|
||
- [x] 7. Мобильная вёрстка 375×667 + PWA. Тесты: unit (матчинг,
|
||
запоминание маппингов, bookQty, расхождения, частичная инв.),
|
||
integration (накладная → Supply Draft; частичная инв. не трогает
|
||
другие товары; bookQty = текущий Stock), e2e на стенде.
|
||
- [x] 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.
|