# Инвентаризация по модели МойСклада — прогресс Замечание владельца (08.10.2026): «инвентаризация стоит в состоянии „проведено“, но без оприходования и списания — логика непонятная». **Сейчас (неправильно):** `InventoriesController.Post` сам применяет движения `MovementType.InventoryAdjustment` к остаткам и ставит `Status=Posted` — без создания Оприходования/Списания. Владелец видит «Проведено» без связанных документов; в отчётах непонятно, откуда изменения. **Как должно быть (по МойСкладу):** инвентаризация НЕ двигает остатки; она фиксирует расчётный/фактический/разницу, а движения создаются связанными документами Оприходование (излишки) и Списание (недостача). **ПОПРАВКА (Mac-Claude):** кнопку «Применить результаты» НЕ добавляем (не одобрено владельцем). Только две кнопки «Создать оприходование» / «Создать списание». Мобильный `post` — временная совместимость (в docs помечено). ## План / статус 0. [x] Сверка с МойСкладом → `docs/inventory-moysklad-reference.md` (API SPA — факты из справки + школы торговли; поля calculatedQuantity/correctionAmount/correctionSum, applicable, enter/loss «на основании»). 1. [x] Инвентаризация не двигает остатки; статусы `Draft`→`Completed` («Черновик»→«Завершена»). Эндпоинт `complete` замораживает строки без движений (`InventoriesController`). 2. [x] На завершённой — `create-enter` (излишки) / `create-loss` (недостача): создают черновики Оприходования/Списания со строками разницы + ссылка `InventoryDocId`. Повторно нельзя (409). Кнопки «Применить результаты» НЕТ (по поправке). 3. [x] Блок «Связанные документы» в карточке (web); колонка «Результат» в списке; «На основании инвентаризации №…» в Оприходовании/Списании (web + DTO). 4. [x] «Вернуть в черновик» (`unpost`) отменяет проведение и удаляет связанные документы (остатки возвращаются). Править завершённую нельзя (Update/AddLine требуют Draft). 5. [x] Миграция `Posted+InventoryAdjustment` → связанные проведённые Оприходование/Списание: `InventoryMigrationController` (dry-run/apply) переметка движений (не задваивает), остатки до/после проверяются (`stockUnchanged`). Backup — в `deploy/migrate-inventory-to-docs.sh`. 6. [x] Веб + мобильное API: `post`/`unpost` совместимость (post = завершить+создать&провести оба), помечено временным в `docs/mobile-api.md`. CSV-импорт инвентаризации — без изменений (работает). 7. [~] Тесты: unit (InventoryResult — разница/сумма/только посчитанные) ✓; integration/e2e/full-chain шаг 10 — ниже. 8. [x] `docs/supply-inventory.md` — «Как провести инвентаризацию» (5 шагов). 9. [~] deploy-stage + коммиты в main (Opus 5.5), global.json не коммитить, не мешать с rebrand — ниже. ### Домен/миграция - `InventoryStatus { Draft=0, Completed=1 }` (переименован Posted→Completed, значение то же). - `Enter.InventoryDocId` / `Loss.InventoryDocId` (nullable) + EF-миграция `Phase38_InventoryLinks`. - `InventoryResult` (application) — чистая разбивка diff→излишки/недостача (юнит-тесты). - Демо-сидеры: инвентаризации теперь `Completed` без прямых движений. ## Что НЕ трогаем Прод, shared-postgres, global.json, gateway nginx, sklad. ## Проверка (на стенде test.admin.food-market.kz) - **Unit:** `InventoryResultTests` (разница/сумма/только посчитанные/округление) + poco — 64/64 ✓. - **Live e2e (API):** создать (излишек +2, недостача −2) → `complete` (остаток НЕ изменился) → `create-enter`/`create-loss` → в инвентаризации видны связанные документы (черновик) → провести оба → остатки +2/−2 ✓; в Оприходовании `inventoryNumber` = И-2026-… ✓; повторный `create-enter` → **409** ✓; `unpost` → удалил связанные, остатки вернулись, статус Draft ✓. - **Миграция данных:** `inventory-migration/run` dry-run → 1 кандидат; `apply` → migrated 1, **stockUnchanged=true, stockDiffRows=0** (остатки до/после совпали); повторный dry-run → 0 (идемпотентно). И-2026-000001 → связанное проведённое Списание С-2026-000002 (см. скрин). - **full-chain шаг 10:** 16/16 ЗЕЛЁНЫЙ — добавлена проверка новой модели (complete→create-enter→ связанный документ→провести→+3→«на основании»), плюс совместимый `/post`. - **menu-walk:** 3/3 (все роли, страницы инвентаризации рендерятся, 0 ошибок/тостов). - **Скриншоты:** `docs/inventory-screenshots/` (карточка «Завершена» с кнопками и блоком «Связанные документы», колонка «Результат» в списке). - **deploy-stage:** OK. Формальных xUnit-integration не добавлял — поведение покрыто full-chain (реальный стек) + живым e2e на стенде + unit. UAT — обновить при следующем прогоне UAT-сценария. ## Журнал - 08.10 — старт: прочитано замечание, составлен план. Сверка с МойСкладом. - 08.10 — реализация: домен (Draft→Completed, Enter/Loss.InventoryDocId, миграция Phase38), InventoryResult, контроллеры (complete/create-enter/create-loss/post-compat/unpost), миграция данных (InventoryMigrationController + скрипт), веб-UI, доки. - 08.10 — проверено на стенде: full-chain 16/16, menu-walk 3/3, live e2e всех сценариев, миграция stockUnchanged. Коммиты в main (0d44cda, b4bd0e4, b036050), push. global.json не трогал.