# E2E report: stage-enter

Запущен: 2026-05-29T11:57:15.604Z
Длительность: 14.9с

**Итог:** 10 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 10)

## ✓ Step ent01_setup: Создать org с admin + продукт (для строк) + storeId — все ref'ы для теста

Длительность: 9827мс

| Тип | Проверка | Результат |
|---|---|---|
| api | Org A с product+store готов | ✓ 283b6739-4377-4c6e-b6e6-2ea27c4a9f49 |
| api | Org B с product+store готов | ✓ 7ada5e66-efcb-441c-9d9f-df8a7c4b4055 |

## ✓ Step ent02_create_draft: POST /api/inventory/enters → Draft с 2 строками, номер сгенерирован "О-YYYY-NNNNNN"

Длительность: 611мс

| Тип | Проверка | Результат |
|---|---|---|
| api | POST /api/inventory/enters → 201 | ✓ 201 {"id":"262e47c2-1cd5-466c-8f8d-6496c9e88225","number":"О-2026-000001","date":"2026-05-29T11:57:25.554Z","status":0,"storeId":"45769058-4482-4e85-8052-02255a2bb060","storeName":"Основной склад","cu |
| api | Total = sum(qty*cost) = 3750 | ✓ total=3750 vs 3750 |
| api | Номер сгенерирован формата О-YYYY-NNNNNN | ✓ number=О-2026-000001 |
| api | Lines.Count = 2 | ✓ lines=2 |
| api | Status = Draft (0) или строка "Draft" | ✓ status=0 |

## ✓ Step ent03_update_draft: PUT — поменять Notes, заменить строки, проверить пересчёт Total

Длительность: 464мс

| Тип | Проверка | Результат |
|---|---|---|
| api | PUT enter Draft → 204 | ✓ 204  |
| api | GET после PUT: Total = 20*150 = 3000, Lines.Count = 1 | ✓ total=3000 lines=1 |
| api | PUT restore с 2 строками для post-теста → 204 | ✓ 204 |

## ✓ Step ent04_post: POST {id}/post → Status=Posted, Stock.Quantity += sum(line.Quantity), StockMovement[type=Enter]

Длительность: 982мс

| Тип | Проверка | Результат |
|---|---|---|
| api | POST {id}/post → 204 | ✓ 204  |
| api | Stock.Quantity продукта 1 += 10 | ✓ delta=10 |
| api | Stock.Quantity продукта 2 += 5 | ✓ delta=5 |
| api | Создано минимум 2 StockMovement с DocumentId = enterIdA | ✓ movs=2, types=Enter,Enter |
| api | После Post: Status = Posted (1), PostedAt не null | ✓ status=1 postedAt=2026-05-29T11:57:26.83119Z |

## ✓ Step ent05_post_idempotent_or_conflict: Повторный POST/post проведённого → 409 «Документ уже проведён»

Длительность: 155мс

| Тип | Проверка | Результат |
|---|---|---|
| api | Повторный POST {id}/post → 409 «Документ уже проведён» | ✓ 409 {"error":"Документ уже проведён."} |

## ✓ Step ent06_unpost: POST {id}/unpost → Status=Draft, StockMovement[type=enter-reversal] с -Quantity

Длительность: 508мс

| Тип | Проверка | Результат |
|---|---|---|
| api | POST {id}/unpost → 204 | ✓ 204  |
| api | После Unpost: stock продукта 1 -= 10 | ✓ delta=-10 |
| api | После Unpost: stock продукта 2 -= 5 | ✓ delta=-5 |
| api | После Unpost: Status = Draft (0), PostedAt = null | ✓ status=0 postedAt=null |

## ✓ Step ent07_unpost_negative_guard: Если после Post часть товара продана (Stock < Quantity) — Unpost = 409 с conflicts

Длительность: 1041мс

| Тип | Проверка | Результат |
|---|---|---|
| api | Unpost после расхода → 409 с conflicts (остаток уйдёт в минус) | ✓ 409 {"error":"Нельзя отменить проведение: остаток уйдёт в минус (часть товара уже расходована).","lines":[{"productId":"878b46c7-83d0-4042-81ed-0472117c32c7","productName":"Enter Prod a 1780055835604" |

## ✓ Step ent08_validation_edge_cases: Edge — пустые Lines → 400; POST пустого draft → 400 «без строк»

Длительность: 345мс

| Тип | Проверка | Результат |
|---|---|---|
| api | POST с пустыми lines → 400 | ✓ 400 {"error":"Оприходование должно содержать хотя бы одну позицию."} |
| api | POST с Guid.Empty storeId → 400 | ✓ 400 {"error":"Поле StoreId обязательно.","field":"StoreId"} |
| api | POST с qty<0 → 400 (FluentValidation Range) | ✓ 400 {"type":"https://tools.ietf.org/html/rfc9110#section-15.5.1","title":"One or more validation errors occurred.","status":400,"errors":{"Lines[0].Quantity":["The field Quantity must be between 0 and |

## ✓ Step ent09_multi_tenant_isolation: Org B не видит enter org A (list пустой; GET by id → 404; POST/post → 404)

Длительность: 354мс

| Тип | Проверка | Результат |
|---|---|---|
| api | Org B GET /enters НЕ содержит enter org A | ✓ total=0 sees=false |
| api | Org B GET /enters/{id-чужой} → 404 | ✓ 404 |
| api | Org B POST /enters/{id-чужой}/post → 404 | ✓ 404 |

## ✓ Step ent10_concurrent_put_no_version: Два параллельных PUT (без RowVersion) — оба 204. Logic gap: Enter без IVersionedEntity, транзакция не защищает от lost-update.

Длительность: 637мс

| Тип | Проверка | Результат |
|---|---|---|
| api | Поведение под двумя параллельными PUT (without RowVersion) — last-write-wins | ✓ statuses=[204, 204] |

## Summary

- Passed: 10
- Failed: 0
- Warnings: 0
- Skipped: 0

## Critical bugs

Нет.

## Logic gaps

- Enter не реализует IVersionedEntity → нет xmin concurrency-токена. При параллельных PUT обоих в Draft выигрывает последний (lost-update). TD-6 добавил xmin на Supply/Demand/RetailSale/Transfer/InventoryDoc — Enter/Loss/SupplierReturn/CustomerReturn остались без защиты. Это logic gap, желательно добавить, как минимум вызывается из UI редактора.
