Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
Smoke stage: - POST /purchases/invoices/upload-photos → 400 (не 404) без файлов - mobile-catalog: 31 269 ШК, JSON 3.44 МБ → gzip 1.75 МБ, ETag работает, повтор с If-None-Match → 304 - stage-ui-menu-walk.spec.ts: 3/3 passed, 0 ошибок у admin/keeper/cashier Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
7.1 KiB
7.1 KiB
Порт улучшений накладных/инвентаризации из sklad (05.10.2026)
Источник: ~/ref/sklad (read-only), handoff: ~/ref/sklad/docs/handoff-2026-10-05-nakladnye-inventarizaciya.md,
диапазон коммитов f455fa9..b7eb637 + 3ced706 (readme).
Правило: ничего из МойСклад — только наша БД (Product, ProductBarcode), наши документы
Supply (как InvoiceUpload-черновик→Supply) и Inventory, наши права
(SuppliesEdit, InventoryEdit, роли Кладовщик/Администратор).
Задачи
- 1. Серверное автосохранение правок накладной + индикатор + lines до черновика + refetchOnWindowFocus:false
- 2. Общее поле скана с панелью «в какую строку?» (цветные сообщения, linesRef)
- 3. CameraScanner без перезапуска + глобальный hardware keydown на страницах накл/приёмки/инв
- 4. Фото-приёмка (PhotoSession + shots.ts + upload-photos + Claude photos + EAN + миниатюры)
- 5. Хранение фото: удаление на draft/delete, 24h для брошенных; без KeepFilesDays
- 6. «Файлы» и «камера» в обоих способах приёмки
- 7. Excel/CSV через TableReader + шаблон xlsx в docs/
- 8. Инвентаризация: камера + видимое поле + импорт Excel/CSV
- 9. Каталог без простоев: индекс штрихкода ✓ (unique
IX_product_barcodes_OrganizationId_Code), gzip черезUseResponseCompression, ETag/If-None-Match наmobile-catalog. Синтетический замер 31 000 позиций: JSON 3.60 МБ → gzip 0.98 МБ (ratio 27%). - 10. Тесты: unit — EanTests (6), TableReaderTests (5), ClaudeCliInvoicePhotosParseTests (4), InvoicePhotoRetentionTests (3). Build integration/e2e — зелёный.
- 11. deploy-stage, ретест, docs/supply-inventory.md
Решения владельца
- Хранение фото: НЕ копить. Удалять при создании Supply-черновика, при удалении InvoiceUpload,
и через 24 часа для брошенных «на проверке». Никакого
Invoices:KeepFilesDays. - Модель Claude:
claude-sonnet-5-5(Haiku сочиняет данные). - Тайм-аут фото-пачки:
Invoices:ClaudeCli:PhotoTimeoutSeconds= 600 с. - Каталог: наша БД, права
SuppliesEdit/InventoryEdit. - gateway: лимит запроса не трогал самостоятельно; если фото-пачка не пройдёт
на стенде по размеру — поднять
client_max_body_sizeдо 64M (сейчас, вероятно, 10M-32M).
Что лежит где
Backend
| Что | Файл |
|---|---|
| Контрольная цифра EAN | src/food-market.api/Infrastructure/Invoices/Ean.cs |
| Табличная читалка .xlsx/.csv + парсер шаблона | src/food-market.api/Infrastructure/Invoices/TableReader.cs |
| InvoiceLine +Photo/BarcodeSource/Note, PhotoHint, IInvoiceExtractor.ExtractPhotosAsync | .../InvoiceModels.cs |
| InvoiceMatcher.FindByBarcode | .../InvoiceMatcher.cs |
| InvoiceProcessor: ветки photos/excel/vision, MatchFromPhoto, SweepAbandonedPhotos, DeleteStored | .../InvoiceProcessor.cs |
ClaudeCli ExtractPhotosAsync + BuildPhotosPrompt + FromPhotosJson; дефолт claude-sonnet-5-5 |
.../ClaudeCliInvoiceExtractor.cs |
POST /invoices/upload-photos + GET /invoices/{id}/photo/{n}; apply/delete убирают папку |
Controllers/Purchases/InvoicesController.cs |
POST /inventory/inventories/import (xlsx/csv → {found, unknown}) |
Controllers/Inventory/InventoriesController.cs |
gzip response-compression + ETag на mobile-catalog |
Program.cs, InventoriesController.cs |
Frontend
| Что | Файл |
|---|---|
| Общий модуль ZXing TRY_HARDER + compress 2400/0.85 + fileToCanvas | src/food-market.web/src/lib/shots.ts |
| Полноэкранная пачка снимков (камера + готовые фото) | .../components/PhotoSession.tsx |
CameraScanner: onCodeRef + эффект [] (нет перезапуска камеры) |
.../components/CameraScanner.tsx |
InvoicesPage: Снять камерой / Загрузить файл / Сфотографировать листы / Фото товаров+накладная |
.../pages/InvoicesPage.tsx |
| InvoiceReviewPage: автосохранение 700 мс + индикатор + row-picker + linesRef + глобальный keydown + миниатюры | .../pages/InvoiceReviewPage.tsx |
| SupplyScanPage: глобальный keydown (аппаратный сканер вне фокуса) | .../pages/SupplyScanPage.tsx |
| InventoryMobilePage: сканер-поле на виду + импорт Excel/CSV + глобальный keydown | .../pages/InventoryMobilePage.tsx |
| Шаблон для поставщиков (xlsx, 9-я строка — заголовки) | docs/supplier-invoice-template.xlsx (scripts/make_supplier_template.py) |
Тесты
| Что | Файл |
|---|---|
| EAN корректность + 1-digit error ловится | tests/food-market.UnitTests/EanTests.cs |
| xlsx/csv UTF-8/1251 + шаблон + .xls friendly error | tests/food-market.UnitTests/TableReaderTests.cs |
| JSON ответа фото-пачки + Note из comment + unmatched → Warnings | tests/food-market.UnitTests/ClaudeCliInvoicePhotosParseTests.cs |
| DeleteStored: файл, папка, идемпотентность | tests/food-market.UnitTests/InvoicePhotoRetentionTests.cs |
Пре-существующий отказ ApiReferenceDocsJobTests.Scans_endpoints_with_doubly_nested_generic_return
не связан с портом (Sprint 28, падал до изменений).
Deploy и retest
- Commit
6b0fc68→~/deploy-stage.sh→ stage зелёный на https://test.admin.food-market.kz - Smoke по новым endpoint'ам:
POST /api/purchases/invoices/upload-photosбез файлов → 400 «Нет снимков.» (ранее 404)GET /api/inventory/inventories/mobile-catalogпод gzip: JSON 3.44 МБ (31 269 ШК на Demo) → gzip 1.75 МБ, Content-Encoding: gzip, Vary: Accept-Encoding ETag"inv-cat-f7abeb59d181533a-all", Cache-Controlprivate, max-age=60- Повтор с
If-None-Match→HTTP/2 304
tests/e2e/scenarios/stage-ui-menu-walk.spec.tsна стенде — 3/3 passed, 3.7 min, 0 4xx/5xx/toast.error/console.error у demo-admin (28 пунктов), demo-keeper (17), demo-cashier (7).
Журнал
- 05.10.2026: порт выполнен в один проход; API build зелёный, web tsc+vite build зелёный, 18 новых unit-тестов зелёные. deploy-stage зелёный, menu-walk 3/3 зелёный.