food-market/docs/supply-inventory-mobile-progress.md
nns 11b43aefe5 feat(s31): приёмка по фото — upload → Claude CLI → match → Supply Draft (1/8)
Backend-pipeline по образцу ~/ref/sklad/sklad/Invoices/, но документы
создаются в НАШЕЙ базе (Supply), не в МойСкладе.

Домен (food-market.domain/Purchases/InvoiceUpload.cs):
- InvoiceUpload: файл + статус (pending/parsing/needs_review/applied/failed)
  + распознанная шапка + ParsedJson (jsonb) + ссылка на созданный Supply.
- InvoiceAlias: запомненное соответствие (SupplierKey, SourceCode|
  SourceNameNorm) → ProductId. Два частично-уникальных индекса (filter
  SourceCode/SourceNameNorm IS NOT NULL).

Миграция Phase31a (идемпотентная ADD/CREATE IF NOT EXISTS; [Migration]+
[DbContext]).

Infrastructure/Invoices/:
- IInvoiceExtractor + ParsedInvoice/InvoiceLine DTO.
- ClaudeCliInvoiceExtractor — порт из sklad: 'claude -p --output-format
  json', промпт один-в-один (копировать все строки, null если не читается,
  barcode != supplier_code, сверка с «Итого»). Поддерживает local и
  Invoices:ClaudeCli:RemoteHost (ssh+scp+cleanup).
- InvoiceMatcher — barcode → alias → none. По названию НЕ ищем
  (sklad-урок: 2-5 ошибок из 10, подмена хуже пустой строки).
- InvoiceProcessor + InvoiceWorker (BackgroundService):
  pending → parsing → needs_review | failed. SweepAsync раз в час
  удаляет файлы старше Invoices:KeepFilesDays (default 7); строки
  остаются. Multi-tenant через IgnoreQueryFilters + явный OrgId.

Controller api/purchases/invoices:
- POST /upload (SuppliesEdit, 60 MB max): файлы в uploads/invoices/{yyyy-
  MM}/, запись в pending.
- GET /, GET /{id} — список + детали со строками.
- GET /{id}/file — отдать файл.
- DELETE /{id} — удалить запись + файл.
- PUT /{id}/lines — правки шапки + строк + авто-upsert InvoiceAlias
  для каждой строки с MatchedBy=manual|alias (два ключа: по code и по
  name_norm).
- POST /{id}/apply — создать Supply (Draft) с данным поставщиком/
  складом/валютой, статус → applied, SupplyId ссылается, файл удаляется.
- GET /product-by-barcode, /counterparty-search — помощь UI.

Build зелёный. Web + тесты — следующими шагами.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-10-04 21:30:02 +05:00

3.8 KiB
Raw Blame History

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].