diff --git a/README.md b/README.md
index cd176a3..4893988 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# food-market
- 🟢 **Quality:** [`docs/quality-status.md`](docs/quality-status.md)
+ 🔴 **Quality:** [`docs/quality-status.md`](docs/quality-status.md)
[](http://192.168.1.193:3000/nns/food-market/actions)
[](http://192.168.1.193:3000/nns/food-market/actions)
diff --git a/docs/migration-reconciliation.md b/docs/migration-reconciliation.md
index 77a6930..3062426 100644
--- a/docs/migration-reconciliation.md
+++ b/docs/migration-reconciliation.md
@@ -1,80 +1,34 @@
# Сверка переноса МойСклад → ALL MARKET
-_Сгенерировано 2026-10-09 18:55:15._
+_Сгенерировано 2026-10-09 20:06:41._
## 1. Число документов по типам
| Тип | МойСклад | ALL MARKET | Δ | Статус |
|---|---|---|---|---|
-| Приёмки | 7131 | 7131 | 0 | ✓ |
+| Приёмки | 7132 | 7131 | -1 | ~ дельта |
| Возвраты поставщику | 550 | 550 | 0 | ✓ |
| Оприходования | 72 | 72 | 0 | ✓ |
| Списания | 3068 | 3068 | 0 | ✓ |
-| Розничные продажи | 97761 | 97757 | -4 | ~ дельта |
+| Розничные продажи | 97778 | 97761 | -17 | ~ дельта |
| Розничные возвраты | 438 | 438 | 0 | ✓ |
_Доккаунты: Δ<0 — догоняется дельтой (живой аккаунт рос во время переноса); Δ>0 — разобрать._
## 2. Остатки (товар)
-- Товаров с остатком в МойСкладе: **7579**
-- Позиций (товар) сопоставлено по остатку: **30937**
-- Расхождений: **42** (из них нет в каталоге переноса: **35**, в каталоге: **7**)
+- Товаров с остатком в МойСкладе: **7583**
+- Позиций (товар) сопоставлено по остатку: **30992**
+- Расхождений: **1** (из них нет в каталоге переноса: **1**, в каталоге: **0**)
> **Объяснение расхождений.** Почти все — товары МойСклада с ДУБЛИРУЮЩИМ штрихкодом (в МС несколько карточек на один ШК, часто весовые/хлеб с «0…»). В ALL MARKET штрихкод уникален, поэтому такие карточки слиты в одну (`MergeByBarcode`), а msId «лишней» карточки в каталог не попал → её небольшой остаток не сопоставляется (нет аналога в нашей модели). Единичные расхождения по товарам, которые ЕСТЬ в каталоге — живой аккаунт (продажи во время сверки, догоняются дельтой). **Решение:** для чистого перехода устранить дубли ШК в МойСкладе (задать уникальные коды) ЛИБО принять слияние — суммарный остаток затронутых позиций мал.
-_Нет в каталоге переноса (дубль ШК в МойСкладе → слияние, нет аналога) (35):_
+_Нет в каталоге переноса (дубль ШК в МойСкладе → слияние, нет аналога) (1):_
| MS товар id | МойСклад | ALL MARKET | Δ |
|---|---|---|---|
-| 73205528-e938-11ef-0a80-175500330fcb | 61 | 0 | -61 |
-| 8b61ed46-e937-11ef-0a80-175500323d69 | 24 | 0 | -24 |
-| fc348b52-e936-11ef-0a80-17550031bd68 | 12 | 0 | -12 |
-| b98138dc-e937-11ef-0a80-17550032684d | -8 | 0 | +8 |
-| d6edacf2-42a6-11f0-0a80-10740005b1a2 | 5 | 0 | -5 |
| 5b4e390a-f0fd-11ef-0a80-05e40016676a | 5 | 0 | -5 |
-| e5b59eff-4d13-11f1-0a80-1ac7003c4de8 | 5 | 0 | -5 |
-| 332a6bd4-e958-11ef-0a80-00c1004499a3 | -4 | 0 | +4 |
-| a2a8663c-1459-11f0-0a80-10670009dd87 | 4 | 0 | -4 |
-| c8546fd1-0bb5-11f0-0a80-13750008f717 | 4 | 0 | -4 |
-| 402a80c0-e958-11ef-0a80-00c10044a742 | 3 | 0 | -3 |
-| b507f602-e938-11ef-0a80-1755003356f4 | 3 | 0 | -3 |
-| 97c65fd1-a927-11f0-0a80-1cc20015f801 | 3 | 0 | -3 |
-| 9f2ddb59-e937-11ef-0a80-175500324e12 | 3 | 0 | -3 |
-| 993f7d68-e936-11ef-0a80-17550031622e | 2 | 0 | -2 |
-| 5255b353-5009-11f0-0a80-191e002a9b50 | -2 | 0 | +2 |
-| 6a270b4b-c3c4-11f1-0a80-1137000e40ca | 2 | 0 | -2 |
-| a84e7828-9f86-11f1-0a80-0283002e05a1 | 2 | 0 | -2 |
-| f4a33cf0-e938-11ef-0a80-1755003384c5 | 2 | 0 | -2 |
-| 94e5e2ed-f9e2-11ef-0a80-04e50022a093 | -2 | 0 | +2 |
-| 5831256a-c3c4-11f1-0a80-0e78000e1353 | 2 | 0 | -2 |
-| 5de1c651-2a6b-11f0-0a80-1aca000df4c4 | -2 | 0 | +2 |
-| f43c4aef-e936-11ef-0a80-17550031b76d | 1.44 | 0 | -1.44 |
-| 98a9c5b5-169c-11f0-0a80-0ed000036fc3 | -1 | 0 | +1 |
-| cf15b43d-f15c-11f0-0a80-1c3600129e3f | -1 | 0 | +1 |
-| 7cd4d51b-0570-11f0-0a80-01d5000a0b2c | 1 | 0 | -1 |
-| c399400d-e936-11ef-0a80-175500318cb4 | -1 | 0 | +1 |
-| d83097b9-c3b0-11f0-0a80-1bf7003603df | 1 | 0 | -1 |
-| e2c3ba51-e936-11ef-0a80-17550031a732 | 1 | 0 | -1 |
-| dafc3a7d-e937-11ef-0a80-175500327e40 | -1 | 0 | +1 |
-| 604f8951-5463-11f1-0a80-138e0014965b | 1 | 0 | -1 |
-| 46546392-895d-11f0-0a80-10930005ecc6 | -1 | 0 | +1 |
-| 0267e386-e938-11ef-0a80-17550032a4eb | -1 | 0 | +1 |
-| e3ea0e4e-e938-11ef-0a80-175500337cd9 | -1 | 0 | +1 |
-| dd15ebd1-e937-11ef-0a80-175500327ff8 | -1 | 0 | +1 |
-
-_Есть в каталоге (живой аккаунт/дельта) (7):_
-
-| MS товар id | МойСклад | ALL MARKET | Δ |
-|---|---|---|---|
-| 9e4ae7f0-e936-11ef-0a80-1755003167da | -60 | -56 | +4 |
-| 9b047139-e938-11ef-0a80-1755003346c0 | 38 | 40 | +2 |
-| 0b43ff86-e937-11ef-0a80-17550031c8d9 | 0 | 1 | +1 |
-| d87169e5-e936-11ef-0a80-175500319e86 | 1 | 0 | -1 |
-| fb8b449e-e937-11ef-0a80-17550032a005 | 1 | 0 | -1 |
-| 8c1d613b-e938-11ef-0a80-17550033353f | 1 | 2 | +1 |
-| 50d1842d-872a-11f0-0a80-17b400482545 | -16 | -15 | +1 |
## 3. Выручка и чеки по месяцам (розница, без возвратов)
@@ -107,8 +61,8 @@ _Есть в каталоге (живой аккаунт/дельта) (7):_
| 2026-07 | 8,927,375.15 | 8,899,134.27 | 5388 | 5388 | +0 |
| 2026-08 | 8,973,627.90 | 8,951,418.07 | 5157 | 5157 | +0 |
| 2026-09 | 8,130,513.91 | 8,089,012.19 | 4856 | 4856 | +0 |
-| 2026-10 | 2,283,721.52 | 2,285,446.48 | 1236 | 1232 | -4 ⚠дельта |
-| **Итого** | **168,911,343.41** | **167,445,450.92** | **97761** | **97757** | **-4** |
+| 2026-10 | 2,287,366.52 | 2,310,208.83 | 1253 | 1236 | -17 ⚠дельта |
+| **Итого** | **168,914,988.41** | **167,470,213.27** | **97778** | **97761** | **-17** |
## 4. Балансы счетов
diff --git a/docs/quality-status.md b/docs/quality-status.md
index d52bb21..6dd18bc 100644
--- a/docs/quality-status.md
+++ b/docs/quality-status.md
@@ -1,57 +1,77 @@
# Quality status
-_Обновлено: 2026-06-08T07:48:24+00:00 · auto-gen из `~/quality-watchdog.sh`_
+_Обновлено: 2026-10-09T15:09:30+00:00 · auto-gen из `~/quality-watchdog.sh`_
-## 🟢 Текущий статус
+## 🔴 Текущий статус
-**Последний прогон:** `2026-06-08T12:48:01+05:00`
-**Зелёных шагов:** 8/8
-**Красных шагов:** 0
+**Последний прогон:** `2026-10-09T20:05:01+05:00`
+**Зелёных шагов:** 5/8
+**Красных шагов:** 4
## Шаги smoke-suite
| Шаг | Статус | Последнее изменение | Consecutive fail |
|---|---|---|---|
-| /health/ready | 🟢 | `2026-06-08T12:48:01+05:00` | 0 |
-| signup→login→/api/me | 🟢 | `2026-06-08T12:48:01+05:00` | 0 |
-| GET /api/catalog/products | 🟢 | `2026-06-08T12:48:01+05:00` | 0 |
-| Playwright UI (product CRUD) | 🟢 | `2026-06-08T12:48:01+05:00` | 0 |
-| /metrics (Prometheus) | 🟢 | `2026-06-08T12:48:01+05:00` | 0 |
-| /hubs/notifications/negotiate | 🟢 | `2026-06-08T12:48:01+05:00` | 0 |
-| Multi-tenant isolation | 🟢 | `2026-06-08T12:48:01+05:00` | 0 |
-| Performance p95 vs baseline | 🟢 | `2026-06-08T12:48:01+05:00` | 0 |
+| /health/ready | 🟢 | `2026-10-09T20:05:01+05:00` | 0 |
+| signup→login→/api/me | 🔴 | `2026-10-09T20:05:01+05:00` | 27 |
+| GET /api/catalog/products | 🔴 | `2026-10-09T20:05:01+05:00` | 27 |
+| Playwright UI (product CRUD) | 🟢 | `2026-10-09T20:05:01+05:00` | 0 |
+| /metrics (Prometheus) | 🟢 | `2026-10-09T20:05:01+05:00` | 0 |
+| /hubs/notifications/negotiate | 🔴 | `2026-10-09T20:05:01+05:00` | 27 |
+| Multi-tenant isolation | 🟢 | `2026-10-09T20:05:01+05:00` | 0 |
+| Performance p95 vs baseline | 🔴 | `2026-10-09T20:05:01+05:00` | 27 |
+
+## Детали падений (последний прогон)
+
+- `auth_me: не удалось получить admin token (len=0)`
+- `products: skipped (нет токена)`
+- `signalr: skipped (нет токена)`
+- `perf: skipped (нет токена)`
## Performance baseline (p95, ms)
| Endpoint | p95 (ms) |
|---|---|
-| `/api/catalog/products/page/1/pageSize/10` | 233 |
-| `/api/me` | 259 |
-| `/api/sales/retail/stats/days/7` | 228 |
+| `/api/catalog/products/page/1/pageSize/10` | 363 |
+| `/api/me` | 279 |
+| `/api/sales/retail/stats/days/7` | 269 |
_Регрессия = текущий p95 >50% от baseline. Baseline обновляется только когда регрессии нет (берёт min)._
## История за 7 дней
-**Прогонов:** 14
-**С красным:** 7
-**Green-ratio:** 50%
+**Прогонов:** 165
+**С красным:** 40
+**Green-ratio:** 75%
### Прогоны с красным шагом
| Время | Красные шаги |
|---|---|
-| `2026-06-08T12:16:05+05:00` | multi_tenant |
-| `2026-06-08T12:16:52+05:00` | multi_tenant |
-| `2026-06-08T12:18:01+05:00` | multi_tenant |
-| `2026-06-08T12:18:35+05:00` | multi_tenant |
-| `2026-06-08T12:22:49+05:00` | health, auth_me, products, metrics, signalr, multi_tenant, perf |
-| `2026-06-08T12:23:00+05:00` | health, auth_me, products, metrics, signalr, multi_tenant, perf |
-| `2026-06-08T12:23:18+05:00` | perf |
+| `2026-10-09T01:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T02:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T03:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T04:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T05:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T06:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T07:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T08:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T09:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T10:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T11:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T12:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T13:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T14:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T15:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T16:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T17:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T18:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T19:05:01+05:00` | auth_me, products, signalr, perf |
+| `2026-10-09T20:05:01+05:00` | auth_me, products, signalr, perf |
## Последние 24 прогона
-`🔴🔴🔴🔴🟢🟢🔴🔴🔴🟢🟢🟢🟢🟢`
+`🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴`
---
diff --git a/global.json b/global.json
index 581be33..c3ed38b 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "8.0.417",
+ "version": "8.0.131",
"rollForward": "latestFeature",
"allowPrerelease": false
}
diff --git a/scripts/migration/__pycache__/delta_sync.cpython-312.pyc b/scripts/migration/__pycache__/delta_sync.cpython-312.pyc
new file mode 100644
index 0000000..2bac227
Binary files /dev/null and b/scripts/migration/__pycache__/delta_sync.cpython-312.pyc differ
diff --git a/scripts/migration/__pycache__/reconcile.cpython-312.pyc b/scripts/migration/__pycache__/reconcile.cpython-312.pyc
new file mode 100644
index 0000000..a6af867
Binary files /dev/null and b/scripts/migration/__pycache__/reconcile.cpython-312.pyc differ
diff --git a/scripts/migration/reconcile.py b/scripts/migration/reconcile.py
index 5164c45..283764b 100644
--- a/scripts/migration/reconcile.py
+++ b/scripts/migration/reconcile.py
@@ -123,13 +123,12 @@ try:
print(f"- Позиций (товар) сопоставлено по остатку: **{matched}**")
print(f"- Расхождений: **{len(mism)}** (из них нет в каталоге переноса: **{len(not_in_cat)}**, "
f"в каталоге: **{len(in_cat)}**)")
- print("\n> **Объяснение расхождений.** Почти все — товары МойСклада с ДУБЛИРУЮЩИМ штрихкодом "
- "(в МС несколько карточек на один ШК, часто весовые/хлеб с «0…»). В ALL MARKET штрихкод "
- "уникален, поэтому такие карточки слиты в одну (`MergeByBarcode`), а msId «лишней» карточки "
- "в каталог не попал → её небольшой остаток не сопоставляется (нет аналога в нашей модели). "
- "Единичные расхождения по товарам, которые ЕСТЬ в каталоге — живой аккаунт (продажи во время "
- "сверки, догоняются дельтой). **Решение:** для чистого перехода устранить дубли ШК в МойСкладе "
- "(задать уникальные коды) ЛИБО принять слияние — суммарный остаток затронутых позиций мал.\n")
+ print("\n> **Объяснение расхождений.** После фикса ревью карточки с дублем штрихкода переносятся КАЖДАЯ "
+ "отдельно (уникальность ШК снята, Phase44; дубли видны в «Проверке данных» → dup-barcode), а "
+ "остатки выровнены к снимку `report/stock/all` МойСклада (движения `Initial` «МС-выравнивание»). "
+ "Поэтому расхождений по каталогу быть не должно. Оставшиеся единичные — ЖИВОЙ аккаунт (продажи "
+ "между выравниванием и сверкой), догоняются дельтой; «нет в каталоге» — редкие товары, которых "
+ "нет в выгрузке (архивные/служебные). Суммарный остаток затронутых позиций мал.\n")
def tbl(rows,title):
if not rows: return
print(f"\n_{title} ({len(rows)}):_\n")
diff --git a/src/food-market.infrastructure/Integrations/MoySklad/MoySkladImportService.cs b/src/food-market.infrastructure/Integrations/MoySklad/MoySkladImportService.cs
index df1af5a..ab224d9 100644
--- a/src/food-market.infrastructure/Integrations/MoySklad/MoySkladImportService.cs
+++ b/src/food-market.infrastructure/Integrations/MoySklad/MoySkladImportService.cs
@@ -378,8 +378,14 @@ await foreach (var p in _client.StreamProductsAsync(token, ct, includeArchived:
if (existing is null && !string.IsNullOrWhiteSpace(article) &&
existingByArticle.TryGetValue(article, out var byArt))
{
- existing = byArt;
- mergeTag = "merge-article";
+ // «Минимум как МойСклад»: НЕ схлопываем две РАЗНЫЕ карточки МойСклада
+ // (разные msId, но одинаковый артикул) в одну. Привязка по артикулу —
+ // только к товару без msId (ручной) или с тем же msId.
+ if (byArt.MoySkladExternalId is null || byArt.MoySkladExternalId == p.Id)
+ {
+ existing = byArt;
+ mergeTag = "merge-article";
+ }
}
// 3) Common fields.
diff --git a/tests/e2e/reports/breadcrumbs-product-1780122623474.png b/tests/e2e/reports/breadcrumbs-product-1780122623474.png
new file mode 100644
index 0000000..7f5ee1a
Binary files /dev/null and b/tests/e2e/reports/breadcrumbs-product-1780122623474.png differ
diff --git a/tests/e2e/reports/confirm-dialog-1780119970286.png b/tests/e2e/reports/confirm-dialog-1780119970286.png
new file mode 100644
index 0000000..69741aa
Binary files /dev/null and b/tests/e2e/reports/confirm-dialog-1780119970286.png differ
diff --git a/tests/e2e/reports/confirm-list-1780119970286.png b/tests/e2e/reports/confirm-list-1780119970286.png
new file mode 100644
index 0000000..f5a23ca
Binary files /dev/null and b/tests/e2e/reports/confirm-list-1780119970286.png differ
diff --git a/tests/e2e/reports/dark-mode/01-dashboard-dark.png b/tests/e2e/reports/dark-mode/01-dashboard-dark.png
new file mode 100644
index 0000000..cb704aa
Binary files /dev/null and b/tests/e2e/reports/dark-mode/01-dashboard-dark.png differ
diff --git a/tests/e2e/reports/dark-mode/01-dashboard-light.png b/tests/e2e/reports/dark-mode/01-dashboard-light.png
new file mode 100644
index 0000000..8791923
Binary files /dev/null and b/tests/e2e/reports/dark-mode/01-dashboard-light.png differ
diff --git a/tests/e2e/reports/dark-mode/02-products-dark.png b/tests/e2e/reports/dark-mode/02-products-dark.png
new file mode 100644
index 0000000..4a0bde9
Binary files /dev/null and b/tests/e2e/reports/dark-mode/02-products-dark.png differ
diff --git a/tests/e2e/reports/dark-mode/02-products-light.png b/tests/e2e/reports/dark-mode/02-products-light.png
new file mode 100644
index 0000000..bcb214b
Binary files /dev/null and b/tests/e2e/reports/dark-mode/02-products-light.png differ
diff --git a/tests/e2e/reports/dark-mode/03-counterparties-dark.png b/tests/e2e/reports/dark-mode/03-counterparties-dark.png
new file mode 100644
index 0000000..3601e4c
Binary files /dev/null and b/tests/e2e/reports/dark-mode/03-counterparties-dark.png differ
diff --git a/tests/e2e/reports/dark-mode/03-counterparties-light.png b/tests/e2e/reports/dark-mode/03-counterparties-light.png
new file mode 100644
index 0000000..9f774cc
Binary files /dev/null and b/tests/e2e/reports/dark-mode/03-counterparties-light.png differ
diff --git a/tests/e2e/reports/dark-mode/04-stock-dark.png b/tests/e2e/reports/dark-mode/04-stock-dark.png
new file mode 100644
index 0000000..cfb838f
Binary files /dev/null and b/tests/e2e/reports/dark-mode/04-stock-dark.png differ
diff --git a/tests/e2e/reports/dark-mode/04-stock-light.png b/tests/e2e/reports/dark-mode/04-stock-light.png
new file mode 100644
index 0000000..cfcac75
Binary files /dev/null and b/tests/e2e/reports/dark-mode/04-stock-light.png differ
diff --git a/tests/e2e/reports/dark-mode/05-supplies-dark.png b/tests/e2e/reports/dark-mode/05-supplies-dark.png
new file mode 100644
index 0000000..13d57de
Binary files /dev/null and b/tests/e2e/reports/dark-mode/05-supplies-dark.png differ
diff --git a/tests/e2e/reports/dark-mode/05-supplies-light.png b/tests/e2e/reports/dark-mode/05-supplies-light.png
new file mode 100644
index 0000000..0737e19
Binary files /dev/null and b/tests/e2e/reports/dark-mode/05-supplies-light.png differ
diff --git a/tests/e2e/reports/dark-mode/06-retail-sales-dark.png b/tests/e2e/reports/dark-mode/06-retail-sales-dark.png
new file mode 100644
index 0000000..65ed9c1
Binary files /dev/null and b/tests/e2e/reports/dark-mode/06-retail-sales-dark.png differ
diff --git a/tests/e2e/reports/dark-mode/06-retail-sales-light.png b/tests/e2e/reports/dark-mode/06-retail-sales-light.png
new file mode 100644
index 0000000..0b4f10a
Binary files /dev/null and b/tests/e2e/reports/dark-mode/06-retail-sales-light.png differ
diff --git a/tests/e2e/reports/dark-mode/07-report-sales-dark.png b/tests/e2e/reports/dark-mode/07-report-sales-dark.png
new file mode 100644
index 0000000..2c39a85
Binary files /dev/null and b/tests/e2e/reports/dark-mode/07-report-sales-dark.png differ
diff --git a/tests/e2e/reports/dark-mode/07-report-sales-light.png b/tests/e2e/reports/dark-mode/07-report-sales-light.png
new file mode 100644
index 0000000..9e1fe7a
Binary files /dev/null and b/tests/e2e/reports/dark-mode/07-report-sales-light.png differ
diff --git a/tests/e2e/reports/dark-mode/08-report-stock-dark.png b/tests/e2e/reports/dark-mode/08-report-stock-dark.png
new file mode 100644
index 0000000..7177c41
Binary files /dev/null and b/tests/e2e/reports/dark-mode/08-report-stock-dark.png differ
diff --git a/tests/e2e/reports/dark-mode/08-report-stock-light.png b/tests/e2e/reports/dark-mode/08-report-stock-light.png
new file mode 100644
index 0000000..0978905
Binary files /dev/null and b/tests/e2e/reports/dark-mode/08-report-stock-light.png differ
diff --git a/tests/e2e/reports/dark-mode/09-report-profit-dark.png b/tests/e2e/reports/dark-mode/09-report-profit-dark.png
new file mode 100644
index 0000000..2d730a0
Binary files /dev/null and b/tests/e2e/reports/dark-mode/09-report-profit-dark.png differ
diff --git a/tests/e2e/reports/dark-mode/09-report-profit-light.png b/tests/e2e/reports/dark-mode/09-report-profit-light.png
new file mode 100644
index 0000000..aa66fb2
Binary files /dev/null and b/tests/e2e/reports/dark-mode/09-report-profit-light.png differ
diff --git a/tests/e2e/reports/dark-mode/10-report-abc-dark.png b/tests/e2e/reports/dark-mode/10-report-abc-dark.png
new file mode 100644
index 0000000..a7eec92
Binary files /dev/null and b/tests/e2e/reports/dark-mode/10-report-abc-dark.png differ
diff --git a/tests/e2e/reports/dark-mode/10-report-abc-light.png b/tests/e2e/reports/dark-mode/10-report-abc-light.png
new file mode 100644
index 0000000..3a5297d
Binary files /dev/null and b/tests/e2e/reports/dark-mode/10-report-abc-light.png differ
diff --git a/tests/e2e/reports/dq-dashboard-1791516458306.png b/tests/e2e/reports/dq-dashboard-1791516458306.png
new file mode 100644
index 0000000..83e39db
Binary files /dev/null and b/tests/e2e/reports/dq-dashboard-1791516458306.png differ
diff --git a/tests/e2e/reports/dq-panel-1791516458306.png b/tests/e2e/reports/dq-panel-1791516458306.png
new file mode 100644
index 0000000..ce602a4
Binary files /dev/null and b/tests/e2e/reports/dq-panel-1791516458306.png differ
diff --git a/tests/e2e/reports/empty-state-products-1780122048413.png b/tests/e2e/reports/empty-state-products-1780122048413.png
new file mode 100644
index 0000000..d3e4e54
Binary files /dev/null and b/tests/e2e/reports/empty-state-products-1780122048413.png differ
diff --git a/tests/e2e/reports/empty-state-supplies-1780122048413.png b/tests/e2e/reports/empty-state-supplies-1780122048413.png
new file mode 100644
index 0000000..900911a
Binary files /dev/null and b/tests/e2e/reports/empty-state-supplies-1780122048413.png differ
diff --git a/tests/e2e/reports/filters-sweep-2026-10-09T05-10-00-436Z.md b/tests/e2e/reports/filters-sweep-2026-10-09T05-10-00-436Z.md
new file mode 100644
index 0000000..6df4a56
--- /dev/null
+++ b/tests/e2e/reports/filters-sweep-2026-10-09T05-10-00-436Z.md
@@ -0,0 +1,29 @@
+# Filters-sweep 2026-10-09T05-10-00-436Z
+
+Стенд: https://test.admin.food-market.kz · орг: e2e-fullchain-1791522587555@food-market.local
+
+**Итог:** 21 ✓ / 0 ✗
+
+| | Проверка | Детали |
+|---|---|---|
+| ✓ | stock: без includeZero = только ненулевые | ожидали 3 |
+| ✓ | stock: includeZero=true = все не-услуги | получили 4 |
+| ✓ | stock: услуга никогда не в остатках | |
+| ✓ | stock: includeZero добавляет именно нулевой товар | |
+| ✓ | stock: negativeOnly=true = только минус | |
+| ✓ | stock: groupId=parent (+zero) = всё поддерево (3 уровня) | |
+| ✓ | stock: groupId=grandchild = только внук | |
+| ✓ | stock: productGroupId — синоним groupId | |
+| ✓ | stock: groupId без zero = только ненулевые из группы | |
+| ✓ | stock: поиск по артикулу | |
+| ✓ | stock: поиск по штрихкоду | |
+| ✓ | stock: другой склад без остатков и без zero = пусто | получили 0 |
+| ✓ | stock: другой склад + includeZero = все товары с 0 | |
+| ✓ | stock: сортировка по количеству (asc) монотонна | [-3,0,5,10] |
+| ✓ | stock: пагинация без пересечений | page1=2 page2=2 total=4 |
+| ✓ | stock: total пагинации = полному набору | 4 vs 4 |
+| ✓ | stock/export: includeZero отдаёт все товары | строк 4 |
+| ✓ | catalog: groupId=parent = поддерево | |
+| ✓ | catalog: productGroupId — синоним (раньше молча игнорировался) | |
+| ✓ | catalog: groupId=grandchild = только внук | |
+| ✓ | catalog: isService=true = только услуги | |
\ No newline at end of file
diff --git a/tests/e2e/reports/filters-sweep-2026-10-09T05-21-57-290Z.md b/tests/e2e/reports/filters-sweep-2026-10-09T05-21-57-290Z.md
new file mode 100644
index 0000000..dbac6de
--- /dev/null
+++ b/tests/e2e/reports/filters-sweep-2026-10-09T05-21-57-290Z.md
@@ -0,0 +1,29 @@
+# Filters-sweep 2026-10-09T05-21-57-290Z
+
+Стенд: https://test.admin.food-market.kz · орг: e2e-fullchain-1791523309816@food-market.local
+
+**Итог:** 21 ✓ / 0 ✗
+
+| | Проверка | Детали |
+|---|---|---|
+| ✓ | stock: без includeZero = только ненулевые | ожидали 3 |
+| ✓ | stock: includeZero=true = все не-услуги | получили 4 |
+| ✓ | stock: услуга никогда не в остатках | |
+| ✓ | stock: includeZero добавляет именно нулевой товар | |
+| ✓ | stock: negativeOnly=true = только минус | |
+| ✓ | stock: groupId=parent (+zero) = всё поддерево (3 уровня) | |
+| ✓ | stock: groupId=grandchild = только внук | |
+| ✓ | stock: productGroupId — синоним groupId | |
+| ✓ | stock: groupId без zero = только ненулевые из группы | |
+| ✓ | stock: поиск по артикулу | |
+| ✓ | stock: поиск по штрихкоду | |
+| ✓ | stock: другой склад без остатков и без zero = пусто | получили 0 |
+| ✓ | stock: другой склад + includeZero = все товары с 0 | |
+| ✓ | stock: сортировка по количеству (asc) монотонна | [-3,0,5,10] |
+| ✓ | stock: пагинация без пересечений | page1=2 page2=2 total=4 |
+| ✓ | stock: total пагинации = полному набору | 4 vs 4 |
+| ✓ | stock/export: includeZero отдаёт все товары | строк 4 |
+| ✓ | catalog: groupId=parent = поддерево | |
+| ✓ | catalog: productGroupId — синоним (раньше молча игнорировался) | |
+| ✓ | catalog: groupId=grandchild = только внук | |
+| ✓ | catalog: isService=true = только услуги | |
\ No newline at end of file
diff --git a/tests/e2e/reports/filters-sweep-2026-10-09T06-24-38-578Z.md b/tests/e2e/reports/filters-sweep-2026-10-09T06-24-38-578Z.md
new file mode 100644
index 0000000..04425de
--- /dev/null
+++ b/tests/e2e/reports/filters-sweep-2026-10-09T06-24-38-578Z.md
@@ -0,0 +1,29 @@
+# Filters-sweep 2026-10-09T06-24-38-578Z
+
+Стенд: https://test.admin.food-market.kz · орг: e2e-fullchain-1791527070732@food-market.local
+
+**Итог:** 21 ✓ / 0 ✗
+
+| | Проверка | Детали |
+|---|---|---|
+| ✓ | stock: без includeZero = только ненулевые | ожидали 3 |
+| ✓ | stock: includeZero=true = все не-услуги | получили 4 |
+| ✓ | stock: услуга никогда не в остатках | |
+| ✓ | stock: includeZero добавляет именно нулевой товар | |
+| ✓ | stock: negativeOnly=true = только минус | |
+| ✓ | stock: groupId=parent (+zero) = всё поддерево (3 уровня) | |
+| ✓ | stock: groupId=grandchild = только внук | |
+| ✓ | stock: productGroupId — синоним groupId | |
+| ✓ | stock: groupId без zero = только ненулевые из группы | |
+| ✓ | stock: поиск по артикулу | |
+| ✓ | stock: поиск по штрихкоду | |
+| ✓ | stock: другой склад без остатков и без zero = пусто | получили 0 |
+| ✓ | stock: другой склад + includeZero = все товары с 0 | |
+| ✓ | stock: сортировка по количеству (asc) монотонна | [-3,0,5,10] |
+| ✓ | stock: пагинация без пересечений | page1=2 page2=2 total=4 |
+| ✓ | stock: total пагинации = полному набору | 4 vs 4 |
+| ✓ | stock/export: includeZero отдаёт все товары | строк 4 |
+| ✓ | catalog: groupId=parent = поддерево | |
+| ✓ | catalog: productGroupId — синоним (раньше молча игнорировался) | |
+| ✓ | catalog: groupId=grandchild = только внук | |
+| ✓ | catalog: isService=true = только услуги | |
\ No newline at end of file
diff --git a/tests/e2e/reports/full-chain-2026-10-07T19-19-52-313Z.md b/tests/e2e/reports/full-chain-2026-10-07T19-19-52-313Z.md
new file mode 100644
index 0000000..7fc21d7
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-07T19-19-52-313Z.md
@@ -0,0 +1,164 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T19:19:39.366Z
+Длительность: 12.9с
+
+**Итог:** 3 ✓ / 2 ✗ / 0 ⚠ / 11 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2582мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✗ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2941мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Товар №3 создан | ✗ ожид=200 факт=400 |
+| api | Создано 5 товаров (разные ед.изм.) | ✗ ожид=5 факт=4 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✗ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 5736мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791400779365 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791400779365 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги 403 | ✗ ожид=403 факт=200 |
+| api | Кассир → сотрудники/настройки 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✗ ожид=200 факт=404 |
+| api | Блокировка (увольнение) сотрудника | ✗ ожид=200 факт=404 |
+| api | Заблокированный кассир не получает токен | ✗ ожид=отказ факт=200 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 952мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 734мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ◯ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 1мс
+
+## ◯ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 0мс
+
+> Handler step06_supply2_excel не найден в full-chain.steps.ts
+
+## ◯ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 0мс
+
+> Handler step07_supply3_photo не найден в full-chain.steps.ts
+
+## ◯ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 0мс
+
+> Handler step08_supplier_payments не найден в full-chain.steps.ts
+
+## ◯ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 0мс
+
+> Handler step09_cashier_shift не найден в full-chain.steps.ts
+
+## ◯ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 0мс
+
+> Handler step09a_points_binding не найден в full-chain.steps.ts
+
+## ◯ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 0мс
+
+> Handler step10_warehouse_ops не найден в full-chain.steps.ts
+
+## ◯ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 0мс
+
+> Handler step11_reports не найден в full-chain.steps.ts
+
+## ◯ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 0мс
+
+> Handler step12_invariants не найден в full-chain.steps.ts
+
+## ◯ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 0мс
+
+> Handler step13_cancel_rollback не найден в full-chain.steps.ts
+
+## ◯ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 0мс
+
+> Handler step14_finalize не найден в full-chain.steps.ts
+
+## Summary
+
+- Passed: 3
+- Failed: 2
+- Warnings: 0
+- Skipped: 11
+
+## Critical bugs
+
+### CRITICAL
+
+- **[02] Товар №3 не создан**
+ - 400 {"error":"Штрихкод 2791400779372 уже используется товаром «Товар 2 fc1791400779365»."}
+- **[02a] Кассир видит деньги/настройки**
+ - money=200 emps=403
+- **[02a] Заблокированный сотрудник всё ещё входит**
+ - token выдан (200)
diff --git a/tests/e2e/reports/full-chain-2026-10-07T19-25-00-580Z.md b/tests/e2e/reports/full-chain-2026-10-07T19-25-00-580Z.md
new file mode 100644
index 0000000..0c0bbeb
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-07T19-25-00-580Z.md
@@ -0,0 +1,171 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T19:24:47.162Z
+Длительность: 13.4с
+
+**Итог:** 5 ✓ / 1 ✗ / 0 ⚠ / 10 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2651мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2289мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✗ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 4600мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791401087162 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791401087162 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги 403 | ✗ ожид=403 факт=200 |
+| api | Кассир → сотрудники/настройки 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✗ ожид=200 факт=500 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 900мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 439мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2537мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток f9e5968a… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 06a69d08… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 6e19a8ae… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток fce9dd8a… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток bb8746bc… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ◯ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 0мс
+
+> Handler step06_supply2_excel не найден в full-chain.steps.ts
+
+## ◯ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 0мс
+
+> Handler step07_supply3_photo не найден в full-chain.steps.ts
+
+## ◯ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 0мс
+
+> Handler step08_supplier_payments не найден в full-chain.steps.ts
+
+## ◯ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 0мс
+
+> Handler step09_cashier_shift не найден в full-chain.steps.ts
+
+## ◯ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 0мс
+
+> Handler step09a_points_binding не найден в full-chain.steps.ts
+
+## ◯ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 0мс
+
+> Handler step10_warehouse_ops не найден в full-chain.steps.ts
+
+## ◯ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 0мс
+
+> Handler step11_reports не найден в full-chain.steps.ts
+
+## ◯ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 0мс
+
+> Handler step12_invariants не найден в full-chain.steps.ts
+
+## ◯ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 0мс
+
+> Handler step13_cancel_rollback не найден в full-chain.steps.ts
+
+## ◯ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 0мс
+
+> Handler step14_finalize не найден в full-chain.steps.ts
+
+## Summary
+
+- Passed: 5
+- Failed: 1
+- Warnings: 0
+- Skipped: 10
+
+## Critical bugs
+
+### CRITICAL
+
+- **[02a] Кассир видит деньги/настройки**
+ - money=200 emps=403
diff --git a/tests/e2e/reports/full-chain-2026-10-07T19-33-46-792Z.md b/tests/e2e/reports/full-chain-2026-10-07T19-33-46-792Z.md
new file mode 100644
index 0000000..a97d435
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-07T19-33-46-792Z.md
@@ -0,0 +1,257 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T19:32:45.863Z
+Длительность: 60.9с
+
+**Итог:** 13 ✓ / 3 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2492мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2165мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✗ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 4955мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791401565862 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791401565862 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги 403 | ✗ ожид=403 факт=200 |
+| api | Кассир → сотрудники/настройки 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✗ ожид=200 факт=500 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 902мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 462мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2797мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток b31b6d8a… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток ca037582… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток faa2e546… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 0ae22a4d… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток ea0cedad… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5540мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914015 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914015 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914015 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 23364мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Фото-накладная распознана (OCR, needs_review) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1161мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 5341мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✗ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3051мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✗ ожид=4xx факт=200 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 3597мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1055мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по точкам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по кассирам доступен | ✓ ожид=200 факт=200 |
+
+## ✗ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3129мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914015 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140156 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: вход demo-admin | ✗ ожид=token факт=token demo-admin@food-market.local: 400 {"error":"invalid_gr |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 918мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 0мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 13
+- Failed: 3
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+### CRITICAL
+
+- **[02a] Кассир видит деньги/настройки**
+ - money=200 emps=403
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
+
+## Logic gaps
+
+- Открытие смены на НЕактивной точке продаж не отклоняется сервером — продажа на деактивированной точке возможна.
diff --git a/tests/e2e/reports/full-chain-2026-10-07T19-47-59-669Z.md b/tests/e2e/reports/full-chain-2026-10-07T19-47-59-669Z.md
new file mode 100644
index 0000000..389d406
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-07T19-47-59-669Z.md
@@ -0,0 +1,251 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T19:46:46.876Z
+Длительность: 72.8с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 3119мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 4092мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 5676мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791402406876 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791402406876 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1355мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 803мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 8654мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток ed2f8221… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 313285a8… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 7fa320d6… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток b33d6804… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 6ee491a1… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5702мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914024 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914024 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914024 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 23355мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Фото-накладная распознана (OCR, needs_review) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1718мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 6760мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2512мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 3507мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1214мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по точкам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по кассирам доступен | ✓ ожид=200 факт=200 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3517мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914024 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140240 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 805мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-07T20-04-36-379Z.md b/tests/e2e/reports/full-chain-2026-10-07T20-04-36-379Z.md
new file mode 100644
index 0000000..1e43494
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-07T20-04-36-379Z.md
@@ -0,0 +1,263 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:03:33.268Z
+Длительность: 63.1с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2185мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вход demo-admin (режим B) | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 1413мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Выбрано реальных товаров каталога (≥5, штрихкод+цена) | ✓ ожид=≥5 факт=12 |
+| api | Среди выбранных есть весовой (информативно) | ✓ ожид=≥0 факт=0 |
+| api | Поставщик [e2e] создан | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 5004мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 (e2e) 1791403413267 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 (e2e) 1791403413267 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1002мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 491мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 4926мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 0bd54f29… +20 | ✓ ожид=20 факт=20 |
+| api | Остаток 0cfad6a5… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток e6e79bf2… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток fbe7d065… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 3a92d8a7… +40 | ✓ ожид=40 факт=40 |
+| api | Остаток 9a6a59f8… +45 | ✓ ожид=45 факт=45 |
+| api | Остаток db59983d… +50 | ✓ ожид=50 факт=50 |
+| api | Остаток 66866675… +55 | ✓ ожид=55 факт=55 |
+| api | Остаток a6d3c6a1… +60 | ✓ ожид=60 факт=60 |
+| api | Остаток f75a5241… +65 | ✓ ожид=65 факт=65 |
+| api | Остаток 519251c8… +70 | ✓ ожид=70 факт=70 |
+| api | Остаток 89f82dd6… +75 | ✓ ожид=75 факт=75 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=900 факт=900 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5142мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток "BIOBLAS" шампунь +7 | ✓ ожид=7 факт=7 |
+| api | Остаток "BIOBLAS" шампунь +4 | ✓ ожид=4 факт=4 |
+| api | Остаток "BIOBLAS" шампунь +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 23243мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Фото-накладная распознана (OCR, needs_review) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1161мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=148812 факт=148812 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=18390 факт=18390 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=349498 факт=349498 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 4838мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=14275 факт=14275 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=3775/14275 факт=3775/14275 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2865мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2500 факт=2500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=3550 факт=3550 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 2778мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=48 факт=48 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1150мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=7650 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=-98812 факт=-98812 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=181610 факт=181610 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по точкам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по кассирам доступен | ✓ ожид=200 факт=200 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 4912мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=48 факт=48 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: "IQ уроки" книги | ✓ ожид=38 факт=38 |
+| api | Инвариант остаток≡Σдвижений: "Ludwik" средств | ✓ ожид=45 факт=45 |
+| api | Инвариант остаток≡Σдвижений: "Ludwik" средств | ✓ ожид=50 факт=50 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=55 факт=55 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=60 факт=60 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=65 факт=65 |
+| api | Инвариант остаток≡Σдвижений: "Rice Day" GRANA | ✓ ожид=70 факт=70 |
+| api | Инвариант остаток≡Σдвижений: "Richmond" Gold | ✓ ожид=75 факт=75 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса (e2e) 1791 | ✓ ожид=-98812 факт=-98812 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 (e2e) 17 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк (e2e) 17914 | ✓ ожид=181610 факт=181610 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг (e2e) | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 (e2e | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=349498 факт=349498 |
+| api | Изоляция: режим B (демо) — проверка через temp-орг в режиме C | ✓ ожид=n/a факт=n/a |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 775мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=498310 факт=498310 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1222мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим B: e2e-сотрудники деактивированы (не удалены) | ✓ ожид=3 факт=3 |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-07T20-16-55-604Z.md b/tests/e2e/reports/full-chain-2026-10-07T20-16-55-604Z.md
new file mode 100644
index 0000000..cd40d3e
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-07T20-16-55-604Z.md
@@ -0,0 +1,260 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:16:02.029Z
+Длительность: 53.6с
+
+**Итог:** 14 ✓ / 2 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2367мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2269мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 7271мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791404162028 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791404162028 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1046мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 483мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2593мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 03418a53… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 918d099e… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 2416b8d6… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 785e527a… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 6ab8727f… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5234мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914041 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914041 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914041 +9 | ✓ ожид=9 факт=9 |
+
+## ✗ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 16113мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Фото-накладная распознана (OCR, needs_review) | ✗ ожид=needs_review факт=failed |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1229мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=150850 факт=150850 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 4665мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2646мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 2433мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=16.5 факт=16.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=38 факт=38 |
+
+## ✗ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1077мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✗ ожид=3300 факт=0 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3362мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=16.5 факт=16.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=27 факт=27 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914041 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140416 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=150850 факт=150850 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 783мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=184750 факт=184750 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 14
+- Failed: 2
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+### HIGH
+
+- **[07] OCR фото-накладной не дал needs_review**
+ - status=failed
+
+### MEDIUM
+
+- **[11] Выручка по точкам ≠ общей выручке**
+ - точки=0 всего=3300
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-07T20-25-29-826Z.md b/tests/e2e/reports/full-chain-2026-10-07T20-25-29-826Z.md
new file mode 100644
index 0000000..52d9eac
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-07T20-25-29-826Z.md
@@ -0,0 +1,259 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:24:07.574Z
+Длительность: 82.2с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 3034мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 3871мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 7730мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791404647572 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791404647572 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1320мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 831мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 4602мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 3a2c514b… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток afd9b5b0… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток b4529814… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 65d3b4e8… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 6497cf02… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 6168мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914046 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914046 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914046 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 32835мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1778мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 6887мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3305мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 4172мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1386мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3466мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914046 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140464 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 860мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-07T20-52-40-354Z.md b/tests/e2e/reports/full-chain-2026-10-07T20-52-40-354Z.md
new file mode 100644
index 0000000..c905419
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-07T20-52-40-354Z.md
@@ -0,0 +1,271 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:51:43.718Z
+Длительность: 56.6с
+
+**Итог:** 15 ✓ / 1 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2792мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2776мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 7022мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791406303717 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791406303717 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 897мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 468мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2505мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 22cefc7d… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 43d1e648… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 8701ced3… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 8e84b005… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток f4998fc5… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5090мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914063 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914063 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914063 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 16921мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1225мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 4802мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2968мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✗ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 4114мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✗ ожид=<400 факт=403 |
+| api | Кладовщик → списание доступно (не 403) | ✗ ожид=<400 факт=403 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✗ ожид=35 факт=0 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✗ ожид=2 факт=0 |
+| api | Импорт инвентаризации нашёл 2 товара | ✗ ожид=2 факт=0 |
+| api | Инвентаризация (частичная) создана | ✗ ожид=200+id факт=400 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1095мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3186мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=0 факт=0 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=0 факт=0 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=8 факт=8 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914063 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140630 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 771мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 15
+- Failed: 1
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+### CRITICAL
+
+- **[10] Пустая инвентаризация обнулила непосчитанные товары**
+ - было 35 стало 0
+
+### HIGH
+
+- **[10] Кладовщик без прав на склад (API 403, а веб показывает)**
+ - enter=403 loss=403
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-07T20-58-59-996Z.md b/tests/e2e/reports/full-chain-2026-10-07T20-58-59-996Z.md
new file mode 100644
index 0000000..f9fc1e3
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-07T20-58-59-996Z.md
@@ -0,0 +1,266 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:57:50.326Z
+Длительность: 69.7с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 4773мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 4937мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 8635мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791406670325 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791406670325 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1400мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 913мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 3659мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 7391b5ff… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток b4a3d930… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток a070e2ee… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 415f8c48… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 557dc716… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5734мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914066 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914066 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914066 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 17010мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1486мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 6373мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3274мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 6052мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1133мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3472мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914066 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140667 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 813мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-07T21-48-52-494Z.md b/tests/e2e/reports/full-chain-2026-10-07T21-48-52-494Z.md
new file mode 100644
index 0000000..eb11302
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-07T21-48-52-494Z.md
@@ -0,0 +1,280 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T21:47:46.482Z
+Длительность: 66.0с
+
+**Итог:** 12 ✓ / 4 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2621мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2650мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 7605мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791409666481 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791409666481 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 987мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 463мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2719мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 6b82efab… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток ddf4f91d… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 6181a002… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 9d801d60… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 04ba52e4… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5296мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914096 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914096 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914096 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 23375мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✗ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 2057мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✗ ожид=409 факт=204 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+
+## ✗ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 5294мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✗ ожид=28450 факт=20000 |
+| api | Продажи картой в остатке эквайринга | ✗ ожид=1150 факт=0 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3140мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 4968мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+
+## ✗ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1176мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✗ ожид=28950 факт=20000 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✗ ожид=1150 факт=0 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✗ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 2821мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✗ ожид=28950 факт=20000 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✗ ожид=1150 факт=0 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✗ ожид=3700 факт=3000 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 838мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 12
+- Failed: 4
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+### CRITICAL
+
+- **[08] Расход больше остатка кассы прошёл (касса в минус)**
+ - post=204
+- **[09] Движения смены не попали в остаток кассы**
+ - ожид=28450 факт=20000
+- **[12] Остаток счёта Касса ≠ независимой формуле**
+ - ожид=28950 факт=20000
+- **[12] Остаток счёта Эквайринг ≠ независимой формуле**
+ - ожид=1150 факт=0
+- **[12] Остаток счёта Касса-2 ≠ независимой формуле**
+ - ожид=3700 факт=3000
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-07T21-54-37-164Z.md b/tests/e2e/reports/full-chain-2026-10-07T21-54-37-164Z.md
new file mode 100644
index 0000000..3837a74
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-07T21-54-37-164Z.md
@@ -0,0 +1,269 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T21:53:12.764Z
+Длительность: 84.4с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 4634мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 4376мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 8913мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791409992760 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791409992760 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1332мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 925мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 3439мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 04867538… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 82bf238b… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 034e6fc7… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток f91ab464… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 5b6ca78e… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5704мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914099 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914099 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914099 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 23653мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 2582мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 8059мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 4248мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 9128мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1875мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 4141мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 1384мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-08T05-02-22-839Z.md b/tests/e2e/reports/full-chain-2026-10-08T05-02-22-839Z.md
new file mode 100644
index 0000000..0b71a34
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-08T05-02-22-839Z.md
@@ -0,0 +1,305 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-08T05:00:48.729Z
+Длительность: 94.1с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 5778мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| ui | Кабинет владельца открылся без ошибок (0 console/5xx/тостов) | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 6037мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+| ui | Экран «Каталог: 5 товаров с ценами и штрихкодами»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Карточка товара: цена продажи и штрихкод»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Справочник контрагентов: поставщик (БИН, телефон)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 10873мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791435648725 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791435648725 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| ui | Кассир: в меню нет модуля «Деньги» (счета/платежи/долги) | ✓ ожид=нет факт=нет |
+| ui | Кассир: в меню есть своя касса (/money/shifts) | ✓ ожид=есть факт=есть |
+| ui | Кассир: в меню нет «Настройки» | ✓ ожид=нет /settings факт=нет |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+| ui | Экран «Сотрудники: кассир, кладовщик, администратор (роли)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Точки продаж (2 кассы)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 2022мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+| ui | Экран «Счета: касса, банк (номер), эквайринг — начальные остатки»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 1567мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+| ui | Экран «Долги поставщикам: начальный долг 100 000 ₸»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 5431мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 77dd1a1f… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 64220f32… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 0dc70a6e… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 2393672c… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 7e7e642d… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+| ui | Экран «Приёмка №1: форма создания (до проведения)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Список приёмок»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №1: проведена, строки и себестоимость»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 6885мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914356 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914356 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914356 +9 | ✓ ожид=9 факт=9 |
+| ui | Экран «Загруженные накладные (табличная разобрана)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №2: «Поставщик не указан», проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 21436мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+| ui | Экран «Фото-накладная: распознана (OCR) и сопоставлена вручную»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №3 (по фото): проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 3521мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+| ui | Экран «Платежи поставщикам: нал из кассы + с банка»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Долги поставщикам после оплат (= формуле)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 8178мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+| ui | Экран «Смены кассы: открытие/закрытие, размен»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Закрытая смена: должно быть / факт / разница (Z-отчёт)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Чеки продаж (наличные/карта/смешанная) и возврат»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3485мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+| ui | Экран «Параллельные смены на точках 1 и 2 (деньги раздельны)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 8670мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+| ui | Экран «Оприходование излишка (+8)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Списание брака (−2)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Инвентаризация (часть товаров): расхождения»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Остатки после складских операций»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 4659мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| ui | Экран «Отчёт: продажи за день (выручка)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: прибыль (выручка − себестоимость)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: остатки на дату»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт «Деньги»: остатки по счетам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: долги поставщикам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3162мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179143 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179143 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179143 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179143 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179143 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+| ui | Экран «Движения склада (остаток ≡ Σ движений)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 1441мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+| ui | Экран «Отмена платежа → долг вернулся»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 958мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Финальный дашборд без ошибок | ✓ ожид=0 ошибок факт=0 ошибок |
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-08T13-22-29-575Z.md b/tests/e2e/reports/full-chain-2026-10-08T13-22-29-575Z.md
new file mode 100644
index 0000000..be6b97e
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-08T13-22-29-575Z.md
@@ -0,0 +1,305 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-08T13:20:58.455Z
+Длительность: 91.1с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 4886мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| ui | Кабинет владельца открылся без ошибок (0 console/5xx/тостов) | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 5602мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+| ui | Экран «Каталог: 5 товаров с ценами и штрихкодами»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Карточка товара: цена продажи и штрихкод»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Справочник контрагентов: поставщик (БИН, телефон)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 10046мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791465658454 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791465658454 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| ui | Кассир: в меню нет модуля «Деньги» (счета/платежи/долги) | ✓ ожид=нет факт=нет |
+| ui | Кассир: в меню есть своя касса (/money/shifts) | ✓ ожид=есть факт=есть |
+| ui | Кассир: в меню нет «Настройки» | ✓ ожид=нет /settings факт=нет |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+| ui | Экран «Сотрудники: кассир, кладовщик, администратор (роли)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Точки продаж (2 кассы)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1855мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+| ui | Экран «Счета: касса, банк (номер), эквайринг — начальные остатки»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 1391мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+| ui | Экран «Долги поставщикам: начальный долг 100 000 ₸»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 5515мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток c40fb2ef… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 141907d6… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 5e27fd59… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток d1707685… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 694a444f… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+| ui | Экран «Приёмка №1: форма создания (до проведения)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Список приёмок»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №1: проведена, строки и себестоимость»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 6704мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914656 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914656 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914656 +9 | ✓ ожид=9 факт=9 |
+| ui | Экран «Загруженные накладные (табличная разобрана)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №2: «Поставщик не указан», проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 21764мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+| ui | Экран «Фото-накладная: распознана (OCR) и сопоставлена вручную»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №3 (по фото): проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 3541мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+| ui | Экран «Платежи поставщикам: нал из кассы + с банка»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Долги поставщикам после оплат (= формуле)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 7957мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+| ui | Экран «Смены кассы: открытие/закрытие, размен»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Закрытая смена: должно быть / факт / разница (Z-отчёт)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Чеки продаж (наличные/карта/смешанная) и возврат»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3327мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+| ui | Экран «Параллельные смены на точках 1 и 2 (деньги раздельны)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 8352мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+| ui | Экран «Оприходование излишка (+8)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Списание брака (−2)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Инвентаризация (часть товаров): расхождения»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Остатки после складских операций»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 4617мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| ui | Экран «Отчёт: продажи за день (выручка)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: прибыль (выручка − себестоимость)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: остатки на дату»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт «Деньги»: остатки по счетам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: долги поставщикам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3090мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179146 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179146 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179146 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179146 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179146 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+| ui | Экран «Движения склада (остаток ≡ Σ движений)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 1500мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+| ui | Экран «Отмена платежа → долг вернулся»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 968мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Финальный дашборд без ошибок | ✓ ожид=0 ошибок факт=0 ошибок |
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-08T15-44-00-213Z.md b/tests/e2e/reports/full-chain-2026-10-08T15-44-00-213Z.md
new file mode 100644
index 0000000..07e7b40
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-08T15-44-00-213Z.md
@@ -0,0 +1,312 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-08T15:42:26.250Z
+Длительность: 94.0с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 5379мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| ui | Кабинет владельца открылся без ошибок (0 console/5xx/тостов) | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 5311мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+| ui | Экран «Каталог: 5 товаров с ценами и штрихкодами»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Карточка товара: цена продажи и штрихкод»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Справочник контрагентов: поставщик (БИН, телефон)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 11136мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791474146246 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791474146246 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| ui | Кассир: в меню нет модуля «Деньги» (счета/платежи/долги) | ✓ ожид=нет факт=нет |
+| ui | Кассир: в меню есть своя касса (/money/shifts) | ✓ ожид=есть факт=есть |
+| ui | Кассир: в меню нет «Настройки» | ✓ ожид=нет /settings факт=нет |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+| ui | Экран «Сотрудники: кассир, кладовщик, администратор (роли)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Точки продаж (2 кассы)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 2322мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+| ui | Экран «Счета: касса, банк (номер), эквайринг — начальные остатки»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 1416мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+| ui | Экран «Долги поставщикам: начальный долг 100 000 ₸»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 5513мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 07b0f8f2… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 85c5df41… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 3a92b534… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 14a6ac60… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 83273433… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+| ui | Экран «Приёмка №1: форма создания (до проведения)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Список приёмок»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №1: проведена, строки и себестоимость»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 6622мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914741 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914741 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914741 +9 | ✓ ожид=9 факт=9 |
+| ui | Экран «Загруженные накладные (табличная разобрана)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №2: «Поставщик не указан», проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 21655мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+| ui | Экран «Фото-накладная: распознана (OCR) и сопоставлена вручную»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №3 (по фото): проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 3639мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+| ui | Экран «Платежи поставщикам: нал из кассы + с банка»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Долги поставщикам после оплат (= формуле)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 8204мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+| ui | Экран «Смены кассы: открытие/закрытие, размен»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Закрытая смена: должно быть / факт / разница (Z-отчёт)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Чеки продаж (наличные/карта/смешанная) и возврат»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3484мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+| ui | Экран «Параллельные смены на точках 1 и 2 (деньги раздельны)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 8710мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+| api | Инвентаризация завершена (Completed) | ✓ ожид=204 факт=204 |
+| api | После завершения остаток НЕ изменился | ✓ ожид=40.5 факт=40.5 |
+| api | Создано оприходование излишков | ✓ ожид=200+enterId факт=200 |
+| api | В инвентаризации виден связанный документ | ✓ ожид=true факт=true |
+| api | Оприходование проведено | ✓ ожид=204 факт=204 |
+| api | Излишек применён оприходованием (+3) | ✓ ожид=3 факт=3 |
+| api | Оприходование «на основании инвентаризации №…» | ✓ ожид=инв.№ факт=И-2026-000003 |
+| ui | Экран «Оприходование излишка (+8)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Списание брака (−2)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Инвентаризация (часть товаров): расхождения»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Остатки после складских операций»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 4760мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| ui | Экран «Отчёт: продажи за день (выручка)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: прибыль (выручка − себестоимость)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: остатки на дату»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт «Деньги»: остатки по счетам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: долги поставщикам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3249мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179147 | ✓ ожид=43.5 факт=43.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179147 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179147 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179147 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179147 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+| ui | Экран «Движения склада (остаток ≡ Σ движений)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 1504мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+| ui | Экран «Отмена платежа → долг вернулся»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1056мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Финальный дашборд без ошибок | ✓ ожид=0 ошибок факт=0 ошибок |
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-08T20-28-47-547Z.md b/tests/e2e/reports/full-chain-2026-10-08T20-28-47-547Z.md
new file mode 100644
index 0000000..778cef7
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-08T20-28-47-547Z.md
@@ -0,0 +1,283 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-08T20:27:42.485Z
+Длительность: 65.1с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2496мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2224мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 7486мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791491262483 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791491262483 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1211мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 841мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2880мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 2c431ed6… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 1b17444d… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток d69bed51… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 39be51c4… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 3aa12e64… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5762мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914912 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914912 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914912 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 19934мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 2153мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 6018мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2848мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 7138мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+| api | Инвентаризация завершена (Completed) | ✓ ожид=204 факт=204 |
+| api | После завершения остаток НЕ изменился | ✓ ожид=40.5 факт=40.5 |
+| api | Создано оприходование излишков | ✓ ожид=200+enterId факт=200 |
+| api | В инвентаризации виден связанный документ | ✓ ожид=true факт=true |
+| api | Оприходование проведено | ✓ ожид=204 факт=204 |
+| api | Излишек применён оприходованием (+3) | ✓ ожид=3 факт=3 |
+| api | Оприходование «на основании инвентаризации №…» | ✓ ожид=инв.№ факт=И-2026-000003 |
+| api | unpost при проведённом связанном → 409 (не удаляет) | ✓ ожид=409 факт=409 |
+| api | Отмена результатов (cancel-results) → 200 | ✓ ожид=200 факт=200 |
+| api | После отмены результатов остаток вернулся | ✓ ожид=40.5 факт=40.5 |
+| api | Оприходование НЕ удалено, стало черновиком | ✓ ожид=draft факт=200/0 |
+| api | Связанный документ остался (черновик) | ✓ ожид=true факт=true |
+| api | Повторное проведение оприходования | ✓ ожид=204 факт=204 |
+| api | После повторного проведения остаток снова = факт (+3) | ✓ ожид=3 факт=3 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1031мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 2343мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179149 | ✓ ожид=43.5 факт=43.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179149 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179149 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179149 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179149 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 691мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-09T02-32-35-066Z.md b/tests/e2e/reports/full-chain-2026-10-09T02-32-35-066Z.md
new file mode 100644
index 0000000..7100179
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-09T02-32-35-066Z.md
@@ -0,0 +1,285 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-09T02:31:28.439Z
+Длительность: 66.6с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2579мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2727мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 7284мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791513088437 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791513088437 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1261мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 688мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 3094мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 320cbae3… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 70b1d7d1… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток c8952930… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 2426489b… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 66127d8b… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5196мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17915130 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17915130 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17915130 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 19951мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 2053мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 6434мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | После продажи в минус появилось предупреждение | ✓ ожид=>=1 факт=1 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Z-отчёт: разбивка по товарам (byProduct) | ✓ ожид=>0 факт=3 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без смены → автооткрытие смены | ✓ ожид=204 факт=204 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2680мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 8336мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+| api | Инвентаризация завершена (Completed) | ✓ ожид=204 факт=204 |
+| api | После завершения остаток НЕ изменился | ✓ ожид=40.5 факт=40.5 |
+| api | Создано оприходование излишков | ✓ ожид=200+enterId факт=200 |
+| api | В инвентаризации виден связанный документ | ✓ ожид=true факт=true |
+| api | Оприходование проведено | ✓ ожид=204 факт=204 |
+| api | Излишек применён оприходованием (+3) | ✓ ожид=3 факт=3 |
+| api | Оприходование «на основании инвентаризации №…» | ✓ ожид=инв.№ факт=И-2026-000003 |
+| api | unpost при проведённом связанном → 409 (не удаляет) | ✓ ожид=409 факт=409 |
+| api | Отмена результатов (cancel-results) → 200 | ✓ ожид=200 факт=200 |
+| api | После отмены результатов остаток вернулся | ✓ ожид=40.5 факт=40.5 |
+| api | Оприходование НЕ удалено, стало черновиком | ✓ ожид=draft факт=200/0 |
+| api | Связанный документ остался (черновик) | ✓ ожид=true факт=true |
+| api | Повторное проведение оприходования | ✓ ожид=204 факт=204 |
+| api | После повторного проведения остаток снова = факт (+3) | ✓ ожид=3 факт=3 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1056мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=4000 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=4000 факт=4000 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=4000 факт=4000 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 2298мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179151 | ✓ ожид=43.5 факт=43.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179151 | ✓ ожид=56 факт=56 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179151 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179151 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179151 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 984мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 2мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-09T05-21-47-078Z.md b/tests/e2e/reports/full-chain-2026-10-09T05-21-47-078Z.md
new file mode 100644
index 0000000..07c1618
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-09T05-21-47-078Z.md
@@ -0,0 +1,282 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-09T05:20:36.351Z
+Длительность: 70.7с
+
+**Итог:** 12 ✓ / 4 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 4776мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 4355мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 8187мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791523236350 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791523236350 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1309мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 756мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✗ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 3480мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 64df7151… +12.5 | ✗ ожид=12.5 факт=0 |
+| api | Остаток f0f839c9… +25 | ✗ ожид=25 факт=0 |
+| api | Остаток fe1be28a… +30 | ✗ ожид=30 факт=0 |
+| api | Остаток 214e4381… +35 | ✗ ожид=35 факт=0 |
+| api | Остаток 851ac7fb… +40 | ✗ ожид=40 факт=0 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✗ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5315мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17915232 +7 | ✗ ожид=7 факт=0 |
+| api | Остаток Товар 2 fc17915232 +4 | ✗ ожид=4 факт=0 |
+| api | Остаток Товар 3 fc17915232 +9 | ✗ ожид=9 факт=0 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 20124мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 2339мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 6514мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | После продажи в минус появилось предупреждение | ✓ ожид=>=1 факт=1 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Z-отчёт: разбивка по товарам (byProduct) | ✓ ожид=>0 факт=3 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без смены → автооткрытие смены | ✓ ожид=204 факт=204 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2757мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✗ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 6382мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=0 факт=0 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✗ ожид=-1 факт=0 |
+| api | Оприходование излишка (+8) | ✗ ожид=8 факт=0 |
+| api | Списание брака (−2) | ✗ ожид=2 факт=0 |
+| api | Импорт инвентаризации нашёл 2 товара | ✗ ожид=2 факт=0 |
+| api | Инвентаризация (частичная) создана | ✗ ожид=200+id факт=400 |
+| api | Инвентаризация завершена (Completed) | ✓ ожид=204 факт=204 |
+| api | После завершения остаток НЕ изменился | ✓ ожид=0 факт=0 |
+| api | Создано оприходование излишков | ✗ ожид=200+enterId факт=400 |
+| api | В инвентаризации виден связанный документ | ✗ ожид=true факт=false |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1021мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=4000 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=4000 факт=4000 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=4000 факт=4000 |
+
+## ✗ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 2477мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179152 | ✗ ожид=41.5 факт=0 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179152 | ✗ ожид=56 факт=0 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179152 | ✗ ожид=54 факт=0 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179152 | ✗ ожид=43 факт=0 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179152 | ✗ ожид=38 факт=0 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 931мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 12
+- Failed: 4
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+### CRITICAL
+
+- **[12] Остаток ≠ сумме движений склада**
+ - см. строки шага
+
+### HIGH
+
+- **[05] Остатки не выросли на количество приёмки**
+ - supply=fc4e0c87-0c9e-4c83-8cc7-76e86b8fb97d
+- **[06] Остатки после приёмки №2 не совпали**
+ - supply=22a8eb2c-50bb-42be-9ed3-78f1740aa228
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-09T05-23-34-327Z.md b/tests/e2e/reports/full-chain-2026-10-09T05-23-34-327Z.md
new file mode 100644
index 0000000..404117a
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-09T05-23-34-327Z.md
@@ -0,0 +1,285 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-09T05:22:39.032Z
+Длительность: 55.3с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 1815мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 1869мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 6426мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791523359030 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791523359030 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 814мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 381мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2306мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 34a7a0a2… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 2c8be8bf… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток da57d45d… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 87f7fda1… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток a5d5bfa5… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5153мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17915233 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17915233 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17915233 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 16945мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1437мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 4840мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | После продажи в минус появилось предупреждение | ✓ ожид=>=1 факт=1 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Z-отчёт: разбивка по товарам (byProduct) | ✓ ожид=>0 факт=3 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без смены → автооткрытие смены | ✓ ожид=204 факт=204 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2642мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 6721мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+| api | Инвентаризация завершена (Completed) | ✓ ожид=204 факт=204 |
+| api | После завершения остаток НЕ изменился | ✓ ожид=40.5 факт=40.5 |
+| api | Создано оприходование излишков | ✓ ожид=200+enterId факт=200 |
+| api | В инвентаризации виден связанный документ | ✓ ожид=true факт=true |
+| api | Оприходование проведено | ✓ ожид=204 факт=204 |
+| api | Излишек применён оприходованием (+3) | ✓ ожид=3 факт=3 |
+| api | Оприходование «на основании инвентаризации №…» | ✓ ожид=инв.№ факт=И-2026-000003 |
+| api | unpost при проведённом связанном → 409 (не удаляет) | ✓ ожид=409 факт=409 |
+| api | Отмена результатов (cancel-results) → 200 | ✓ ожид=200 факт=200 |
+| api | После отмены результатов остаток вернулся | ✓ ожид=40.5 факт=40.5 |
+| api | Оприходование НЕ удалено, стало черновиком | ✓ ожид=draft факт=200/0 |
+| api | Связанный документ остался (черновик) | ✓ ожид=true факт=true |
+| api | Повторное проведение оприходования | ✓ ожид=204 факт=204 |
+| api | После повторного проведения остаток снова = факт (+3) | ✓ ожид=3 факт=3 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 899мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=4000 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=4000 факт=4000 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=4000 факт=4000 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 2153мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179152 | ✓ ожид=43.5 факт=43.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179152 | ✓ ожид=56 факт=56 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179152 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179152 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179152 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 887мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-09T05-39-00-855Z.md b/tests/e2e/reports/full-chain-2026-10-09T05-39-00-855Z.md
new file mode 100644
index 0000000..babfd2d
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-09T05-39-00-855Z.md
@@ -0,0 +1,285 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-09T05:38:01.732Z
+Длительность: 59.1с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2451мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2190мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 6704мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791524281730 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791524281730 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 906мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 423мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2431мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 55e93eb8… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток ac63b7c4… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток c30c9385… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток b081da76… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 43a52782… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 4884мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17915242 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17915242 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17915242 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 19904мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1390мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 4746мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | После продажи в минус появилось предупреждение | ✓ ожид=>=1 факт=1 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Z-отчёт: разбивка по товарам (byProduct) | ✓ ожид=>0 факт=3 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без смены → автооткрытие смены | ✓ ожид=204 факт=204 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2708мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 6294мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+| api | Инвентаризация завершена (Completed) | ✓ ожид=204 факт=204 |
+| api | После завершения остаток НЕ изменился | ✓ ожид=40.5 факт=40.5 |
+| api | Создано оприходование излишков | ✓ ожид=200+enterId факт=200 |
+| api | В инвентаризации виден связанный документ | ✓ ожид=true факт=true |
+| api | Оприходование проведено | ✓ ожид=204 факт=204 |
+| api | Излишек применён оприходованием (+3) | ✓ ожид=3 факт=3 |
+| api | Оприходование «на основании инвентаризации №…» | ✓ ожид=инв.№ факт=И-2026-000003 |
+| api | unpost при проведённом связанном → 409 (не удаляет) | ✓ ожид=409 факт=409 |
+| api | Отмена результатов (cancel-results) → 200 | ✓ ожид=200 факт=200 |
+| api | После отмены результатов остаток вернулся | ✓ ожид=40.5 факт=40.5 |
+| api | Оприходование НЕ удалено, стало черновиком | ✓ ожид=draft факт=200/0 |
+| api | Связанный документ остался (черновик) | ✓ ожид=true факт=true |
+| api | Повторное проведение оприходования | ✓ ожид=204 факт=204 |
+| api | После повторного проведения остаток снова = факт (+3) | ✓ ожид=3 факт=3 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 842мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=4000 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=4000 факт=4000 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=4000 факт=4000 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 2235мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179152 | ✓ ожид=43.5 факт=43.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179152 | ✓ ожид=56 факт=56 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179152 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179152 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179152 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 1011мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-2026-10-09T06-24-27-925Z.md b/tests/e2e/reports/full-chain-2026-10-09T06-24-27-925Z.md
new file mode 100644
index 0000000..97e4718
--- /dev/null
+++ b/tests/e2e/reports/full-chain-2026-10-09T06-24-27-925Z.md
@@ -0,0 +1,285 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-09T06:23:18.925Z
+Длительность: 69.0с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2549мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2412мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 7959мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791526998918 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791526998918 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1271мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 821мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 3334мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 8db5fd64… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 878b7af1… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 4b8131d1… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 70ac094f… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 0081b920… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5266мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17915269 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17915269 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17915269 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 20155мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 2273мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 6971мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | После продажи в минус появилось предупреждение | ✓ ожид=>=1 факт=1 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Z-отчёт: разбивка по товарам (byProduct) | ✓ ожид=>0 факт=3 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без смены → автооткрытие смены | ✓ ожид=204 факт=204 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2584мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 8983мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+| api | Инвентаризация завершена (Completed) | ✓ ожид=204 факт=204 |
+| api | После завершения остаток НЕ изменился | ✓ ожид=40.5 факт=40.5 |
+| api | Создано оприходование излишков | ✓ ожид=200+enterId факт=200 |
+| api | В инвентаризации виден связанный документ | ✓ ожид=true факт=true |
+| api | Оприходование проведено | ✓ ожид=204 факт=204 |
+| api | Излишек применён оприходованием (+3) | ✓ ожид=3 факт=3 |
+| api | Оприходование «на основании инвентаризации №…» | ✓ ожид=инв.№ факт=И-2026-000003 |
+| api | unpost при проведённом связанном → 409 (не удаляет) | ✓ ожид=409 факт=409 |
+| api | Отмена результатов (cancel-results) → 200 | ✓ ожид=200 факт=200 |
+| api | После отмены результатов остаток вернулся | ✓ ожид=40.5 факт=40.5 |
+| api | Оприходование НЕ удалено, стало черновиком | ✓ ожид=draft факт=200/0 |
+| api | Связанный документ остался (черновик) | ✓ ожид=true факт=true |
+| api | Повторное проведение оприходования | ✓ ожид=204 факт=204 |
+| api | После повторного проведения остаток снова = факт (+3) | ✓ ожид=3 факт=3 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 979мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=4000 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=4000 факт=4000 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=4000 факт=4000 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 2461мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179152 | ✓ ожид=43.5 факт=43.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179152 | ✓ ожид=56 факт=56 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179152 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179152 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179152 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 978мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636.md b/tests/e2e/reports/full-chain-demo-20261008-010636.md
new file mode 100644
index 0000000..63f6221
--- /dev/null
+++ b/tests/e2e/reports/full-chain-demo-20261008-010636.md
@@ -0,0 +1,481 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:06:43.067Z
+Длительность: 119.0с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 5107мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вход demo-admin (режим B) | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| ui | Кабинет владельца открылся без ошибок (0 console/5xx/тостов) | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Вход владельца → дашборд](full-chain-demo-20261008-010636/screenshots/01-vhod-dashboard.png)
+
+
+
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 5709мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Выбрано реальных товаров каталога (≥5, штрихкод+цена) | ✓ ожид=≥5 факт=12 |
+| api | Среди выбранных есть весовой (информативно) | ✓ ожид=≥0 факт=0 |
+| api | Поставщик [e2e] создан | ✓ ожид=200+id факт=201 |
+| ui | Экран «Каталог «Демо-магазина»: реальные товары»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Поставщик [e2e]»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Каталог «Демо-магазина»: реальные товары](full-chain-demo-20261008-010636/screenshots/02-tovary-realnye.png)
+
+
+
+[Поставщик [e2e]](full-chain-demo-20261008-010636/screenshots/02-postavshchik.png)
+
+![Поставщик [e2e]](full-chain-demo-20261008-010636/screenshots/02-postavshchik.png)
+
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 8377мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 (e2e) 1791403603066 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 (e2e) 1791403603066 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| ui | Экран «Сотрудники: кассир, кладовщик, администратор (роли)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Точки продаж (2 кассы)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Сотрудники: кассир, кладовщик, администратор (роли)](full-chain-demo-20261008-010636/screenshots/02a-sotrudniki.png)
+
+
+
+[Точки продаж (2 кассы)](full-chain-demo-20261008-010636/screenshots/02a-tochki-prodazh.png)
+
+
+
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 2564мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+| ui | Экран «Счета: касса, банк (номер), эквайринг — начальные остатки»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Счета: касса, банк (номер), эквайринг — начальные остатки](full-chain-demo-20261008-010636/screenshots/03-scheta.png)
+
+
+
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 2068мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+| ui | Экран «Долги поставщикам: начальный долг 100 000 ₸»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Долги поставщикам: начальный долг 100 000 ₸](full-chain-demo-20261008-010636/screenshots/04-dolg-nachalnyy.png)
+
+
+
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 9501мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 0bd54f29… +20 | ✓ ожид=20 факт=20 |
+| api | Остаток 0cfad6a5… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток e6e79bf2… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток fbe7d065… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 3a92d8a7… +40 | ✓ ожид=40 факт=40 |
+| api | Остаток 9a6a59f8… +45 | ✓ ожид=45 факт=45 |
+| api | Остаток db59983d… +50 | ✓ ожид=50 факт=50 |
+| api | Остаток 66866675… +55 | ✓ ожид=55 факт=55 |
+| api | Остаток a6d3c6a1… +60 | ✓ ожид=60 факт=60 |
+| api | Остаток f75a5241… +65 | ✓ ожид=65 факт=65 |
+| api | Остаток 519251c8… +70 | ✓ ожид=70 факт=70 |
+| api | Остаток 89f82dd6… +75 | ✓ ожид=75 факт=75 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=900 факт=900 |
+| ui | Экран «Приёмка №1: форма создания (до проведения)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Список приёмок»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №1: проведена, строки и себестоимость»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Приёмка №1: форма создания (до проведения)](full-chain-demo-20261008-010636/screenshots/05-priemka1-forma.png)
+
+
+
+[Список приёмок](full-chain-demo-20261008-010636/screenshots/05-priemka1-spisok.png)
+
+
+
+[Приёмка №1: проведена, строки и себестоимость](full-chain-demo-20261008-010636/screenshots/05-priemka1-provedena.png)
+
+
+
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 8516мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток "BIOBLAS" шампунь +7 | ✓ ожид=7 факт=7 |
+| api | Остаток "BIOBLAS" шампунь +4 | ✓ ожид=4 факт=4 |
+| api | Остаток "BIOBLAS" шампунь +9 | ✓ ожид=9 факт=9 |
+| ui | Экран «Загруженные накладные (табличная разобрана)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №2: «Поставщик не указан», проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Загруженные накладные (табличная разобрана)](full-chain-demo-20261008-010636/screenshots/06-nakladnye-spisok.png)
+
+
+
+[Приёмка №2: «Поставщик не указан», проведена](full-chain-demo-20261008-010636/screenshots/06-priemka2-provedena.png)
+
+
+
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 25707мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Фото-накладная распознана (OCR, needs_review) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+| ui | Экран «Фото-накладная: распознана (OCR) и сопоставлена вручную»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №3 (по фото): проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Фото-накладная: распознана (OCR) и сопоставлена вручную](full-chain-demo-20261008-010636/screenshots/07-foto-nakladnaya-razobrana.png)
+
+
+
+[Приёмка №3 (по фото): проведена](full-chain-demo-20261008-010636/screenshots/07-priemka3-provedena.png)
+
+
+
+[Фото-приёмка с телефона (моб.)](full-chain-demo-20261008-010636/screenshots/07-mob-foto-priemka.png)
+
+
+
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 4651мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=148812 факт=148812 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=18390 факт=18390 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=349498 факт=349498 |
+| ui | Экран «Платежи поставщикам: нал из кассы + с банка»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Долги поставщикам после оплат (= формуле)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Платежи поставщикам: нал из кассы + с банка](full-chain-demo-20261008-010636/screenshots/08-platezhi.png)
+
+
+
+[Долги поставщикам после оплат (= формуле)](full-chain-demo-20261008-010636/screenshots/08-dolg-posle-oplat.png)
+
+
+
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 9860мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=14275 факт=14275 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=3775/14275 факт=3775/14275 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+| ui | Экран «Смены кассы: открытие/закрытие, размен»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Закрытая смена: должно быть / факт / разница (Z-отчёт)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Чеки продаж (наличные/карта/смешанная) и возврат»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Смены кассы: открытие/закрытие, размен](full-chain-demo-20261008-010636/screenshots/09-smeny-spisok.png)
+
+
+
+[Закрытая смена: должно быть / факт / разница (Z-отчёт)](full-chain-demo-20261008-010636/screenshots/09-smena-zakryta-z.png)
+
+
+
+[Чеки продаж (наличные/карта/смешанная) и возврат](full-chain-demo-20261008-010636/screenshots/09-cheki-prodazhi.png)
+
+
+
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 4205мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2500 факт=2500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=3550 факт=3550 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+| ui | Экран «Параллельные смены на точках 1 и 2 (деньги раздельны)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Параллельные смены на точках 1 и 2 (деньги раздельны)](full-chain-demo-20261008-010636/screenshots/09a-parallelnye-smeny.png)
+
+
+
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 10471мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=48 факт=48 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+| ui | Экран «Оприходование излишка (+8)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Списание брака (−2)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Инвентаризация (часть товаров): расхождения»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Остатки после складских операций»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Оприходование излишка (+8)](full-chain-demo-20261008-010636/screenshots/10-oprihodovanie.png)
+
+
+
+[Списание брака (−2)](full-chain-demo-20261008-010636/screenshots/10-spisanie-braka.png)
+
+
+
+[Инвентаризация (часть товаров): расхождения](full-chain-demo-20261008-010636/screenshots/10-inventarizaciya.png)
+
+
+
+[Остатки после складских операций](full-chain-demo-20261008-010636/screenshots/10-ostatki-sklad.png)
+
+
+
+[Инвентаризация с телефона (сканер) (моб.)](full-chain-demo-20261008-010636/screenshots/10-mob-inventarizaciya.png)
+
+
+
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 9412мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=7650 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=-98812 факт=-98812 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=181610 факт=181610 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по точкам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по кассирам доступен | ✓ ожид=200 факт=200 |
+| ui | Экран «Отчёт: продажи за день (выручка)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: прибыль (выручка − себестоимость)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: остатки на дату»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт «Деньги»: остатки по счетам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: долги поставщикам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отчёт: продажи за день (выручка)](full-chain-demo-20261008-010636/screenshots/11-otchet-prodazhi.png)
+
+
+
+[Отчёт: прибыль (выручка − себестоимость)](full-chain-demo-20261008-010636/screenshots/11-otchet-pribyl.png)
+
+
+
+[Отчёт: остатки на дату](full-chain-demo-20261008-010636/screenshots/11-otchet-ostatki.png)
+
+
+
+[Отчёт «Деньги»: остатки по счетам](full-chain-demo-20261008-010636/screenshots/11-otchet-dengi.png)
+
+
+
+[Отчёт: долги поставщикам](full-chain-demo-20261008-010636/screenshots/11-otchet-dolgi.png)
+
+
+
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 7084мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=48 факт=48 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: "IQ уроки" книги | ✓ ожид=38 факт=38 |
+| api | Инвариант остаток≡Σдвижений: "Ludwik" средств | ✓ ожид=45 факт=45 |
+| api | Инвариант остаток≡Σдвижений: "Ludwik" средств | ✓ ожид=50 факт=50 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=55 факт=55 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=60 факт=60 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=65 факт=65 |
+| api | Инвариант остаток≡Σдвижений: "Rice Day" GRANA | ✓ ожид=70 факт=70 |
+| api | Инвариант остаток≡Σдвижений: "Richmond" Gold | ✓ ожид=75 факт=75 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса (e2e) 1791 | ✓ ожид=-98812 факт=-98812 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 (e2e) 17 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк (e2e) 17914 | ✓ ожид=181610 факт=181610 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг (e2e) | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 (e2e | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=349498 факт=349498 |
+| api | Изоляция: режим B (демо) — проверка через temp-орг в режиме C | ✓ ожид=n/a факт=n/a |
+| ui | Экран «Движения склада (остаток ≡ Σ движений)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Движения склада (остаток ≡ Σ движений)](full-chain-demo-20261008-010636/screenshots/12-dvizheniya-sklada.png)
+
+
+
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 2491мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=498310 факт=498310 |
+| ui | Экран «Отмена платежа → долг вернулся»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отмена платежа → долг вернулся](full-chain-demo-20261008-010636/screenshots/13-otkat-dolg-vernulsya.png)
+
+
+
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 3230мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Финальный дашборд без ошибок | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Галерея index.html собрана (34 кадров) | ✓ ожид=index.html факт=34 |
+| api | Режим B: e2e-сотрудники деактивированы (не удалены) | ✓ ожид=3 факт=3 |
+
+Скриншоты процесса:
+
+[Итоговый дашборд](full-chain-demo-20261008-010636/screenshots/14-itog-dashboard.png)
+
+
+
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Галерея скриншотов: /home/nns/food-market/tests/e2e/reports/full-chain-demo-20261008-010636/index.html
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/index.html b/tests/e2e/reports/full-chain-demo-20261008-010636/index.html
new file mode 100644
index 0000000..41ebde5
--- /dev/null
+++ b/tests/e2e/reports/full-chain-demo-20261008-010636/index.html
@@ -0,0 +1,237 @@
+
+
+Full-chain e2e — скриншоты процессов (Демо-магазин (B))
+
+
+step01_register_and_login
+
+
+
+
+ 🖥 Вход владельца → дашборд организации01-vhod-dashboard.png
+
+step02_catalog_and_supplier
+
+
+
+
+ 🖥 Каталог «Демо-магазина»: реальные товары02-tovary-realnye.png
+
+
+
+
+
+ 🖥 Поставщик [e2e]02-postavshchik.png
+
+step02a_employees_and_points
+
+
+
+
+ 🖥 Сотрудники: кассир, кладовщик, администратор (роли)02a-sotrudniki.png
+
+
+
+
+
+ 🖥 Точки продаж (2 кассы)02a-tochki-prodazh.png
+
+step03_money_accounts
+
+
+
+
+ 🖥 Счета: касса, банк (номер), эквайринг — начальные остатки03-scheta.png
+
+step04_initial_supplier_debt
+
+
+
+
+ 🖥 Долги поставщикам: начальный долг 100 000 ₸04-dolg-nachalnyy.png
+
+step05_supply1_manual
+
+
+
+
+ 🖥 Приёмка №1: форма создания (до проведения)05-priemka1-forma.png
+
+
+
+
+
+ 🖥 Список приёмок05-priemka1-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №1: проведена, строки и себестоимость05-priemka1-provedena.png
+
+step06_supply2_excel
+
+
+
+
+ 🖥 Загруженные накладные (табличная разобрана)06-nakladnye-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №2: «Поставщик не указан», проведена06-priemka2-provedena.png
+
+step07_supply3_photo
+
+
+
+
+ 🖥 Фото-накладная: распознана (OCR) и сопоставлена вручную07-foto-nakladnaya-razobrana.png
+
+
+
+
+
+ 🖥 Приёмка №3 (по фото): проведена07-priemka3-provedena.png
+
+
+
+
+
+ 📱 Фото-приёмка с телефона07-mob-foto-priemka.png
+
+step08_supplier_payments
+
+
+
+
+ 🖥 Платежи поставщикам: нал из кассы + с банка08-platezhi.png
+
+
+
+
+
+ 🖥 Долги поставщикам после оплат (= формуле)08-dolg-posle-oplat.png
+
+step09_cashier_shift
+
+
+
+
+ 🖥 Смены кассы: открытие/закрытие, размен09-smeny-spisok.png
+
+
+
+
+
+ 🖥 Закрытая смена: должно быть / факт / разница (Z-отчёт)09-smena-zakryta-z.png
+
+
+
+
+
+ 🖥 Чеки продаж (наличные/карта/смешанная) и возврат09-cheki-prodazhi.png
+
+step09a_points_binding
+
+
+
+
+ 🖥 Параллельные смены на точках 1 и 2 (деньги раздельны)09a-parallelnye-smeny.png
+
+step10_warehouse_ops
+
+
+
+
+ 🖥 Оприходование излишка (+8)10-oprihodovanie.png
+
+
+
+
+
+ 🖥 Списание брака (−2)10-spisanie-braka.png
+
+
+
+
+
+ 🖥 Инвентаризация (часть товаров): расхождения10-inventarizaciya.png
+
+
+
+
+
+ 🖥 Остатки после складских операций10-ostatki-sklad.png
+
+
+
+
+
+ 📱 Инвентаризация с телефона (сканер)10-mob-inventarizaciya.png
+
+step11_reports
+
+
+
+
+ 🖥 Отчёт: продажи за день (выручка)11-otchet-prodazhi.png
+
+
+
+
+
+ 🖥 Отчёт: прибыль (выручка − себестоимость)11-otchet-pribyl.png
+
+
+
+
+
+ 🖥 Отчёт: остатки на дату11-otchet-ostatki.png
+
+
+
+
+
+ 🖥 Отчёт «Деньги»: остатки по счетам11-otchet-dengi.png
+
+
+
+
+
+ 🖥 Отчёт: долги поставщикам11-otchet-dolgi.png
+
+step12_invariants
+
+
+
+
+ 🖥 Движения склада (остаток ≡ Σ движений)12-dvizheniya-sklada.png
+
+step13_cancel_rollback
+
+
+
+
+ 🖥 Отмена платежа → долг вернулся13-otkat-dolg-vernulsya.png
+
+step14_finalize
+
+
+
+
+ 🖥 Итоговый дашборд магазина после полного дня14-itog-dashboard.png
+
+
\ No newline at end of file
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/01-vhod-dashboard.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/01-vhod-dashboard.png
new file mode 100644
index 0000000..91e50bc
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/01-vhod-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/02-postavshchik.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/02-postavshchik.png
new file mode 100644
index 0000000..14c15b7
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/02-postavshchik.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/02-tovary-realnye.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/02-tovary-realnye.png
new file mode 100644
index 0000000..340009a
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/02-tovary-realnye.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/02a-sotrudniki.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/02a-sotrudniki.png
new file mode 100644
index 0000000..c93da3f
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/02a-sotrudniki.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/02a-tochki-prodazh.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/02a-tochki-prodazh.png
new file mode 100644
index 0000000..4cfe8e4
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/02a-tochki-prodazh.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/03-scheta.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/03-scheta.png
new file mode 100644
index 0000000..bfea531
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/03-scheta.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/04-dolg-nachalnyy.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/04-dolg-nachalnyy.png
new file mode 100644
index 0000000..03373d7
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/04-dolg-nachalnyy.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/05-priemka1-forma.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/05-priemka1-forma.png
new file mode 100644
index 0000000..a614adb
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/05-priemka1-forma.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/05-priemka1-provedena.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/05-priemka1-provedena.png
new file mode 100644
index 0000000..624d35a
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/05-priemka1-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/05-priemka1-spisok.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/05-priemka1-spisok.png
new file mode 100644
index 0000000..13343b6
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/05-priemka1-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/06-nakladnye-spisok.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/06-nakladnye-spisok.png
new file mode 100644
index 0000000..90aa2ad
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/06-nakladnye-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/06-priemka2-provedena.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/06-priemka2-provedena.png
new file mode 100644
index 0000000..4385924
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/06-priemka2-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/07-foto-nakladnaya-razobrana.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/07-foto-nakladnaya-razobrana.png
new file mode 100644
index 0000000..3d83dce
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/07-foto-nakladnaya-razobrana.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/07-mob-foto-priemka.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/07-mob-foto-priemka.png
new file mode 100644
index 0000000..f490d39
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/07-mob-foto-priemka.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/07-priemka3-provedena.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/07-priemka3-provedena.png
new file mode 100644
index 0000000..ce5e21b
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/07-priemka3-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/08-dolg-posle-oplat.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/08-dolg-posle-oplat.png
new file mode 100644
index 0000000..51b2be7
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/08-dolg-posle-oplat.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/08-platezhi.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/08-platezhi.png
new file mode 100644
index 0000000..2349214
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/08-platezhi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/09-cheki-prodazhi.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/09-cheki-prodazhi.png
new file mode 100644
index 0000000..9763e7e
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/09-cheki-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/09-smena-zakryta-z.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/09-smena-zakryta-z.png
new file mode 100644
index 0000000..94ecee8
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/09-smena-zakryta-z.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/09-smeny-spisok.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/09-smeny-spisok.png
new file mode 100644
index 0000000..7fa0347
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/09-smeny-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/09a-parallelnye-smeny.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/09a-parallelnye-smeny.png
new file mode 100644
index 0000000..acb04fa
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/09a-parallelnye-smeny.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-inventarizaciya.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-inventarizaciya.png
new file mode 100644
index 0000000..7e044db
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-mob-inventarizaciya.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-mob-inventarizaciya.png
new file mode 100644
index 0000000..f2528cd
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-mob-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-oprihodovanie.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-oprihodovanie.png
new file mode 100644
index 0000000..10ffece
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-oprihodovanie.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-ostatki-sklad.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-ostatki-sklad.png
new file mode 100644
index 0000000..0184e2d
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-ostatki-sklad.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-spisanie-braka.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-spisanie-braka.png
new file mode 100644
index 0000000..a307e31
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/10-spisanie-braka.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-dengi.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-dengi.png
new file mode 100644
index 0000000..091797c
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-dengi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-dolgi.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-dolgi.png
new file mode 100644
index 0000000..51b2be7
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-dolgi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-ostatki.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-ostatki.png
new file mode 100644
index 0000000..55ac013
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-ostatki.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-pribyl.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-pribyl.png
new file mode 100644
index 0000000..fedb95c
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-pribyl.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-prodazhi.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-prodazhi.png
new file mode 100644
index 0000000..ba36271
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/11-otchet-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/12-dvizheniya-sklada.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/12-dvizheniya-sklada.png
new file mode 100644
index 0000000..d53c67e
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/12-dvizheniya-sklada.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/13-otkat-dolg-vernulsya.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/13-otkat-dolg-vernulsya.png
new file mode 100644
index 0000000..51b2be7
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/13-otkat-dolg-vernulsya.png differ
diff --git a/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/14-itog-dashboard.png b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/14-itog-dashboard.png
new file mode 100644
index 0000000..0c638c9
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-20261008-010636/screenshots/14-itog-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158.md b/tests/e2e/reports/full-chain-demo-final-20261008-013158.md
new file mode 100644
index 0000000..6df2556
--- /dev/null
+++ b/tests/e2e/reports/full-chain-demo-final-20261008-013158.md
@@ -0,0 +1,500 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:32:02.141Z
+Длительность: 141.3с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 4850мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вход demo-admin (режим B) | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| ui | Кабинет владельца открылся без ошибок (0 console/5xx/тостов) | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Вход владельца → дашборд](full-chain-demo-final-20261008-013158/screenshots/01-vhod-dashboard.png)
+
+
+
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 5195мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Выбрано реальных товаров каталога (≥5, штрихкод+цена) | ✓ ожид=≥5 факт=12 |
+| api | Среди выбранных есть весовой (информативно) | ✓ ожид=≥0 факт=0 |
+| api | Поставщик [e2e] создан | ✓ ожид=200+id факт=201 |
+| ui | Экран «Каталог «Демо-магазина»: реальные товары»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Поставщик [e2e]»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Каталог «Демо-магазина»: реальные товары](full-chain-demo-final-20261008-013158/screenshots/02-tovary-realnye.png)
+
+
+
+[Поставщик [e2e]](full-chain-demo-final-20261008-013158/screenshots/02-postavshchik.png)
+
+![Поставщик [e2e]](full-chain-demo-final-20261008-013158/screenshots/02-postavshchik.png)
+
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 18827мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 (e2e) 1791405122140 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 (e2e) 1791405122140 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| ui | Кассир: в меню нет модуля «Деньги» (счета/платежи/долги) | ✓ ожид=нет факт=нет |
+| ui | Кассир: в меню есть своя касса (/money/shifts) | ✓ ожид=есть факт=есть |
+| ui | Кассир: в меню нет «Настройки» | ✓ ожид=нет /settings факт=нет |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+| ui | Экран «Сотрудники: кассир, кладовщик, администратор (роли)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Точки продаж (2 кассы)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Кабинет кассира (ограниченное меню)](full-chain-demo-final-20261008-013158/screenshots/02a-kabinet-kassira.png)
+
+
+
+[Кассир: прямой URL /money/accounts не открывает данные](full-chain-demo-final-20261008-013158/screenshots/02a-kassir-pryamoy-url.png)
+
+
+
+[Сотрудники: кассир, кладовщик, администратор (роли)](full-chain-demo-final-20261008-013158/screenshots/02a-sotrudniki.png)
+
+
+
+[Точки продаж (2 кассы)](full-chain-demo-final-20261008-013158/screenshots/02a-tochki-prodazh.png)
+
+
+
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 2672мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+| ui | Экран «Счета: касса, банк (номер), эквайринг — начальные остатки»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Счета: касса, банк (номер), эквайринг — начальные остатки](full-chain-demo-final-20261008-013158/screenshots/03-scheta.png)
+
+
+
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 2013мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+| ui | Экран «Долги поставщикам: начальный долг 100 000 ₸»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Долги поставщикам: начальный долг 100 000 ₸](full-chain-demo-final-20261008-013158/screenshots/04-dolg-nachalnyy.png)
+
+
+
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 9626мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 0bd54f29… +20 | ✓ ожид=20 факт=20 |
+| api | Остаток 0cfad6a5… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток e6e79bf2… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток fbe7d065… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 3a92d8a7… +40 | ✓ ожид=40 факт=40 |
+| api | Остаток 9a6a59f8… +45 | ✓ ожид=45 факт=45 |
+| api | Остаток db59983d… +50 | ✓ ожид=50 факт=50 |
+| api | Остаток 66866675… +55 | ✓ ожид=55 факт=55 |
+| api | Остаток a6d3c6a1… +60 | ✓ ожид=60 факт=60 |
+| api | Остаток f75a5241… +65 | ✓ ожид=65 факт=65 |
+| api | Остаток 519251c8… +70 | ✓ ожид=70 факт=70 |
+| api | Остаток 89f82dd6… +75 | ✓ ожид=75 факт=75 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=900 факт=900 |
+| ui | Экран «Приёмка №1: форма создания (до проведения)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Список приёмок»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №1: проведена, строки и себестоимость»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Приёмка №1: форма создания (до проведения)](full-chain-demo-final-20261008-013158/screenshots/05-priemka1-forma.png)
+
+
+
+[Список приёмок](full-chain-demo-final-20261008-013158/screenshots/05-priemka1-spisok.png)
+
+
+
+[Приёмка №1: проведена, строки и себестоимость](full-chain-demo-final-20261008-013158/screenshots/05-priemka1-provedena.png)
+
+
+
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 20829мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток "BIOBLAS" шампунь +7 | ✓ ожид=7 факт=7 |
+| api | Остаток "BIOBLAS" шампунь +4 | ✓ ожид=4 факт=4 |
+| api | Остаток "BIOBLAS" шампунь +9 | ✓ ожид=9 факт=9 |
+| ui | Экран «Загруженные накладные (табличная разобрана)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №2: «Поставщик не указан», проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Загруженные накладные (табличная разобрана)](full-chain-demo-final-20261008-013158/screenshots/06-nakladnye-spisok.png)
+
+
+
+[Приёмка №2: «Поставщик не указан», проведена](full-chain-demo-final-20261008-013158/screenshots/06-priemka2-provedena.png)
+
+
+
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 25889мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+| ui | Экран «Фото-накладная: распознана (OCR) и сопоставлена вручную»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №3 (по фото): проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Фото-накладная: распознана (OCR) и сопоставлена вручную](full-chain-demo-final-20261008-013158/screenshots/07-foto-nakladnaya-razobrana.png)
+
+
+
+[Приёмка №3 (по фото): проведена](full-chain-demo-final-20261008-013158/screenshots/07-priemka3-provedena.png)
+
+
+
+[Фото-приёмка с телефона (моб.)](full-chain-demo-final-20261008-013158/screenshots/07-mob-foto-priemka.png)
+
+
+
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 4408мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=148812 факт=148812 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=18390 факт=18390 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=349498 факт=349498 |
+| ui | Экран «Платежи поставщикам: нал из кассы + с банка»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Долги поставщикам после оплат (= формуле)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Платежи поставщикам: нал из кассы + с банка](full-chain-demo-final-20261008-013158/screenshots/08-platezhi.png)
+
+
+
+[Долги поставщикам после оплат (= формуле)](full-chain-demo-final-20261008-013158/screenshots/08-dolg-posle-oplat.png)
+
+
+
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 10008мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=14275 факт=14275 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=3775/14275 факт=3775/14275 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+| ui | Экран «Смены кассы: открытие/закрытие, размен»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Закрытая смена: должно быть / факт / разница (Z-отчёт)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Чеки продаж (наличные/карта/смешанная) и возврат»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Смены кассы: открытие/закрытие, размен](full-chain-demo-final-20261008-013158/screenshots/09-smeny-spisok.png)
+
+
+
+[Закрытая смена: должно быть / факт / разница (Z-отчёт)](full-chain-demo-final-20261008-013158/screenshots/09-smena-zakryta-z.png)
+
+
+
+[Чеки продаж (наличные/карта/смешанная) и возврат](full-chain-demo-final-20261008-013158/screenshots/09-cheki-prodazhi.png)
+
+
+
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 4759мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2500 факт=2500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=3550 факт=3550 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+| ui | Экран «Параллельные смены на точках 1 и 2 (деньги раздельны)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Параллельные смены на точках 1 и 2 (деньги раздельны)](full-chain-demo-final-20261008-013158/screenshots/09a-parallelnye-smeny.png)
+
+
+
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 10399мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=48 факт=48 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+| ui | Экран «Оприходование излишка (+8)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Списание брака (−2)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Инвентаризация (часть товаров): расхождения»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Остатки после складских операций»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Оприходование излишка (+8)](full-chain-demo-final-20261008-013158/screenshots/10-oprihodovanie.png)
+
+
+
+[Списание брака (−2)](full-chain-demo-final-20261008-013158/screenshots/10-spisanie-braka.png)
+
+
+
+[Инвентаризация (часть товаров): расхождения](full-chain-demo-final-20261008-013158/screenshots/10-inventarizaciya.png)
+
+
+
+[Остатки после складских операций](full-chain-demo-final-20261008-013158/screenshots/10-ostatki-sklad.png)
+
+
+
+[Инвентаризация с телефона (сканер) (моб.)](full-chain-demo-final-20261008-013158/screenshots/10-mob-inventarizaciya.png)
+
+
+
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 9510мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=7650 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=-98812 факт=-98812 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=181610 факт=181610 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=7650 факт=7650 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=7650 факт=7650 |
+| ui | Экран «Отчёт: продажи за день (выручка)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: прибыль (выручка − себестоимость)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: остатки на дату»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт «Деньги»: остатки по счетам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: долги поставщикам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отчёт: продажи за день (выручка)](full-chain-demo-final-20261008-013158/screenshots/11-otchet-prodazhi.png)
+
+
+
+[Отчёт: прибыль (выручка − себестоимость)](full-chain-demo-final-20261008-013158/screenshots/11-otchet-pribyl.png)
+
+
+
+[Отчёт: остатки на дату](full-chain-demo-final-20261008-013158/screenshots/11-otchet-ostatki.png)
+
+
+
+[Отчёт «Деньги»: остатки по счетам](full-chain-demo-final-20261008-013158/screenshots/11-otchet-dengi.png)
+
+
+
+[Отчёт: долги поставщикам](full-chain-demo-final-20261008-013158/screenshots/11-otchet-dolgi.png)
+
+
+
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 6687мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=48 факт=48 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: "IQ уроки" книги | ✓ ожид=38 факт=38 |
+| api | Инвариант остаток≡Σдвижений: "Ludwik" средств | ✓ ожид=45 факт=45 |
+| api | Инвариант остаток≡Σдвижений: "Ludwik" средств | ✓ ожид=50 факт=50 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=55 факт=55 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=60 факт=60 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=65 факт=65 |
+| api | Инвариант остаток≡Σдвижений: "Rice Day" GRANA | ✓ ожид=70 факт=70 |
+| api | Инвариант остаток≡Σдвижений: "Richmond" Gold | ✓ ожид=75 факт=75 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса (e2e) 1791 | ✓ ожид=-98812 факт=-98812 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 (e2e) 17 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк (e2e) 17914 | ✓ ожид=181610 факт=181610 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг (e2e) | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 (e2e | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=349498 факт=349498 |
+| api | Изоляция: режим B (демо) — проверка через temp-орг в режиме C | ✓ ожид=n/a факт=n/a |
+| ui | Экран «Движения склада (остаток ≡ Σ движений)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Движения склада (остаток ≡ Σ движений)](full-chain-demo-final-20261008-013158/screenshots/12-dvizheniya-sklada.png)
+
+
+
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 2371мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=498310 факт=498310 |
+| ui | Экран «Отмена платежа → долг вернулся»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отмена платежа → долг вернулся](full-chain-demo-final-20261008-013158/screenshots/13-otkat-dolg-vernulsya.png)
+
+
+
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 3273мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Финальный дашборд без ошибок | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Галерея index.html собрана (36 кадров) | ✓ ожид=index.html факт=36 |
+| api | Режим B: e2e-сотрудники деактивированы (не удалены) | ✓ ожид=3 факт=3 |
+
+Скриншоты процесса:
+
+[Итоговый дашборд](full-chain-demo-final-20261008-013158/screenshots/14-itog-dashboard.png)
+
+
+
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Галерея скриншотов: /home/nns/food-market/tests/e2e/reports/full-chain-demo-final-20261008-013158/index.html
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/index.html b/tests/e2e/reports/full-chain-demo-final-20261008-013158/index.html
new file mode 100644
index 0000000..0cd1b56
--- /dev/null
+++ b/tests/e2e/reports/full-chain-demo-final-20261008-013158/index.html
@@ -0,0 +1,249 @@
+
+
+Full-chain e2e — скриншоты процессов (Демо-магазин (B))
+
+
+step01_register_and_login
+
+
+
+
+ 🖥 Вход владельца → дашборд организации01-vhod-dashboard.png
+
+step02_catalog_and_supplier
+
+
+
+
+ 🖥 Каталог «Демо-магазина»: реальные товары02-tovary-realnye.png
+
+
+
+
+
+ 🖥 Поставщик [e2e]02-postavshchik.png
+
+step02a_employees_and_points
+
+
+
+
+ 🖥 Кабинет кассира: без «Деньги»/«Настроек»02a-kabinet-kassira.png
+
+
+
+
+
+ 🖥 Кассир по прямому URL /money/accounts — нет данных02a-kassir-pryamoy-url.png
+
+
+
+
+
+ 🖥 Сотрудники: кассир, кладовщик, администратор (роли)02a-sotrudniki.png
+
+
+
+
+
+ 🖥 Точки продаж (2 кассы)02a-tochki-prodazh.png
+
+step03_money_accounts
+
+
+
+
+ 🖥 Счета: касса, банк (номер), эквайринг — начальные остатки03-scheta.png
+
+step04_initial_supplier_debt
+
+
+
+
+ 🖥 Долги поставщикам: начальный долг 100 000 ₸04-dolg-nachalnyy.png
+
+step05_supply1_manual
+
+
+
+
+ 🖥 Приёмка №1: форма создания (до проведения)05-priemka1-forma.png
+
+
+
+
+
+ 🖥 Список приёмок05-priemka1-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №1: проведена, строки и себестоимость05-priemka1-provedena.png
+
+step06_supply2_excel
+
+
+
+
+ 🖥 Загруженные накладные (табличная разобрана)06-nakladnye-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №2: «Поставщик не указан», проведена06-priemka2-provedena.png
+
+step07_supply3_photo
+
+
+
+
+ 🖥 Фото-накладная: распознана (OCR) и сопоставлена вручную07-foto-nakladnaya-razobrana.png
+
+
+
+
+
+ 🖥 Приёмка №3 (по фото): проведена07-priemka3-provedena.png
+
+
+
+
+
+ 📱 Фото-приёмка с телефона07-mob-foto-priemka.png
+
+step08_supplier_payments
+
+
+
+
+ 🖥 Платежи поставщикам: нал из кассы + с банка08-platezhi.png
+
+
+
+
+
+ 🖥 Долги поставщикам после оплат (= формуле)08-dolg-posle-oplat.png
+
+step09_cashier_shift
+
+
+
+
+ 🖥 Смены кассы: открытие/закрытие, размен09-smeny-spisok.png
+
+
+
+
+
+ 🖥 Закрытая смена: должно быть / факт / разница (Z-отчёт)09-smena-zakryta-z.png
+
+
+
+
+
+ 🖥 Чеки продаж (наличные/карта/смешанная) и возврат09-cheki-prodazhi.png
+
+step09a_points_binding
+
+
+
+
+ 🖥 Параллельные смены на точках 1 и 2 (деньги раздельны)09a-parallelnye-smeny.png
+
+step10_warehouse_ops
+
+
+
+
+ 🖥 Оприходование излишка (+8)10-oprihodovanie.png
+
+
+
+
+
+ 🖥 Списание брака (−2)10-spisanie-braka.png
+
+
+
+
+
+ 🖥 Инвентаризация (часть товаров): расхождения10-inventarizaciya.png
+
+
+
+
+
+ 🖥 Остатки после складских операций10-ostatki-sklad.png
+
+
+
+
+
+ 📱 Инвентаризация с телефона (сканер)10-mob-inventarizaciya.png
+
+step11_reports
+
+
+
+
+ 🖥 Отчёт: продажи за день (выручка)11-otchet-prodazhi.png
+
+
+
+
+
+ 🖥 Отчёт: прибыль (выручка − себестоимость)11-otchet-pribyl.png
+
+
+
+
+
+ 🖥 Отчёт: остатки на дату11-otchet-ostatki.png
+
+
+
+
+
+ 🖥 Отчёт «Деньги»: остатки по счетам11-otchet-dengi.png
+
+
+
+
+
+ 🖥 Отчёт: долги поставщикам11-otchet-dolgi.png
+
+step12_invariants
+
+
+
+
+ 🖥 Движения склада (остаток ≡ Σ движений)12-dvizheniya-sklada.png
+
+step13_cancel_rollback
+
+
+
+
+ 🖥 Отмена платежа → долг вернулся13-otkat-dolg-vernulsya.png
+
+step14_finalize
+
+
+
+
+ 🖥 Итоговый дашборд магазина после полного дня14-itog-dashboard.png
+
+
\ No newline at end of file
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/01-vhod-dashboard.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/01-vhod-dashboard.png
new file mode 100644
index 0000000..0bdc6af
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/01-vhod-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02-postavshchik.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02-postavshchik.png
new file mode 100644
index 0000000..29eb897
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02-postavshchik.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02-tovary-realnye.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02-tovary-realnye.png
new file mode 100644
index 0000000..156aa8a
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02-tovary-realnye.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02a-kabinet-kassira.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02a-kabinet-kassira.png
new file mode 100644
index 0000000..a0e60d6
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02a-kabinet-kassira.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02a-kassir-pryamoy-url.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02a-kassir-pryamoy-url.png
new file mode 100644
index 0000000..3ba6889
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02a-kassir-pryamoy-url.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02a-sotrudniki.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02a-sotrudniki.png
new file mode 100644
index 0000000..99246b1
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02a-sotrudniki.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02a-tochki-prodazh.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02a-tochki-prodazh.png
new file mode 100644
index 0000000..9def655
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/02a-tochki-prodazh.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/03-scheta.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/03-scheta.png
new file mode 100644
index 0000000..e37846e
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/03-scheta.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/04-dolg-nachalnyy.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/04-dolg-nachalnyy.png
new file mode 100644
index 0000000..0f2edda
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/04-dolg-nachalnyy.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/05-priemka1-forma.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/05-priemka1-forma.png
new file mode 100644
index 0000000..a614adb
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/05-priemka1-forma.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/05-priemka1-provedena.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/05-priemka1-provedena.png
new file mode 100644
index 0000000..e8f28d2
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/05-priemka1-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/05-priemka1-spisok.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/05-priemka1-spisok.png
new file mode 100644
index 0000000..6401327
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/05-priemka1-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/06-nakladnye-spisok.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/06-nakladnye-spisok.png
new file mode 100644
index 0000000..a087672
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/06-nakladnye-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/06-priemka2-provedena.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/06-priemka2-provedena.png
new file mode 100644
index 0000000..8c596f0
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/06-priemka2-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/07-foto-nakladnaya-razobrana.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/07-foto-nakladnaya-razobrana.png
new file mode 100644
index 0000000..d9cfda0
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/07-foto-nakladnaya-razobrana.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/07-mob-foto-priemka.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/07-mob-foto-priemka.png
new file mode 100644
index 0000000..81b99d1
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/07-mob-foto-priemka.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/07-priemka3-provedena.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/07-priemka3-provedena.png
new file mode 100644
index 0000000..9b44544
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/07-priemka3-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/08-dolg-posle-oplat.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/08-dolg-posle-oplat.png
new file mode 100644
index 0000000..755fdc1
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/08-dolg-posle-oplat.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/08-platezhi.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/08-platezhi.png
new file mode 100644
index 0000000..eb3268e
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/08-platezhi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/09-cheki-prodazhi.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/09-cheki-prodazhi.png
new file mode 100644
index 0000000..052f4ae
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/09-cheki-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/09-smena-zakryta-z.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/09-smena-zakryta-z.png
new file mode 100644
index 0000000..98ac36d
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/09-smena-zakryta-z.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/09-smeny-spisok.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/09-smeny-spisok.png
new file mode 100644
index 0000000..79a4328
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/09-smeny-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/09a-parallelnye-smeny.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/09a-parallelnye-smeny.png
new file mode 100644
index 0000000..3ca01c1
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/09a-parallelnye-smeny.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-inventarizaciya.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-inventarizaciya.png
new file mode 100644
index 0000000..7e044db
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-mob-inventarizaciya.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-mob-inventarizaciya.png
new file mode 100644
index 0000000..f2528cd
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-mob-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-oprihodovanie.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-oprihodovanie.png
new file mode 100644
index 0000000..10ffece
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-oprihodovanie.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-ostatki-sklad.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-ostatki-sklad.png
new file mode 100644
index 0000000..824c594
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-ostatki-sklad.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-spisanie-braka.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-spisanie-braka.png
new file mode 100644
index 0000000..a307e31
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/10-spisanie-braka.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-dengi.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-dengi.png
new file mode 100644
index 0000000..40e9eed
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-dengi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-dolgi.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-dolgi.png
new file mode 100644
index 0000000..755fdc1
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-dolgi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-ostatki.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-ostatki.png
new file mode 100644
index 0000000..55ac013
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-ostatki.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-pribyl.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-pribyl.png
new file mode 100644
index 0000000..fedb95c
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-pribyl.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-prodazhi.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-prodazhi.png
new file mode 100644
index 0000000..ba36271
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/11-otchet-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/12-dvizheniya-sklada.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/12-dvizheniya-sklada.png
new file mode 100644
index 0000000..dc0c5aa
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/12-dvizheniya-sklada.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/13-otkat-dolg-vernulsya.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/13-otkat-dolg-vernulsya.png
new file mode 100644
index 0000000..755fdc1
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/13-otkat-dolg-vernulsya.png differ
diff --git a/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/14-itog-dashboard.png b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/14-itog-dashboard.png
new file mode 100644
index 0000000..34431d8
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-final-20261008-013158/screenshots/14-itog-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416.md b/tests/e2e/reports/full-chain-demo-money-20261008-030416.md
new file mode 100644
index 0000000..f40e5d4
--- /dev/null
+++ b/tests/e2e/reports/full-chain-demo-money-20261008-030416.md
@@ -0,0 +1,507 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T22:04:20.468Z
+Длительность: 142.0с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 5404мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вход demo-admin (режим B) | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| ui | Кабинет владельца открылся без ошибок (0 console/5xx/тостов) | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Вход владельца → дашборд](full-chain-demo-money-20261008-030416/screenshots/01-vhod-dashboard.png)
+
+
+
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 5087мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Выбрано реальных товаров каталога (≥5, штрихкод+цена) | ✓ ожид=≥5 факт=12 |
+| api | Среди выбранных есть весовой (информативно) | ✓ ожид=≥0 факт=0 |
+| api | Поставщик [e2e] создан | ✓ ожид=200+id факт=201 |
+| ui | Экран «Каталог «Демо-магазина»: реальные товары»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Поставщик [e2e]»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Каталог «Демо-магазина»: реальные товары](full-chain-demo-money-20261008-030416/screenshots/02-tovary-realnye.png)
+
+
+
+[Поставщик [e2e]](full-chain-demo-money-20261008-030416/screenshots/02-postavshchik.png)
+
+![Поставщик [e2e]](full-chain-demo-money-20261008-030416/screenshots/02-postavshchik.png)
+
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 19448мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/11 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 (e2e) 1791410660467 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 (e2e) 1791410660467 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| ui | Кассир: в меню нет модуля «Деньги» (счета/платежи/долги) | ✓ ожид=нет факт=нет |
+| ui | Кассир: в меню есть своя касса (/money/shifts) | ✓ ожид=есть факт=есть |
+| ui | Кассир: в меню нет «Настройки» | ✓ ожид=нет /settings факт=нет |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+| ui | Экран «Сотрудники: кассир, кладовщик, администратор (роли)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Точки продаж (2 кассы)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Кабинет кассира (ограниченное меню)](full-chain-demo-money-20261008-030416/screenshots/02a-kabinet-kassira.png)
+
+
+
+[Кассир: прямой URL /money/accounts не открывает данные](full-chain-demo-money-20261008-030416/screenshots/02a-kassir-pryamoy-url.png)
+
+
+
+[Сотрудники: кассир, кладовщик, администратор (роли)](full-chain-demo-money-20261008-030416/screenshots/02a-sotrudniki.png)
+
+
+
+[Точки продаж (2 кассы)](full-chain-demo-money-20261008-030416/screenshots/02a-tochki-prodazh.png)
+
+
+
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 3047мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+| ui | Экран «Счета: касса, банк (номер), эквайринг — начальные остатки»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Счета: касса, банк (номер), эквайринг — начальные остатки](full-chain-demo-money-20261008-030416/screenshots/03-scheta.png)
+
+
+
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 2093мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+| ui | Экран «Долги поставщикам: начальный долг 100 000 ₸»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Долги поставщикам: начальный долг 100 000 ₸](full-chain-demo-money-20261008-030416/screenshots/04-dolg-nachalnyy.png)
+
+
+
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 12167мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 0bd54f29… +20 | ✓ ожид=20 факт=20 |
+| api | Остаток 0cfad6a5… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток e6e79bf2… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток fbe7d065… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 3a92d8a7… +40 | ✓ ожид=40 факт=40 |
+| api | Остаток 9a6a59f8… +45 | ✓ ожид=45 факт=45 |
+| api | Остаток db59983d… +50 | ✓ ожид=50 факт=50 |
+| api | Остаток 66866675… +55 | ✓ ожид=55 факт=55 |
+| api | Остаток a6d3c6a1… +60 | ✓ ожид=60 факт=60 |
+| api | Остаток f75a5241… +65 | ✓ ожид=65 факт=65 |
+| api | Остаток 519251c8… +70 | ✓ ожид=70 факт=70 |
+| api | Остаток 89f82dd6… +75 | ✓ ожид=75 факт=75 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=900 факт=900 |
+| ui | Экран «Приёмка №1: форма создания (до проведения)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Список приёмок»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №1: проведена, строки и себестоимость»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Приёмка №1: форма создания (до проведения)](full-chain-demo-money-20261008-030416/screenshots/05-priemka1-forma.png)
+
+
+
+[Список приёмок](full-chain-demo-money-20261008-030416/screenshots/05-priemka1-spisok.png)
+
+
+
+[Приёмка №1: проведена, строки и себестоимость](full-chain-demo-money-20261008-030416/screenshots/05-priemka1-provedena.png)
+
+
+
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 9963мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток "BIOBLAS" шампунь +7 | ✓ ожид=7 факт=7 |
+| api | Остаток "BIOBLAS" шампунь +4 | ✓ ожид=4 факт=4 |
+| api | Остаток "BIOBLAS" шампунь +9 | ✓ ожид=9 факт=9 |
+| ui | Экран «Загруженные накладные (табличная разобрана)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №2: «Поставщик не указан», проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Загруженные накладные (табличная разобрана)](full-chain-demo-money-20261008-030416/screenshots/06-nakladnye-spisok.png)
+
+
+
+[Приёмка №2: «Поставщик не указан», проведена](full-chain-demo-money-20261008-030416/screenshots/06-priemka2-provedena.png)
+
+
+
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 26456мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+| ui | Экран «Фото-накладная: распознана (OCR) и сопоставлена вручную»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №3 (по фото): проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Фото-накладная: распознана (OCR) и сопоставлена вручную](full-chain-demo-money-20261008-030416/screenshots/07-foto-nakladnaya-razobrana.png)
+
+
+
+[Приёмка №3 (по фото): проведена](full-chain-demo-money-20261008-030416/screenshots/07-priemka3-provedena.png)
+
+
+
+[Фото-приёмка с телефона (моб.)](full-chain-demo-money-20261008-030416/screenshots/07-mob-foto-priemka.png)
+
+
+
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 5928мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=18390 факт=18390 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=468310 факт=468310 |
+| ui | Экран «Платежи поставщикам: нал из кассы + с банка»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Долги поставщикам после оплат (= формуле)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Платежи поставщикам: нал из кассы + с банка](full-chain-demo-money-20261008-030416/screenshots/08-platezhi.png)
+
+
+
+[Долги поставщикам после оплат (= формуле)](full-chain-demo-money-20261008-030416/screenshots/08-dolg-posle-oplat.png)
+
+
+
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 12133мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=14275 факт=14275 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=3775/14275 факт=3775/14275 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=29775 факт=29775 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=2325 факт=2325 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+| ui | Экран «Смены кассы: открытие/закрытие, размен»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Закрытая смена: должно быть / факт / разница (Z-отчёт)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Чеки продаж (наличные/карта/смешанная) и возврат»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Смены кассы: открытие/закрытие, размен](full-chain-demo-money-20261008-030416/screenshots/09-smeny-spisok.png)
+
+
+
+[Закрытая смена: должно быть / факт / разница (Z-отчёт)](full-chain-demo-money-20261008-030416/screenshots/09-smena-zakryta-z.png)
+
+
+
+[Чеки продаж (наличные/карта/смешанная) и возврат](full-chain-demo-money-20261008-030416/screenshots/09-cheki-prodazhi.png)
+
+
+
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 6180мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2500 факт=2500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=3550 факт=3550 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+| ui | Экран «Параллельные смены на точках 1 и 2 (деньги раздельны)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Параллельные смены на точках 1 и 2 (деньги раздельны)](full-chain-demo-money-20261008-030416/screenshots/09a-parallelnye-smeny.png)
+
+
+
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 12672мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=48 факт=48 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+| ui | Экран «Оприходование излишка (+8)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Списание брака (−2)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Инвентаризация (часть товаров): расхождения»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Остатки после складских операций»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Оприходование излишка (+8)](full-chain-demo-money-20261008-030416/screenshots/10-oprihodovanie.png)
+
+
+
+[Списание брака (−2)](full-chain-demo-money-20261008-030416/screenshots/10-spisanie-braka.png)
+
+
+
+[Инвентаризация (часть товаров): расхождения](full-chain-demo-money-20261008-030416/screenshots/10-inventarizaciya.png)
+
+
+
+[Остатки после складских операций](full-chain-demo-money-20261008-030416/screenshots/10-ostatki-sklad.png)
+
+
+
+[Инвентаризация с телефона (сканер) (моб.)](full-chain-demo-money-20261008-030416/screenshots/10-mob-inventarizaciya.png)
+
+
+
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 9682мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=7650 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=31275 факт=31275 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=181610 факт=181610 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=2325 факт=2325 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=7650 факт=7650 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=7650 факт=7650 |
+| ui | Экран «Отчёт: продажи за день (выручка)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: прибыль (выручка − себестоимость)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: остатки на дату»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт «Деньги»: остатки по счетам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: долги поставщикам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отчёт: продажи за день (выручка)](full-chain-demo-money-20261008-030416/screenshots/11-otchet-prodazhi.png)
+
+
+
+[Отчёт: прибыль (выручка − себестоимость)](full-chain-demo-money-20261008-030416/screenshots/11-otchet-pribyl.png)
+
+
+
+[Отчёт: остатки на дату](full-chain-demo-money-20261008-030416/screenshots/11-otchet-ostatki.png)
+
+
+
+[Отчёт «Деньги»: остатки по счетам](full-chain-demo-money-20261008-030416/screenshots/11-otchet-dengi.png)
+
+
+
+[Отчёт: долги поставщикам](full-chain-demo-money-20261008-030416/screenshots/11-otchet-dolgi.png)
+
+
+
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 6495мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=48 факт=48 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: "IQ уроки" книги | ✓ ожид=38 факт=38 |
+| api | Инвариант остаток≡Σдвижений: "Ludwik" средств | ✓ ожид=45 факт=45 |
+| api | Инвариант остаток≡Σдвижений: "Ludwik" средств | ✓ ожид=50 факт=50 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=55 факт=55 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=60 факт=60 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=65 факт=65 |
+| api | Инвариант остаток≡Σдвижений: "Rice Day" GRANA | ✓ ожид=70 факт=70 |
+| api | Инвариант остаток≡Σдвижений: "Richmond" Gold | ✓ ожид=75 факт=75 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=31275 факт=31275 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=181610 факт=181610 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=2325 факт=2325 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=4550 факт=4550 |
+| api | Инвариант долг≡формуле | ✓ ожид=468310 факт=468310 |
+| api | Изоляция: режим B (демо) — проверка через temp-орг в режиме C | ✓ ожид=n/a факт=n/a |
+| ui | Экран «Движения склада (остаток ≡ Σ движений)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Движения склада (остаток ≡ Σ движений)](full-chain-demo-money-20261008-030416/screenshots/12-dvizheniya-sklada.png)
+
+
+
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 2365мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=498310 факт=498310 |
+| ui | Экран «Отмена платежа → долг вернулся»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отмена платежа → долг вернулся](full-chain-demo-money-20261008-030416/screenshots/13-otkat-dolg-vernulsya.png)
+
+
+
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 2906мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Финальный дашборд без ошибок | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Галерея index.html собрана (36 кадров) | ✓ ожид=index.html факт=36 |
+| api | Режим B: e2e-сотрудники деактивированы (не удалены) | ✓ ожид=3 факт=3 |
+
+Скриншоты процесса:
+
+[Итоговый дашборд](full-chain-demo-money-20261008-030416/screenshots/14-itog-dashboard.png)
+
+
+
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Галерея скриншотов: /home/nns/food-market/tests/e2e/reports/full-chain-demo-money-20261008-030416/index.html
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/index.html b/tests/e2e/reports/full-chain-demo-money-20261008-030416/index.html
new file mode 100644
index 0000000..2fa62cc
--- /dev/null
+++ b/tests/e2e/reports/full-chain-demo-money-20261008-030416/index.html
@@ -0,0 +1,249 @@
+
+
+Full-chain e2e — скриншоты процессов (Демо-магазин (B))
+
+
+step01_register_and_login
+
+
+
+
+ 🖥 Вход владельца → дашборд организации01-vhod-dashboard.png
+
+step02_catalog_and_supplier
+
+
+
+
+ 🖥 Каталог «Демо-магазина»: реальные товары02-tovary-realnye.png
+
+
+
+
+
+ 🖥 Поставщик [e2e]02-postavshchik.png
+
+step02a_employees_and_points
+
+
+
+
+ 🖥 Кабинет кассира: без «Деньги»/«Настроек»02a-kabinet-kassira.png
+
+
+
+
+
+ 🖥 Кассир по прямому URL /money/accounts — нет данных02a-kassir-pryamoy-url.png
+
+
+
+
+
+ 🖥 Сотрудники: кассир, кладовщик, администратор (роли)02a-sotrudniki.png
+
+
+
+
+
+ 🖥 Точки продаж (2 кассы)02a-tochki-prodazh.png
+
+step03_money_accounts
+
+
+
+
+ 🖥 Счета: касса, банк (номер), эквайринг — начальные остатки03-scheta.png
+
+step04_initial_supplier_debt
+
+
+
+
+ 🖥 Долги поставщикам: начальный долг 100 000 ₸04-dolg-nachalnyy.png
+
+step05_supply1_manual
+
+
+
+
+ 🖥 Приёмка №1: форма создания (до проведения)05-priemka1-forma.png
+
+
+
+
+
+ 🖥 Список приёмок05-priemka1-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №1: проведена, строки и себестоимость05-priemka1-provedena.png
+
+step06_supply2_excel
+
+
+
+
+ 🖥 Загруженные накладные (табличная разобрана)06-nakladnye-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №2: «Поставщик не указан», проведена06-priemka2-provedena.png
+
+step07_supply3_photo
+
+
+
+
+ 🖥 Фото-накладная: распознана (OCR) и сопоставлена вручную07-foto-nakladnaya-razobrana.png
+
+
+
+
+
+ 🖥 Приёмка №3 (по фото): проведена07-priemka3-provedena.png
+
+
+
+
+
+ 📱 Фото-приёмка с телефона07-mob-foto-priemka.png
+
+step08_supplier_payments
+
+
+
+
+ 🖥 Платежи поставщикам: нал из кассы + с банка08-platezhi.png
+
+
+
+
+
+ 🖥 Долги поставщикам после оплат (= формуле)08-dolg-posle-oplat.png
+
+step09_cashier_shift
+
+
+
+
+ 🖥 Смены кассы: открытие/закрытие, размен09-smeny-spisok.png
+
+
+
+
+
+ 🖥 Закрытая смена: должно быть / факт / разница (Z-отчёт)09-smena-zakryta-z.png
+
+
+
+
+
+ 🖥 Чеки продаж (наличные/карта/смешанная) и возврат09-cheki-prodazhi.png
+
+step09a_points_binding
+
+
+
+
+ 🖥 Параллельные смены на точках 1 и 2 (деньги раздельны)09a-parallelnye-smeny.png
+
+step10_warehouse_ops
+
+
+
+
+ 🖥 Оприходование излишка (+8)10-oprihodovanie.png
+
+
+
+
+
+ 🖥 Списание брака (−2)10-spisanie-braka.png
+
+
+
+
+
+ 🖥 Инвентаризация (часть товаров): расхождения10-inventarizaciya.png
+
+
+
+
+
+ 🖥 Остатки после складских операций10-ostatki-sklad.png
+
+
+
+
+
+ 📱 Инвентаризация с телефона (сканер)10-mob-inventarizaciya.png
+
+step11_reports
+
+
+
+
+ 🖥 Отчёт: продажи за день (выручка)11-otchet-prodazhi.png
+
+
+
+
+
+ 🖥 Отчёт: прибыль (выручка − себестоимость)11-otchet-pribyl.png
+
+
+
+
+
+ 🖥 Отчёт: остатки на дату11-otchet-ostatki.png
+
+
+
+
+
+ 🖥 Отчёт «Деньги»: остатки по счетам11-otchet-dengi.png
+
+
+
+
+
+ 🖥 Отчёт: долги поставщикам11-otchet-dolgi.png
+
+step12_invariants
+
+
+
+
+ 🖥 Движения склада (остаток ≡ Σ движений)12-dvizheniya-sklada.png
+
+step13_cancel_rollback
+
+
+
+
+ 🖥 Отмена платежа → долг вернулся13-otkat-dolg-vernulsya.png
+
+step14_finalize
+
+
+
+
+ 🖥 Итоговый дашборд магазина после полного дня14-itog-dashboard.png
+
+
\ No newline at end of file
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/01-vhod-dashboard.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/01-vhod-dashboard.png
new file mode 100644
index 0000000..91e50bc
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/01-vhod-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02-postavshchik.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02-postavshchik.png
new file mode 100644
index 0000000..f0a89e3
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02-postavshchik.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02-tovary-realnye.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02-tovary-realnye.png
new file mode 100644
index 0000000..340009a
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02-tovary-realnye.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02a-kabinet-kassira.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02a-kabinet-kassira.png
new file mode 100644
index 0000000..b1d5739
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02a-kabinet-kassira.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02a-kassir-pryamoy-url.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02a-kassir-pryamoy-url.png
new file mode 100644
index 0000000..2513660
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02a-kassir-pryamoy-url.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02a-sotrudniki.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02a-sotrudniki.png
new file mode 100644
index 0000000..637b8e9
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02a-sotrudniki.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02a-tochki-prodazh.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02a-tochki-prodazh.png
new file mode 100644
index 0000000..67ea2f5
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/02a-tochki-prodazh.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/03-scheta.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/03-scheta.png
new file mode 100644
index 0000000..8649c72
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/03-scheta.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/04-dolg-nachalnyy.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/04-dolg-nachalnyy.png
new file mode 100644
index 0000000..e28a01b
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/04-dolg-nachalnyy.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/05-priemka1-forma.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/05-priemka1-forma.png
new file mode 100644
index 0000000..a614adb
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/05-priemka1-forma.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/05-priemka1-provedena.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/05-priemka1-provedena.png
new file mode 100644
index 0000000..27a7f6b
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/05-priemka1-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/05-priemka1-spisok.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/05-priemka1-spisok.png
new file mode 100644
index 0000000..bf34a32
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/05-priemka1-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/06-nakladnye-spisok.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/06-nakladnye-spisok.png
new file mode 100644
index 0000000..3a15951
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/06-nakladnye-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/06-priemka2-provedena.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/06-priemka2-provedena.png
new file mode 100644
index 0000000..7876e9b
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/06-priemka2-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/07-foto-nakladnaya-razobrana.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/07-foto-nakladnaya-razobrana.png
new file mode 100644
index 0000000..12f4cd3
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/07-foto-nakladnaya-razobrana.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/07-mob-foto-priemka.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/07-mob-foto-priemka.png
new file mode 100644
index 0000000..8594e43
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/07-mob-foto-priemka.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/07-priemka3-provedena.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/07-priemka3-provedena.png
new file mode 100644
index 0000000..b4445a0
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/07-priemka3-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/08-dolg-posle-oplat.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/08-dolg-posle-oplat.png
new file mode 100644
index 0000000..137dbec
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/08-dolg-posle-oplat.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/08-platezhi.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/08-platezhi.png
new file mode 100644
index 0000000..1f96f26
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/08-platezhi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/09-cheki-prodazhi.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/09-cheki-prodazhi.png
new file mode 100644
index 0000000..b90fe6e
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/09-cheki-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/09-smena-zakryta-z.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/09-smena-zakryta-z.png
new file mode 100644
index 0000000..0278333
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/09-smena-zakryta-z.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/09-smeny-spisok.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/09-smeny-spisok.png
new file mode 100644
index 0000000..688fd3f
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/09-smeny-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/09a-parallelnye-smeny.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/09a-parallelnye-smeny.png
new file mode 100644
index 0000000..1df16d5
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/09a-parallelnye-smeny.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-inventarizaciya.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-inventarizaciya.png
new file mode 100644
index 0000000..7e044db
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-mob-inventarizaciya.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-mob-inventarizaciya.png
new file mode 100644
index 0000000..f2528cd
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-mob-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-oprihodovanie.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-oprihodovanie.png
new file mode 100644
index 0000000..10ffece
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-oprihodovanie.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-ostatki-sklad.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-ostatki-sklad.png
new file mode 100644
index 0000000..6ae907a
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-ostatki-sklad.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-spisanie-braka.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-spisanie-braka.png
new file mode 100644
index 0000000..a307e31
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/10-spisanie-braka.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-dengi.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-dengi.png
new file mode 100644
index 0000000..2739211
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-dengi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-dolgi.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-dolgi.png
new file mode 100644
index 0000000..137dbec
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-dolgi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-ostatki.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-ostatki.png
new file mode 100644
index 0000000..55ac013
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-ostatki.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-pribyl.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-pribyl.png
new file mode 100644
index 0000000..fedb95c
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-pribyl.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-prodazhi.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-prodazhi.png
new file mode 100644
index 0000000..ba36271
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/11-otchet-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/12-dvizheniya-sklada.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/12-dvizheniya-sklada.png
new file mode 100644
index 0000000..3f3645d
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/12-dvizheniya-sklada.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/13-otkat-dolg-vernulsya.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/13-otkat-dolg-vernulsya.png
new file mode 100644
index 0000000..137dbec
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/13-otkat-dolg-vernulsya.png differ
diff --git a/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/14-itog-dashboard.png b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/14-itog-dashboard.png
new file mode 100644
index 0000000..d38920e
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-money-20261008-030416/screenshots/14-itog-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935.md b/tests/e2e/reports/full-chain-demo-v2-20261008-015935.md
new file mode 100644
index 0000000..3d49666
--- /dev/null
+++ b/tests/e2e/reports/full-chain-demo-v2-20261008-015935.md
@@ -0,0 +1,504 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:59:39.225Z
+Длительность: 133.3с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 4941мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вход demo-admin (режим B) | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| ui | Кабинет владельца открылся без ошибок (0 console/5xx/тостов) | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Вход владельца → дашборд](full-chain-demo-v2-20261008-015935/screenshots/01-vhod-dashboard.png)
+
+
+
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 4846мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Выбрано реальных товаров каталога (≥5, штрихкод+цена) | ✓ ожид=≥5 факт=12 |
+| api | Среди выбранных есть весовой (информативно) | ✓ ожид=≥0 факт=0 |
+| api | Поставщик [e2e] создан | ✓ ожид=200+id факт=201 |
+| ui | Экран «Каталог «Демо-магазина»: реальные товары»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Поставщик [e2e]»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Каталог «Демо-магазина»: реальные товары](full-chain-demo-v2-20261008-015935/screenshots/02-tovary-realnye.png)
+
+
+
+[Поставщик [e2e]](full-chain-demo-v2-20261008-015935/screenshots/02-postavshchik.png)
+
+![Поставщик [e2e]](full-chain-demo-v2-20261008-015935/screenshots/02-postavshchik.png)
+
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 19443мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/11 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 (e2e) 1791406779224 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 (e2e) 1791406779224 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| ui | Кассир: в меню нет модуля «Деньги» (счета/платежи/долги) | ✓ ожид=нет факт=нет |
+| ui | Кассир: в меню есть своя касса (/money/shifts) | ✓ ожид=есть факт=есть |
+| ui | Кассир: в меню нет «Настройки» | ✓ ожид=нет /settings факт=нет |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+| ui | Экран «Сотрудники: кассир, кладовщик, администратор (роли)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Точки продаж (2 кассы)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Кабинет кассира (ограниченное меню)](full-chain-demo-v2-20261008-015935/screenshots/02a-kabinet-kassira.png)
+
+
+
+[Кассир: прямой URL /money/accounts не открывает данные](full-chain-demo-v2-20261008-015935/screenshots/02a-kassir-pryamoy-url.png)
+
+
+
+[Сотрудники: кассир, кладовщик, администратор (роли)](full-chain-demo-v2-20261008-015935/screenshots/02a-sotrudniki.png)
+
+
+
+[Точки продаж (2 кассы)](full-chain-demo-v2-20261008-015935/screenshots/02a-tochki-prodazh.png)
+
+
+
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 3917мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+| ui | Экран «Счета: касса, банк (номер), эквайринг — начальные остатки»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Счета: касса, банк (номер), эквайринг — начальные остатки](full-chain-demo-v2-20261008-015935/screenshots/03-scheta.png)
+
+
+
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 2694мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+| ui | Экран «Долги поставщикам: начальный долг 100 000 ₸»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Долги поставщикам: начальный долг 100 000 ₸](full-chain-demo-v2-20261008-015935/screenshots/04-dolg-nachalnyy.png)
+
+
+
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 12197мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 0bd54f29… +20 | ✓ ожид=20 факт=20 |
+| api | Остаток 0cfad6a5… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток e6e79bf2… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток fbe7d065… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 3a92d8a7… +40 | ✓ ожид=40 факт=40 |
+| api | Остаток 9a6a59f8… +45 | ✓ ожид=45 факт=45 |
+| api | Остаток db59983d… +50 | ✓ ожид=50 факт=50 |
+| api | Остаток 66866675… +55 | ✓ ожид=55 факт=55 |
+| api | Остаток a6d3c6a1… +60 | ✓ ожид=60 факт=60 |
+| api | Остаток f75a5241… +65 | ✓ ожид=65 факт=65 |
+| api | Остаток 519251c8… +70 | ✓ ожид=70 факт=70 |
+| api | Остаток 89f82dd6… +75 | ✓ ожид=75 факт=75 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=900 факт=900 |
+| ui | Экран «Приёмка №1: форма создания (до проведения)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Список приёмок»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №1: проведена, строки и себестоимость»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Приёмка №1: форма создания (до проведения)](full-chain-demo-v2-20261008-015935/screenshots/05-priemka1-forma.png)
+
+
+
+[Список приёмок](full-chain-demo-v2-20261008-015935/screenshots/05-priemka1-spisok.png)
+
+
+
+[Приёмка №1: проведена, строки и себестоимость](full-chain-demo-v2-20261008-015935/screenshots/05-priemka1-provedena.png)
+
+
+
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 8735мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток "BIOBLAS" шампунь +7 | ✓ ожид=7 факт=7 |
+| api | Остаток "BIOBLAS" шампунь +4 | ✓ ожид=4 факт=4 |
+| api | Остаток "BIOBLAS" шампунь +9 | ✓ ожид=9 факт=9 |
+| ui | Экран «Загруженные накладные (табличная разобрана)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №2: «Поставщик не указан», проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Загруженные накладные (табличная разобрана)](full-chain-demo-v2-20261008-015935/screenshots/06-nakladnye-spisok.png)
+
+
+
+[Приёмка №2: «Поставщик не указан», проведена](full-chain-demo-v2-20261008-015935/screenshots/06-priemka2-provedena.png)
+
+
+
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 23010мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+| ui | Экран «Фото-накладная: распознана (OCR) и сопоставлена вручную»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №3 (по фото): проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Фото-накладная: распознана (OCR) и сопоставлена вручную](full-chain-demo-v2-20261008-015935/screenshots/07-foto-nakladnaya-razobrana.png)
+
+
+
+[Приёмка №3 (по фото): проведена](full-chain-demo-v2-20261008-015935/screenshots/07-priemka3-provedena.png)
+
+
+
+[Фото-приёмка с телефона (моб.)](full-chain-demo-v2-20261008-015935/screenshots/07-mob-foto-priemka.png)
+
+
+
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 4747мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=148812 факт=148812 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=18390 факт=18390 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=349498 факт=349498 |
+| ui | Экран «Платежи поставщикам: нал из кассы + с банка»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Долги поставщикам после оплат (= формуле)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Платежи поставщикам: нал из кассы + с банка](full-chain-demo-v2-20261008-015935/screenshots/08-platezhi.png)
+
+
+
+[Долги поставщикам после оплат (= формуле)](full-chain-demo-v2-20261008-015935/screenshots/08-dolg-posle-oplat.png)
+
+
+
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 10499мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=14275 факт=14275 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=3775/14275 факт=3775/14275 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+| ui | Экран «Смены кассы: открытие/закрытие, размен»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Закрытая смена: должно быть / факт / разница (Z-отчёт)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Чеки продаж (наличные/карта/смешанная) и возврат»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Смены кассы: открытие/закрытие, размен](full-chain-demo-v2-20261008-015935/screenshots/09-smeny-spisok.png)
+
+
+
+[Закрытая смена: должно быть / факт / разница (Z-отчёт)](full-chain-demo-v2-20261008-015935/screenshots/09-smena-zakryta-z.png)
+
+
+
+[Чеки продаж (наличные/карта/смешанная) и возврат](full-chain-demo-v2-20261008-015935/screenshots/09-cheki-prodazhi.png)
+
+
+
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 5019мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2500 факт=2500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=3550 факт=3550 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+| ui | Экран «Параллельные смены на точках 1 и 2 (деньги раздельны)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Параллельные смены на точках 1 и 2 (деньги раздельны)](full-chain-demo-v2-20261008-015935/screenshots/09a-parallelnye-smeny.png)
+
+
+
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 11309мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=48 факт=48 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+| ui | Экран «Оприходование излишка (+8)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Списание брака (−2)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Инвентаризация (часть товаров): расхождения»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Остатки после складских операций»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Оприходование излишка (+8)](full-chain-demo-v2-20261008-015935/screenshots/10-oprihodovanie.png)
+
+
+
+[Списание брака (−2)](full-chain-demo-v2-20261008-015935/screenshots/10-spisanie-braka.png)
+
+
+
+[Инвентаризация (часть товаров): расхождения](full-chain-demo-v2-20261008-015935/screenshots/10-inventarizaciya.png)
+
+
+
+[Остатки после складских операций](full-chain-demo-v2-20261008-015935/screenshots/10-ostatki-sklad.png)
+
+
+
+[Инвентаризация с телефона (сканер) (моб.)](full-chain-demo-v2-20261008-015935/screenshots/10-mob-inventarizaciya.png)
+
+
+
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 9386мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=7650 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=-98812 факт=-98812 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=181610 факт=181610 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=7650 факт=7650 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=7650 факт=7650 |
+| ui | Экран «Отчёт: продажи за день (выручка)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: прибыль (выручка − себестоимость)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: остатки на дату»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт «Деньги»: остатки по счетам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: долги поставщикам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отчёт: продажи за день (выручка)](full-chain-demo-v2-20261008-015935/screenshots/11-otchet-prodazhi.png)
+
+
+
+[Отчёт: прибыль (выручка − себестоимость)](full-chain-demo-v2-20261008-015935/screenshots/11-otchet-pribyl.png)
+
+
+
+[Отчёт: остатки на дату](full-chain-demo-v2-20261008-015935/screenshots/11-otchet-ostatki.png)
+
+
+
+[Отчёт «Деньги»: остатки по счетам](full-chain-demo-v2-20261008-015935/screenshots/11-otchet-dengi.png)
+
+
+
+[Отчёт: долги поставщикам](full-chain-demo-v2-20261008-015935/screenshots/11-otchet-dolgi.png)
+
+
+
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 6685мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=48 факт=48 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: "BIOBLAS" шампун | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: "IQ уроки" книги | ✓ ожид=38 факт=38 |
+| api | Инвариант остаток≡Σдвижений: "Ludwik" средств | ✓ ожид=45 факт=45 |
+| api | Инвариант остаток≡Σдвижений: "Ludwik" средств | ✓ ожид=50 факт=50 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=55 факт=55 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=60 факт=60 |
+| api | Инвариант остаток≡Σдвижений: "Pero" салфетки | ✓ ожид=65 факт=65 |
+| api | Инвариант остаток≡Σдвижений: "Rice Day" GRANA | ✓ ожид=70 факт=70 |
+| api | Инвариант остаток≡Σдвижений: "Richmond" Gold | ✓ ожид=75 факт=75 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса (e2e) 1791 | ✓ ожид=-98812 факт=-98812 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 (e2e) 17 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк (e2e) 17914 | ✓ ожид=181610 факт=181610 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг (e2e) | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 (e2e | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=349498 факт=349498 |
+| api | Изоляция: режим B (демо) — проверка через temp-орг в режиме C | ✓ ожид=n/a факт=n/a |
+| ui | Экран «Движения склада (остаток ≡ Σ движений)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Движения склада (остаток ≡ Σ движений)](full-chain-demo-v2-20261008-015935/screenshots/12-dvizheniya-sklada.png)
+
+
+
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 2625мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=498310 факт=498310 |
+| ui | Экран «Отмена платежа → долг вернулся»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отмена платежа → долг вернулся](full-chain-demo-v2-20261008-015935/screenshots/13-otkat-dolg-vernulsya.png)
+
+
+
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 3206мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Финальный дашборд без ошибок | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Галерея index.html собрана (36 кадров) | ✓ ожид=index.html факт=36 |
+| api | Режим B: e2e-сотрудники деактивированы (не удалены) | ✓ ожид=3 факт=3 |
+
+Скриншоты процесса:
+
+[Итоговый дашборд](full-chain-demo-v2-20261008-015935/screenshots/14-itog-dashboard.png)
+
+
+
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Галерея скриншотов: /home/nns/food-market/tests/e2e/reports/full-chain-demo-v2-20261008-015935/index.html
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/index.html b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/index.html
new file mode 100644
index 0000000..738fa4d
--- /dev/null
+++ b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/index.html
@@ -0,0 +1,249 @@
+
+
+Full-chain e2e — скриншоты процессов (Демо-магазин (B))
+
+
+step01_register_and_login
+
+
+
+
+ 🖥 Вход владельца → дашборд организации01-vhod-dashboard.png
+
+step02_catalog_and_supplier
+
+
+
+
+ 🖥 Каталог «Демо-магазина»: реальные товары02-tovary-realnye.png
+
+
+
+
+
+ 🖥 Поставщик [e2e]02-postavshchik.png
+
+step02a_employees_and_points
+
+
+
+
+ 🖥 Кабинет кассира: без «Деньги»/«Настроек»02a-kabinet-kassira.png
+
+
+
+
+
+ 🖥 Кассир по прямому URL /money/accounts — нет данных02a-kassir-pryamoy-url.png
+
+
+
+
+
+ 🖥 Сотрудники: кассир, кладовщик, администратор (роли)02a-sotrudniki.png
+
+
+
+
+
+ 🖥 Точки продаж (2 кассы)02a-tochki-prodazh.png
+
+step03_money_accounts
+
+
+
+
+ 🖥 Счета: касса, банк (номер), эквайринг — начальные остатки03-scheta.png
+
+step04_initial_supplier_debt
+
+
+
+
+ 🖥 Долги поставщикам: начальный долг 100 000 ₸04-dolg-nachalnyy.png
+
+step05_supply1_manual
+
+
+
+
+ 🖥 Приёмка №1: форма создания (до проведения)05-priemka1-forma.png
+
+
+
+
+
+ 🖥 Список приёмок05-priemka1-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №1: проведена, строки и себестоимость05-priemka1-provedena.png
+
+step06_supply2_excel
+
+
+
+
+ 🖥 Загруженные накладные (табличная разобрана)06-nakladnye-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №2: «Поставщик не указан», проведена06-priemka2-provedena.png
+
+step07_supply3_photo
+
+
+
+
+ 🖥 Фото-накладная: распознана (OCR) и сопоставлена вручную07-foto-nakladnaya-razobrana.png
+
+
+
+
+
+ 🖥 Приёмка №3 (по фото): проведена07-priemka3-provedena.png
+
+
+
+
+
+ 📱 Фото-приёмка с телефона07-mob-foto-priemka.png
+
+step08_supplier_payments
+
+
+
+
+ 🖥 Платежи поставщикам: нал из кассы + с банка08-platezhi.png
+
+
+
+
+
+ 🖥 Долги поставщикам после оплат (= формуле)08-dolg-posle-oplat.png
+
+step09_cashier_shift
+
+
+
+
+ 🖥 Смены кассы: открытие/закрытие, размен09-smeny-spisok.png
+
+
+
+
+
+ 🖥 Закрытая смена: должно быть / факт / разница (Z-отчёт)09-smena-zakryta-z.png
+
+
+
+
+
+ 🖥 Чеки продаж (наличные/карта/смешанная) и возврат09-cheki-prodazhi.png
+
+step09a_points_binding
+
+
+
+
+ 🖥 Параллельные смены на точках 1 и 2 (деньги раздельны)09a-parallelnye-smeny.png
+
+step10_warehouse_ops
+
+
+
+
+ 🖥 Оприходование излишка (+8)10-oprihodovanie.png
+
+
+
+
+
+ 🖥 Списание брака (−2)10-spisanie-braka.png
+
+
+
+
+
+ 🖥 Инвентаризация (часть товаров): расхождения10-inventarizaciya.png
+
+
+
+
+
+ 🖥 Остатки после складских операций10-ostatki-sklad.png
+
+
+
+
+
+ 📱 Инвентаризация с телефона (сканер)10-mob-inventarizaciya.png
+
+step11_reports
+
+
+
+
+ 🖥 Отчёт: продажи за день (выручка)11-otchet-prodazhi.png
+
+
+
+
+
+ 🖥 Отчёт: прибыль (выручка − себестоимость)11-otchet-pribyl.png
+
+
+
+
+
+ 🖥 Отчёт: остатки на дату11-otchet-ostatki.png
+
+
+
+
+
+ 🖥 Отчёт «Деньги»: остатки по счетам11-otchet-dengi.png
+
+
+
+
+
+ 🖥 Отчёт: долги поставщикам11-otchet-dolgi.png
+
+step12_invariants
+
+
+
+
+ 🖥 Движения склада (остаток ≡ Σ движений)12-dvizheniya-sklada.png
+
+step13_cancel_rollback
+
+
+
+
+ 🖥 Отмена платежа → долг вернулся13-otkat-dolg-vernulsya.png
+
+step14_finalize
+
+
+
+
+ 🖥 Итоговый дашборд магазина после полного дня14-itog-dashboard.png
+
+
\ No newline at end of file
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/01-vhod-dashboard.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/01-vhod-dashboard.png
new file mode 100644
index 0000000..91e50bc
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/01-vhod-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02-postavshchik.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02-postavshchik.png
new file mode 100644
index 0000000..c5a8440
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02-postavshchik.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02-tovary-realnye.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02-tovary-realnye.png
new file mode 100644
index 0000000..340009a
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02-tovary-realnye.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02a-kabinet-kassira.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02a-kabinet-kassira.png
new file mode 100644
index 0000000..c5b1a10
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02a-kabinet-kassira.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02a-kassir-pryamoy-url.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02a-kassir-pryamoy-url.png
new file mode 100644
index 0000000..660b12a
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02a-kassir-pryamoy-url.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02a-sotrudniki.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02a-sotrudniki.png
new file mode 100644
index 0000000..96061d5
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02a-sotrudniki.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02a-tochki-prodazh.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02a-tochki-prodazh.png
new file mode 100644
index 0000000..ae71a7e
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/02a-tochki-prodazh.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/03-scheta.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/03-scheta.png
new file mode 100644
index 0000000..1a3c4a1
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/03-scheta.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/04-dolg-nachalnyy.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/04-dolg-nachalnyy.png
new file mode 100644
index 0000000..c47c073
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/04-dolg-nachalnyy.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/05-priemka1-forma.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/05-priemka1-forma.png
new file mode 100644
index 0000000..a614adb
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/05-priemka1-forma.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/05-priemka1-provedena.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/05-priemka1-provedena.png
new file mode 100644
index 0000000..089ab4d
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/05-priemka1-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/05-priemka1-spisok.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/05-priemka1-spisok.png
new file mode 100644
index 0000000..b929dce
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/05-priemka1-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/06-nakladnye-spisok.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/06-nakladnye-spisok.png
new file mode 100644
index 0000000..0b421d6
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/06-nakladnye-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/06-priemka2-provedena.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/06-priemka2-provedena.png
new file mode 100644
index 0000000..04e80d2
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/06-priemka2-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/07-foto-nakladnaya-razobrana.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/07-foto-nakladnaya-razobrana.png
new file mode 100644
index 0000000..1aa2664
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/07-foto-nakladnaya-razobrana.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/07-mob-foto-priemka.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/07-mob-foto-priemka.png
new file mode 100644
index 0000000..34a9ebe
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/07-mob-foto-priemka.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/07-priemka3-provedena.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/07-priemka3-provedena.png
new file mode 100644
index 0000000..e929a0a
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/07-priemka3-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/08-dolg-posle-oplat.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/08-dolg-posle-oplat.png
new file mode 100644
index 0000000..4804f3c
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/08-dolg-posle-oplat.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/08-platezhi.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/08-platezhi.png
new file mode 100644
index 0000000..b08e631
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/08-platezhi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/09-cheki-prodazhi.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/09-cheki-prodazhi.png
new file mode 100644
index 0000000..5eba1c3
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/09-cheki-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/09-smena-zakryta-z.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/09-smena-zakryta-z.png
new file mode 100644
index 0000000..b1db5bc
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/09-smena-zakryta-z.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/09-smeny-spisok.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/09-smeny-spisok.png
new file mode 100644
index 0000000..5246be0
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/09-smeny-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/09a-parallelnye-smeny.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/09a-parallelnye-smeny.png
new file mode 100644
index 0000000..d256b5f
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/09a-parallelnye-smeny.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-inventarizaciya.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-inventarizaciya.png
new file mode 100644
index 0000000..7e044db
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-mob-inventarizaciya.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-mob-inventarizaciya.png
new file mode 100644
index 0000000..8edd7bb
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-mob-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-oprihodovanie.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-oprihodovanie.png
new file mode 100644
index 0000000..10ffece
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-oprihodovanie.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-ostatki-sklad.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-ostatki-sklad.png
new file mode 100644
index 0000000..ff63f5c
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-ostatki-sklad.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-spisanie-braka.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-spisanie-braka.png
new file mode 100644
index 0000000..a307e31
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/10-spisanie-braka.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-dengi.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-dengi.png
new file mode 100644
index 0000000..529aa04
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-dengi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-dolgi.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-dolgi.png
new file mode 100644
index 0000000..4804f3c
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-dolgi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-ostatki.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-ostatki.png
new file mode 100644
index 0000000..55ac013
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-ostatki.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-pribyl.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-pribyl.png
new file mode 100644
index 0000000..fedb95c
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-pribyl.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-prodazhi.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-prodazhi.png
new file mode 100644
index 0000000..ba36271
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/11-otchet-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/12-dvizheniya-sklada.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/12-dvizheniya-sklada.png
new file mode 100644
index 0000000..549ff66
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/12-dvizheniya-sklada.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/13-otkat-dolg-vernulsya.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/13-otkat-dolg-vernulsya.png
new file mode 100644
index 0000000..4804f3c
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/13-otkat-dolg-vernulsya.png differ
diff --git a/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/14-itog-dashboard.png b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/14-itog-dashboard.png
new file mode 100644
index 0000000..5838f2f
Binary files /dev/null and b/tests/e2e/reports/full-chain-demo-v2-20261008-015935/screenshots/14-itog-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-final-c1-013213.md b/tests/e2e/reports/full-chain-final-c1-013213.md
new file mode 100644
index 0000000..029b06d
--- /dev/null
+++ b/tests/e2e/reports/full-chain-final-c1-013213.md
@@ -0,0 +1,259 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:32:17.490Z
+Длительность: 57.1с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 1966мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2082мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 7071мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791405137489 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791405137489 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 925мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 462мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2660мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 8f51713e… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 5be45876… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток fc6b2019… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 30cd38ee… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 17fa6f91… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5011мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914051 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914051 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914051 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 19989мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1177мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 5007мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3149мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 2448мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 989мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3415мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914051 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140513 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 720мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-final-c2-013314.md b/tests/e2e/reports/full-chain-final-c2-013314.md
new file mode 100644
index 0000000..10045c0
--- /dev/null
+++ b/tests/e2e/reports/full-chain-final-c2-013314.md
@@ -0,0 +1,262 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:33:18.998Z
+Длительность: 56.2с
+
+**Итог:** 15 ✓ / 1 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2018мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 1939мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 6809мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791405198997 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791405198997 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1026мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 446мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2682мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 58e1e129… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 2a1a9634… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток ea259d21… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 93e763f1… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток a6a2c889… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✗ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5051мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✗ ожид=204 факт=409 |
+| api | Остаток Товар 1 fc17914051 +7 | ✗ ожид=7 факт=0 |
+| api | Остаток Товар 2 fc17914051 +4 | ✗ ожид=4 факт=0 |
+| api | Остаток Товар 3 fc17914051 +9 | ✗ ожид=9 факт=0 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 19969мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1125мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 4500мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3014мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 2473мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=33.5 факт=33.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=44 факт=44 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1070мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3286мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=33.5 факт=33.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=44 факт=44 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914051 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140519 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 750мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 15
+- Failed: 1
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+### HIGH
+
+- **[06] Остатки после приёмки №2 не совпали**
+ - supply=1085f707-f3bf-40c2-89b0-6c1c62a578b6
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-green-1-010932.md b/tests/e2e/reports/full-chain-green-1-010932.md
new file mode 100644
index 0000000..c7a9d42
--- /dev/null
+++ b/tests/e2e/reports/full-chain-green-1-010932.md
@@ -0,0 +1,251 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:09:36.320Z
+Длительность: 63.3с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2516мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2556мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 4912мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791403776319 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791403776319 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1031мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 520мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2590мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 1588893b… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 42a61bd1… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 4b1664b2… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 6d67953a… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток eaece334… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5422мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914037 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914037 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914037 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 20656мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Фото-накладная распознана (OCR, needs_review) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1689мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 7320мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3443мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 3458мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1535мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по точкам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по кассирам доступен | ✓ ожид=200 факт=200 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 4557мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914037 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140377 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 1124мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-green-2-011039.md b/tests/e2e/reports/full-chain-green-2-011039.md
new file mode 100644
index 0000000..00a94f7
--- /dev/null
+++ b/tests/e2e/reports/full-chain-green-2-011039.md
@@ -0,0 +1,251 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:10:44.393Z
+Длительность: 54.6с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2229мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2747мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 5445мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791403844392 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791403844392 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1173мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 549мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2906мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 691a2cf7… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 7c0a1273… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток f694baef… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 011caba4… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток c4277f02… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5130мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914038 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914038 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914038 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 20071мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Фото-накладная распознана (OCR, needs_review) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1072мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 4204мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2219мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 2373мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 896мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по точкам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по кассирам доступен | ✓ ожид=200 факт=200 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 2942мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914038 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140384 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 650мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-mseqc1-030650.md b/tests/e2e/reports/full-chain-mseqc1-030650.md
new file mode 100644
index 0000000..77a577d
--- /dev/null
+++ b/tests/e2e/reports/full-chain-mseqc1-030650.md
@@ -0,0 +1,269 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T22:06:54.185Z
+Длительность: 70.2с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2033мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2226мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 7584мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791410814184 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791410814184 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1123мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 572мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 3426мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток d5d37b23… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 176c8a42… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 27b074ea… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 8e807c36… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 14dd9f49… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 6116мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914108 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914108 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914108 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 20972мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 2344мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 6379мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 4136мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 6861мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1534мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3650мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179141 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179141 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179141 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179141 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179141 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 1216мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-mseqc2-030804.md b/tests/e2e/reports/full-chain-mseqc2-030804.md
new file mode 100644
index 0000000..9467441
--- /dev/null
+++ b/tests/e2e/reports/full-chain-mseqc2-030804.md
@@ -0,0 +1,269 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T22:08:08.822Z
+Длительность: 63.9с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2533мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 3173мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 9233мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791410888821 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791410888821 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1465мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 743мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 3847мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток a0d44395… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток d853ac18… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток a17c4146… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток b9efe750… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 0e46a8de… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 6138мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914108 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914108 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914108 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 17424мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 2008мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 5503мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3101мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 4595мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1004мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 2345мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179141 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179141 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179141 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179141 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179141 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 829мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-nightly-20261008.md b/tests/e2e/reports/full-chain-nightly-20261008.md
new file mode 100644
index 0000000..cec282c
--- /dev/null
+++ b/tests/e2e/reports/full-chain-nightly-20261008.md
@@ -0,0 +1,305 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T23:02:53.702Z
+Длительность: 120.3с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 7331мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| ui | Кабинет владельца открылся без ошибок (0 console/5xx/тостов) | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 5376мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+| ui | Экран «Каталог: 5 товаров с ценами и штрихкодами»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Карточка товара: цена продажи и штрихкод»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Справочник контрагентов: поставщик (БИН, телефон)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 32852мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791414173701 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791414173701 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| ui | Кассир: в меню нет модуля «Деньги» (счета/платежи/долги) | ✓ ожид=нет факт=нет |
+| ui | Кассир: в меню есть своя касса (/money/shifts) | ✓ ожид=есть факт=есть |
+| ui | Кассир: в меню нет «Настройки» | ✓ ожид=нет /settings факт=нет |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+| ui | Экран «Сотрудники: кассир, кладовщик, администратор (роли)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Точки продаж (2 кассы)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 2170мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+| ui | Экран «Счета: касса, банк (номер), эквайринг — начальные остатки»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 1475мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+| ui | Экран «Долги поставщикам: начальный долг 100 000 ₸»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 5696мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 22f77138… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 4821d94a… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток e16b602b… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток cbf843f6… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток beb368d9… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+| ui | Экран «Приёмка №1: форма создания (до проведения)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Список приёмок»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №1: проведена, строки и себестоимость»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 7508мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914141 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914141 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914141 +9 | ✓ ожид=9 факт=9 |
+| ui | Экран «Загруженные накладные (табличная разобрана)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №2: «Поставщик не указан», проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 22568мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+| ui | Экран «Фото-накладная: распознана (OCR) и сопоставлена вручную»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №3 (по фото): проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 3318мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+| ui | Экран «Платежи поставщикам: нал из кассы + с банка»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Долги поставщикам после оплат (= формуле)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 8482мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+| ui | Экран «Смены кассы: открытие/закрытие, размен»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Закрытая смена: должно быть / факт / разница (Z-отчёт)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Чеки продаж (наличные/карта/смешанная) и возврат»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 4353мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+| ui | Экран «Параллельные смены на точках 1 и 2 (деньги раздельны)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 8068мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+| ui | Экран «Оприходование излишка (+8)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Списание брака (−2)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Инвентаризация (часть товаров): расхождения»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Остатки после складских операций»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 5010мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| ui | Экран «Отчёт: продажи за день (выручка)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: прибыль (выручка − себестоимость)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: остатки на дату»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт «Деньги»: остатки по счетам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: долги поставщикам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3575мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179141 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179141 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179141 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179141 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179141 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+| ui | Экран «Движения склада (остаток ≡ Σ движений)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 1559мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+| ui | Экран «Отмена платежа → долг вернулся»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 940мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Финальный дашборд без ошибок | ✓ ожид=0 ошибок факт=0 ошибок |
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-nightly-20261009.md b/tests/e2e/reports/full-chain-nightly-20261009.md
new file mode 100644
index 0000000..938ebbd
--- /dev/null
+++ b/tests/e2e/reports/full-chain-nightly-20261009.md
@@ -0,0 +1,320 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-08T23:00:39.239Z
+Длительность: 94.5с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 4031мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| ui | Кабинет владельца открылся без ошибок (0 console/5xx/тостов) | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 4060мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+| ui | Экран «Каталог: 5 товаров с ценами и штрихкодами»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Карточка товара: цена продажи и штрихкод»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Справочник контрагентов: поставщик (БИН, телефон)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 11110мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791500439239 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791500439239 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| ui | Кассир: в меню нет модуля «Деньги» (счета/платежи/долги) | ✓ ожид=нет факт=нет |
+| ui | Кассир: в меню есть своя касса (/money/shifts) | ✓ ожид=есть факт=есть |
+| ui | Кассир: в меню нет «Настройки» | ✓ ожид=нет /settings факт=нет |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+| ui | Экран «Сотрудники: кассир, кладовщик, администратор (роли)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Точки продаж (2 кассы)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1972мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+| ui | Экран «Счета: касса, банк (номер), эквайринг — начальные остатки»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 1490мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+| ui | Экран «Долги поставщикам: начальный долг 100 000 ₸»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 4626мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток cd58283d… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 3bb3a5e5… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 0b9fe760… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 6e9ca1d8… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток e625754e… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+| ui | Экран «Приёмка №1: форма создания (до проведения)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Список приёмок»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №1: проведена, строки и себестоимость»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 6799мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17915004 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17915004 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17915004 +9 | ✓ ожид=9 факт=9 |
+| ui | Экран «Загруженные накладные (табличная разобрана)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №2: «Поставщик не указан», проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 24693мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+| ui | Экран «Фото-накладная: распознана (OCR) и сопоставлена вручную»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №3 (по фото): проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 3783мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+| ui | Экран «Платежи поставщикам: нал из кассы + с банка»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Долги поставщикам после оплат (= формуле)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 7600мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | После продажи в минус появилось предупреждение | ✓ ожид=>=1 факт=1 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+| ui | Экран «Смены кассы: открытие/закрытие, размен»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Закрытая смена: должно быть / факт / разница (Z-отчёт)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Чеки продаж (наличные/карта/смешанная) и возврат»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3385мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+| ui | Экран «Параллельные смены на точках 1 и 2 (деньги раздельны)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 10354мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+| api | Инвентаризация завершена (Completed) | ✓ ожид=204 факт=204 |
+| api | После завершения остаток НЕ изменился | ✓ ожид=40.5 факт=40.5 |
+| api | Создано оприходование излишков | ✓ ожид=200+enterId факт=200 |
+| api | В инвентаризации виден связанный документ | ✓ ожид=true факт=true |
+| api | Оприходование проведено | ✓ ожид=204 факт=204 |
+| api | Излишек применён оприходованием (+3) | ✓ ожид=3 факт=3 |
+| api | Оприходование «на основании инвентаризации №…» | ✓ ожид=инв.№ факт=И-2026-000003 |
+| api | unpost при проведённом связанном → 409 (не удаляет) | ✓ ожид=409 факт=409 |
+| api | Отмена результатов (cancel-results) → 200 | ✓ ожид=200 факт=200 |
+| api | После отмены результатов остаток вернулся | ✓ ожид=40.5 факт=40.5 |
+| api | Оприходование НЕ удалено, стало черновиком | ✓ ожид=draft факт=200/0 |
+| api | Связанный документ остался (черновик) | ✓ ожид=true факт=true |
+| api | Повторное проведение оприходования | ✓ ожид=204 факт=204 |
+| api | После повторного проведения остаток снова = факт (+3) | ✓ ожид=3 факт=3 |
+| ui | Экран «Оприходование излишка (+8)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Списание брака (−2)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Инвентаризация (часть товаров): расхождения»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Остатки после складских операций»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 4643мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| ui | Экран «Отчёт: продажи за день (выручка)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: прибыль (выручка − себестоимость)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: остатки на дату»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт «Деньги»: остатки по счетам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: долги поставщикам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3165мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179150 | ✓ ожид=43.5 факт=43.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179150 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179150 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179150 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179150 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+| ui | Экран «Движения склада (остаток ≡ Σ движений)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 1617мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+| ui | Экран «Отмена платежа → долг вернулся»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1152мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Финальный дашборд без ошибок | ✓ ожид=0 ошибок факт=0 ошибок |
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-seqc1-020157.md b/tests/e2e/reports/full-chain-seqc1-020157.md
new file mode 100644
index 0000000..4f017df
--- /dev/null
+++ b/tests/e2e/reports/full-chain-seqc1-020157.md
@@ -0,0 +1,266 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T21:02:02.092Z
+Длительность: 60.6с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2208мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2082мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 7180мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791406922091 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791406922091 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 928мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 466мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2538мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток eb3e2a18… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток a057aef1… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 1cb21c9c… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток b48c9f64… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 9684474c… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5083мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914069 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914069 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914069 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 20548мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1230мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 5019мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3103мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 5054мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1084мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3276мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914069 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140692 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 770мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-seqc2-020302.md b/tests/e2e/reports/full-chain-seqc2-020302.md
new file mode 100644
index 0000000..bccb3c7
--- /dev/null
+++ b/tests/e2e/reports/full-chain-seqc2-020302.md
@@ -0,0 +1,266 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T21:03:06.716Z
+Длительность: 62.6с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2029мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2143мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 6950мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791406986715 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791406986715 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 969мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 460мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2662мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток a5cf02b8… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 1af67453… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 0d4fcaf3… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 18b32388… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток c053b6bb… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5217мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914069 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914069 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914069 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 23374мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1121мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 4878мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2991мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 4768мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1113мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3068мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914069 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140698 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 811мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 2мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-uicheck-012558.md b/tests/e2e/reports/full-chain-uicheck-012558.md
new file mode 100644
index 0000000..1f50172
--- /dev/null
+++ b/tests/e2e/reports/full-chain-uicheck-012558.md
@@ -0,0 +1,495 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:26:02.352Z
+Длительность: 143.3с
+
+**Итог:** 15 ✓ / 1 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 4809мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| ui | Кабинет владельца открылся без ошибок (0 console/5xx/тостов) | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Вход владельца → дашборд](full-chain-uicheck-012558/screenshots/01-vhod-dashboard.png)
+
+
+
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 7584мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+| ui | Экран «Каталог: 5 товаров с ценами и штрихкодами»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Карточка товара: цена продажи и штрихкод»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Справочник контрагентов: поставщик (БИН, телефон)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Каталог: 5 товаров с ценами и штрихкодами](full-chain-uicheck-012558/screenshots/02-tovary-spisok.png)
+
+
+
+[Карточка товара: цена продажи и штрихкод](full-chain-uicheck-012558/screenshots/02-tovar-kar_tochka.png)
+
+
+
+[Справочник контрагентов: поставщик (БИН, телефон)](full-chain-uicheck-012558/screenshots/02-postavshchik.png)
+
+
+
+
+## ✗ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 19200мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791404762351 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791404762351 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| ui | Кассир: в меню нет раздела «Деньги» | ✗ ожид=нет /money факт=/money/shifts |
+| ui | Кассир: в меню нет «Настройки» | ✓ ожид=нет /settings факт=нет |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+| ui | Экран «Сотрудники: кассир, кладовщик, администратор (роли)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Точки продаж (2 кассы)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Кабинет кассира (ограниченное меню)](full-chain-uicheck-012558/screenshots/02a-kabinet-kassira.png)
+
+
+
+[Кассир: прямой URL /money/accounts не открывает данные](full-chain-uicheck-012558/screenshots/02a-kassir-pryamoy-url.png)
+
+
+
+[Сотрудники: кассир, кладовщик, администратор (роли)](full-chain-uicheck-012558/screenshots/02a-sotrudniki.png)
+
+
+
+[Точки продаж (2 кассы)](full-chain-uicheck-012558/screenshots/02a-tochki-prodazh.png)
+
+
+
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 2679мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+| ui | Экран «Счета: касса, банк (номер), эквайринг — начальные остатки»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Счета: касса, банк (номер), эквайринг — начальные остатки](full-chain-uicheck-012558/screenshots/03-scheta.png)
+
+
+
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 2134мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+| ui | Экран «Долги поставщикам: начальный долг 100 000 ₸»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Долги поставщикам: начальный долг 100 000 ₸](full-chain-uicheck-012558/screenshots/04-dolg-nachalnyy.png)
+
+
+
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 7556мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 0fa5c747… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 3386b618… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 37032683… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 6bede1a2… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток e45be9a1… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+| ui | Экран «Приёмка №1: форма создания (до проведения)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Список приёмок»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №1: проведена, строки и себестоимость»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Приёмка №1: форма создания (до проведения)](full-chain-uicheck-012558/screenshots/05-priemka1-forma.png)
+
+
+
+[Список приёмок](full-chain-uicheck-012558/screenshots/05-priemka1-spisok.png)
+
+
+
+[Приёмка №1: проведена, строки и себестоимость](full-chain-uicheck-012558/screenshots/05-priemka1-provedena.png)
+
+
+
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 8353мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914047 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914047 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914047 +9 | ✓ ожид=9 факт=9 |
+| ui | Экран «Загруженные накладные (табличная разобрана)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №2: «Поставщик не указан», проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Загруженные накладные (табличная разобрана)](full-chain-uicheck-012558/screenshots/06-nakladnye-spisok.png)
+
+
+
+[Приёмка №2: «Поставщик не указан», проведена](full-chain-uicheck-012558/screenshots/06-priemka2-provedena.png)
+
+
+
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 25706мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+| ui | Экран «Фото-накладная: распознана (OCR) и сопоставлена вручную»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №3 (по фото): проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Фото-накладная: распознана (OCR) и сопоставлена вручную](full-chain-uicheck-012558/screenshots/07-foto-nakladnaya-razobrana.png)
+
+
+
+[Приёмка №3 (по фото): проведена](full-chain-uicheck-012558/screenshots/07-priemka3-provedena.png)
+
+
+
+[Фото-приёмка с телефона (моб.)](full-chain-uicheck-012558/screenshots/07-mob-foto-priemka.png)
+
+
+
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 4617мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+| ui | Экран «Платежи поставщикам: нал из кассы + с банка»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Долги поставщикам после оплат (= формуле)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Платежи поставщикам: нал из кассы + с банка](full-chain-uicheck-012558/screenshots/08-platezhi.png)
+
+
+
+[Долги поставщикам после оплат (= формуле)](full-chain-uicheck-012558/screenshots/08-dolg-posle-oplat.png)
+
+
+
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 10558мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+| ui | Экран «Смены кассы: открытие/закрытие, размен»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Закрытая смена: должно быть / факт / разница (Z-отчёт)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Чеки продаж (наличные/карта/смешанная) и возврат»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Смены кассы: открытие/закрытие, размен](full-chain-uicheck-012558/screenshots/09-smeny-spisok.png)
+
+
+
+[Закрытая смена: должно быть / факт / разница (Z-отчёт)](full-chain-uicheck-012558/screenshots/09-smena-zakryta-z.png)
+
+
+
+[Чеки продаж (наличные/карта/смешанная) и возврат](full-chain-uicheck-012558/screenshots/09-cheki-prodazhi.png)
+
+
+
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 4860мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+| ui | Экран «Параллельные смены на точках 1 и 2 (деньги раздельны)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Параллельные смены на точках 1 и 2 (деньги раздельны)](full-chain-uicheck-012558/screenshots/09a-parallelnye-smeny.png)
+
+
+
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 10641мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+| ui | Экран «Оприходование излишка (+8)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Списание брака (−2)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Инвентаризация (часть товаров): расхождения»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Остатки после складских операций»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Оприходование излишка (+8)](full-chain-uicheck-012558/screenshots/10-oprihodovanie.png)
+
+
+
+[Списание брака (−2)](full-chain-uicheck-012558/screenshots/10-spisanie-braka.png)
+
+
+
+[Инвентаризация (часть товаров): расхождения](full-chain-uicheck-012558/screenshots/10-inventarizaciya.png)
+
+
+
+[Остатки после складских операций](full-chain-uicheck-012558/screenshots/10-ostatki-sklad.png)
+
+
+
+[Инвентаризация с телефона (сканер) (моб.)](full-chain-uicheck-012558/screenshots/10-mob-inventarizaciya.png)
+
+
+
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 9912мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| ui | Экран «Отчёт: продажи за день (выручка)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: прибыль (выручка − себестоимость)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: остатки на дату»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт «Деньги»: остатки по счетам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: долги поставщикам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отчёт: продажи за день (выручка)](full-chain-uicheck-012558/screenshots/11-otchet-prodazhi.png)
+
+
+
+[Отчёт: прибыль (выручка − себестоимость)](full-chain-uicheck-012558/screenshots/11-otchet-pribyl.png)
+
+
+
+[Отчёт: остатки на дату](full-chain-uicheck-012558/screenshots/11-otchet-ostatki.png)
+
+
+
+[Отчёт «Деньги»: остатки по счетам](full-chain-uicheck-012558/screenshots/11-otchet-dengi.png)
+
+
+
+[Отчёт: долги поставщикам](full-chain-uicheck-012558/screenshots/11-otchet-dolgi.png)
+
+
+
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 20449мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914047 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140476 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+| ui | Экран «Движения склада (остаток ≡ Σ движений)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Движения склада (остаток ≡ Σ движений)](full-chain-uicheck-012558/screenshots/12-dvizheniya-sklada.png)
+
+
+
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 2332мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+| ui | Экран «Отмена платежа → долг вернулся»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отмена платежа → долг вернулся](full-chain-uicheck-012558/screenshots/13-otkat-dolg-vernulsya.png)
+
+
+
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1889мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Финальный дашборд без ошибок | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Галерея index.html собрана (37 кадров) | ✓ ожид=index.html факт=37 |
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+Скриншоты процесса:
+
+[Итоговый дашборд](full-chain-uicheck-012558/screenshots/14-itog-dashboard.png)
+
+
+
+
+## Summary
+
+- Passed: 15
+- Failed: 1
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+### HIGH
+
+- **[02a] В меню кассира видны запретные разделы**
+ - /,/dashboard,/catalog/products,/inventory/stock,/sales/retail,/money/shifts,/help,/whats-new,/whats-new,/sales/retail,/inventory/stock
+
+## UX recommendations
+
+- Галерея скриншотов: /home/nns/food-market/tests/e2e/reports/full-chain-uicheck-012558/index.html
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/index.html b/tests/e2e/reports/full-chain-uicheck-012558/index.html
new file mode 100644
index 0000000..ef69e62
--- /dev/null
+++ b/tests/e2e/reports/full-chain-uicheck-012558/index.html
@@ -0,0 +1,255 @@
+
+
+Full-chain e2e — скриншоты процессов (temp-орг (C))
+
+
+step01_register_and_login
+
+
+
+
+ 🖥 Вход владельца → дашборд организации01-vhod-dashboard.png
+
+step02_catalog_and_supplier
+
+
+
+
+ 🖥 Каталог: 5 товаров с ценами и штрихкодами02-tovary-spisok.png
+
+
+
+
+
+ 🖥 Карточка товара: цена продажи и штрихкод02-tovar-kar_tochka.png
+
+
+
+
+
+ 🖥 Справочник контрагентов: поставщик (БИН, телефон)02-postavshchik.png
+
+step02a_employees_and_points
+
+
+
+
+ 🖥 Кабинет кассира: без «Деньги»/«Настроек»02a-kabinet-kassira.png
+
+
+
+
+
+ 🖥 Кассир по прямому URL /money/accounts — нет данных02a-kassir-pryamoy-url.png
+
+
+
+
+
+ 🖥 Сотрудники: кассир, кладовщик, администратор (роли)02a-sotrudniki.png
+
+
+
+
+
+ 🖥 Точки продаж (2 кассы)02a-tochki-prodazh.png
+
+step03_money_accounts
+
+
+
+
+ 🖥 Счета: касса, банк (номер), эквайринг — начальные остатки03-scheta.png
+
+step04_initial_supplier_debt
+
+
+
+
+ 🖥 Долги поставщикам: начальный долг 100 000 ₸04-dolg-nachalnyy.png
+
+step05_supply1_manual
+
+
+
+
+ 🖥 Приёмка №1: форма создания (до проведения)05-priemka1-forma.png
+
+
+
+
+
+ 🖥 Список приёмок05-priemka1-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №1: проведена, строки и себестоимость05-priemka1-provedena.png
+
+step06_supply2_excel
+
+
+
+
+ 🖥 Загруженные накладные (табличная разобрана)06-nakladnye-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №2: «Поставщик не указан», проведена06-priemka2-provedena.png
+
+step07_supply3_photo
+
+
+
+
+ 🖥 Фото-накладная: распознана (OCR) и сопоставлена вручную07-foto-nakladnaya-razobrana.png
+
+
+
+
+
+ 🖥 Приёмка №3 (по фото): проведена07-priemka3-provedena.png
+
+
+
+
+
+ 📱 Фото-приёмка с телефона07-mob-foto-priemka.png
+
+step08_supplier_payments
+
+
+
+
+ 🖥 Платежи поставщикам: нал из кассы + с банка08-platezhi.png
+
+
+
+
+
+ 🖥 Долги поставщикам после оплат (= формуле)08-dolg-posle-oplat.png
+
+step09_cashier_shift
+
+
+
+
+ 🖥 Смены кассы: открытие/закрытие, размен09-smeny-spisok.png
+
+
+
+
+
+ 🖥 Закрытая смена: должно быть / факт / разница (Z-отчёт)09-smena-zakryta-z.png
+
+
+
+
+
+ 🖥 Чеки продаж (наличные/карта/смешанная) и возврат09-cheki-prodazhi.png
+
+step09a_points_binding
+
+
+
+
+ 🖥 Параллельные смены на точках 1 и 2 (деньги раздельны)09a-parallelnye-smeny.png
+
+step10_warehouse_ops
+
+
+
+
+ 🖥 Оприходование излишка (+8)10-oprihodovanie.png
+
+
+
+
+
+ 🖥 Списание брака (−2)10-spisanie-braka.png
+
+
+
+
+
+ 🖥 Инвентаризация (часть товаров): расхождения10-inventarizaciya.png
+
+
+
+
+
+ 🖥 Остатки после складских операций10-ostatki-sklad.png
+
+
+
+
+
+ 📱 Инвентаризация с телефона (сканер)10-mob-inventarizaciya.png
+
+step11_reports
+
+
+
+
+ 🖥 Отчёт: продажи за день (выручка)11-otchet-prodazhi.png
+
+
+
+
+
+ 🖥 Отчёт: прибыль (выручка − себестоимость)11-otchet-pribyl.png
+
+
+
+
+
+ 🖥 Отчёт: остатки на дату11-otchet-ostatki.png
+
+
+
+
+
+ 🖥 Отчёт «Деньги»: остатки по счетам11-otchet-dengi.png
+
+
+
+
+
+ 🖥 Отчёт: долги поставщикам11-otchet-dolgi.png
+
+step12_invariants
+
+
+
+
+ 🖥 Движения склада (остаток ≡ Σ движений)12-dvizheniya-sklada.png
+
+step13_cancel_rollback
+
+
+
+
+ 🖥 Отмена платежа → долг вернулся13-otkat-dolg-vernulsya.png
+
+step14_finalize
+
+
+
+
+ 🖥 Итоговый дашборд магазина после полного дня14-itog-dashboard.png
+
+
\ No newline at end of file
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/01-vhod-dashboard.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/01-vhod-dashboard.png
new file mode 100644
index 0000000..67aa602
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/01-vhod-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02-postavshchik.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02-postavshchik.png
new file mode 100644
index 0000000..116e1fc
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02-postavshchik.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02-tovar-kar_tochka.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02-tovar-kar_tochka.png
new file mode 100644
index 0000000..09f2fa8
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02-tovar-kar_tochka.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02-tovary-spisok.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02-tovary-spisok.png
new file mode 100644
index 0000000..5860270
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02-tovary-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02a-kabinet-kassira.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02a-kabinet-kassira.png
new file mode 100644
index 0000000..9d28da9
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02a-kabinet-kassira.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02a-kassir-pryamoy-url.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02a-kassir-pryamoy-url.png
new file mode 100644
index 0000000..176e7c4
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02a-kassir-pryamoy-url.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02a-sotrudniki.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02a-sotrudniki.png
new file mode 100644
index 0000000..c72cf82
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02a-sotrudniki.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02a-tochki-prodazh.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02a-tochki-prodazh.png
new file mode 100644
index 0000000..51c22db
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/02a-tochki-prodazh.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/03-scheta.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/03-scheta.png
new file mode 100644
index 0000000..5cbe57e
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/03-scheta.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/04-dolg-nachalnyy.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/04-dolg-nachalnyy.png
new file mode 100644
index 0000000..7dd54a3
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/04-dolg-nachalnyy.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/05-priemka1-forma.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/05-priemka1-forma.png
new file mode 100644
index 0000000..b9e48a5
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/05-priemka1-forma.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/05-priemka1-provedena.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/05-priemka1-provedena.png
new file mode 100644
index 0000000..1be0299
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/05-priemka1-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/05-priemka1-spisok.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/05-priemka1-spisok.png
new file mode 100644
index 0000000..0bd8dce
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/05-priemka1-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/06-nakladnye-spisok.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/06-nakladnye-spisok.png
new file mode 100644
index 0000000..6a9851c
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/06-nakladnye-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/06-priemka2-provedena.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/06-priemka2-provedena.png
new file mode 100644
index 0000000..67c5b6d
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/06-priemka2-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/07-foto-nakladnaya-razobrana.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/07-foto-nakladnaya-razobrana.png
new file mode 100644
index 0000000..d957f02
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/07-foto-nakladnaya-razobrana.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/07-mob-foto-priemka.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/07-mob-foto-priemka.png
new file mode 100644
index 0000000..33dd662
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/07-mob-foto-priemka.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/07-priemka3-provedena.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/07-priemka3-provedena.png
new file mode 100644
index 0000000..7786d2b
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/07-priemka3-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/08-dolg-posle-oplat.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/08-dolg-posle-oplat.png
new file mode 100644
index 0000000..45fb720
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/08-dolg-posle-oplat.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/08-platezhi.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/08-platezhi.png
new file mode 100644
index 0000000..c5156df
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/08-platezhi.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/09-cheki-prodazhi.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/09-cheki-prodazhi.png
new file mode 100644
index 0000000..4f103f1
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/09-cheki-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/09-smena-zakryta-z.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/09-smena-zakryta-z.png
new file mode 100644
index 0000000..e421d64
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/09-smena-zakryta-z.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/09-smeny-spisok.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/09-smeny-spisok.png
new file mode 100644
index 0000000..0834a0e
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/09-smeny-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/09a-parallelnye-smeny.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/09a-parallelnye-smeny.png
new file mode 100644
index 0000000..e46f7b3
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/09a-parallelnye-smeny.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-inventarizaciya.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-inventarizaciya.png
new file mode 100644
index 0000000..aeb978d
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-mob-inventarizaciya.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-mob-inventarizaciya.png
new file mode 100644
index 0000000..f2528cd
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-mob-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-oprihodovanie.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-oprihodovanie.png
new file mode 100644
index 0000000..364285f
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-oprihodovanie.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-ostatki-sklad.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-ostatki-sklad.png
new file mode 100644
index 0000000..7f84f57
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-ostatki-sklad.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-spisanie-braka.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-spisanie-braka.png
new file mode 100644
index 0000000..06d7fac
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/10-spisanie-braka.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-dengi.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-dengi.png
new file mode 100644
index 0000000..5e3530a
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-dengi.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-dolgi.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-dolgi.png
new file mode 100644
index 0000000..45fb720
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-dolgi.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-ostatki.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-ostatki.png
new file mode 100644
index 0000000..16a5a78
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-ostatki.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-pribyl.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-pribyl.png
new file mode 100644
index 0000000..2e8b7fe
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-pribyl.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-prodazhi.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-prodazhi.png
new file mode 100644
index 0000000..ba4bc83
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/11-otchet-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/12-dvizheniya-sklada.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/12-dvizheniya-sklada.png
new file mode 100644
index 0000000..8639197
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/12-dvizheniya-sklada.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/13-otkat-dolg-vernulsya.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/13-otkat-dolg-vernulsya.png
new file mode 100644
index 0000000..45fb720
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/13-otkat-dolg-vernulsya.png differ
diff --git a/tests/e2e/reports/full-chain-uicheck-012558/screenshots/14-itog-dashboard.png b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/14-itog-dashboard.png
new file mode 100644
index 0000000..d272eee
Binary files /dev/null and b/tests/e2e/reports/full-chain-uicheck-012558/screenshots/14-itog-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857.md b/tests/e2e/reports/full-chain-uigreen-012857.md
new file mode 100644
index 0000000..986059f
--- /dev/null
+++ b/tests/e2e/reports/full-chain-uigreen-012857.md
@@ -0,0 +1,493 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T20:29:02.179Z
+Длительность: 132.3с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 5489мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| ui | Кабинет владельца открылся без ошибок (0 console/5xx/тостов) | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Вход владельца → дашборд](full-chain-uigreen-012857/screenshots/01-vhod-dashboard.png)
+
+
+
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 7450мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+| ui | Экран «Каталог: 5 товаров с ценами и штрихкодами»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Карточка товара: цена продажи и штрихкод»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Справочник контрагентов: поставщик (БИН, телефон)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Каталог: 5 товаров с ценами и штрихкодами](full-chain-uigreen-012857/screenshots/02-tovary-spisok.png)
+
+
+
+[Карточка товара: цена продажи и штрихкод](full-chain-uigreen-012857/screenshots/02-tovar-kar_tochka.png)
+
+
+
+[Справочник контрагентов: поставщик (БИН, телефон)](full-chain-uigreen-012857/screenshots/02-postavshchik.png)
+
+
+
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 18589мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791404942179 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791404942179 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| ui | Кассир: в меню нет модуля «Деньги» (счета/платежи/долги) | ✓ ожид=нет факт=нет |
+| ui | Кассир: в меню есть своя касса (/money/shifts) | ✓ ожид=есть факт=есть |
+| ui | Кассир: в меню нет «Настройки» | ✓ ожид=нет /settings факт=нет |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+| ui | Экран «Сотрудники: кассир, кладовщик, администратор (роли)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Точки продаж (2 кассы)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Кабинет кассира (ограниченное меню)](full-chain-uigreen-012857/screenshots/02a-kabinet-kassira.png)
+
+
+
+[Кассир: прямой URL /money/accounts не открывает данные](full-chain-uigreen-012857/screenshots/02a-kassir-pryamoy-url.png)
+
+
+
+[Сотрудники: кассир, кладовщик, администратор (роли)](full-chain-uigreen-012857/screenshots/02a-sotrudniki.png)
+
+
+
+[Точки продаж (2 кассы)](full-chain-uigreen-012857/screenshots/02a-tochki-prodazh.png)
+
+
+
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 2693мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+| ui | Экран «Счета: касса, банк (номер), эквайринг — начальные остатки»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Счета: касса, банк (номер), эквайринг — начальные остатки](full-chain-uigreen-012857/screenshots/03-scheta.png)
+
+
+
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 2269мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+| ui | Экран «Долги поставщикам: начальный долг 100 000 ₸»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Долги поставщикам: начальный долг 100 000 ₸](full-chain-uigreen-012857/screenshots/04-dolg-nachalnyy.png)
+
+
+
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 7710мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 56d05341… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток f8ffb806… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 49fc34e8… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток e33e66f4… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 725db2c1… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+| ui | Экран «Приёмка №1: форма создания (до проведения)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Список приёмок»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №1: проведена, строки и себестоимость»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Приёмка №1: форма создания (до проведения)](full-chain-uigreen-012857/screenshots/05-priemka1-forma.png)
+
+
+
+[Список приёмок](full-chain-uigreen-012857/screenshots/05-priemka1-spisok.png)
+
+
+
+[Приёмка №1: проведена, строки и себестоимость](full-chain-uigreen-012857/screenshots/05-priemka1-provedena.png)
+
+
+
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 8447мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914049 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914049 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914049 +9 | ✓ ожид=9 факт=9 |
+| ui | Экран «Загруженные накладные (табличная разобрана)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №2: «Поставщик не указан», проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Загруженные накладные (табличная разобрана)](full-chain-uigreen-012857/screenshots/06-nakladnye-spisok.png)
+
+
+
+[Приёмка №2: «Поставщик не указан», проведена](full-chain-uigreen-012857/screenshots/06-priemka2-provedena.png)
+
+
+
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 28729мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+| ui | Экран «Фото-накладная: распознана (OCR) и сопоставлена вручную»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №3 (по фото): проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Фото-накладная: распознана (OCR) и сопоставлена вручную](full-chain-uigreen-012857/screenshots/07-foto-nakladnaya-razobrana.png)
+
+
+
+[Приёмка №3 (по фото): проведена](full-chain-uigreen-012857/screenshots/07-priemka3-provedena.png)
+
+
+
+[Фото-приёмка с телефона (моб.)](full-chain-uigreen-012857/screenshots/07-mob-foto-priemka.png)
+
+
+
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 4769мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+| ui | Экран «Платежи поставщикам: нал из кассы + с банка»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Долги поставщикам после оплат (= формуле)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Платежи поставщикам: нал из кассы + с банка](full-chain-uigreen-012857/screenshots/08-platezhi.png)
+
+
+
+[Долги поставщикам после оплат (= формуле)](full-chain-uigreen-012857/screenshots/08-dolg-posle-oplat.png)
+
+
+
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 10251мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+| ui | Экран «Смены кассы: открытие/закрытие, размен»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Закрытая смена: должно быть / факт / разница (Z-отчёт)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Чеки продаж (наличные/карта/смешанная) и возврат»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Смены кассы: открытие/закрытие, размен](full-chain-uigreen-012857/screenshots/09-smeny-spisok.png)
+
+
+
+[Закрытая смена: должно быть / факт / разница (Z-отчёт)](full-chain-uigreen-012857/screenshots/09-smena-zakryta-z.png)
+
+
+
+[Чеки продаж (наличные/карта/смешанная) и возврат](full-chain-uigreen-012857/screenshots/09-cheki-prodazhi.png)
+
+
+
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 5155мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+| ui | Экран «Параллельные смены на точках 1 и 2 (деньги раздельны)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Параллельные смены на точках 1 и 2 (деньги раздельны)](full-chain-uigreen-012857/screenshots/09a-parallelnye-smeny.png)
+
+
+
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 10982мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+| ui | Экран «Оприходование излишка (+8)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Списание брака (−2)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Инвентаризация (часть товаров): расхождения»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Остатки после складских операций»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Оприходование излишка (+8)](full-chain-uigreen-012857/screenshots/10-oprihodovanie.png)
+
+
+
+[Списание брака (−2)](full-chain-uigreen-012857/screenshots/10-spisanie-braka.png)
+
+
+
+[Инвентаризация (часть товаров): расхождения](full-chain-uigreen-012857/screenshots/10-inventarizaciya.png)
+
+
+
+[Остатки после складских операций](full-chain-uigreen-012857/screenshots/10-ostatki-sklad.png)
+
+
+
+[Инвентаризация с телефона (сканер) (моб.)](full-chain-uigreen-012857/screenshots/10-mob-inventarizaciya.png)
+
+
+
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 10044мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| ui | Экран «Отчёт: продажи за день (выручка)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: прибыль (выручка − себестоимость)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: остатки на дату»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт «Деньги»: остатки по счетам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: долги поставщикам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отчёт: продажи за день (выручка)](full-chain-uigreen-012857/screenshots/11-otchet-prodazhi.png)
+
+
+
+[Отчёт: прибыль (выручка − себестоимость)](full-chain-uigreen-012857/screenshots/11-otchet-pribyl.png)
+
+
+
+[Отчёт: остатки на дату](full-chain-uigreen-012857/screenshots/11-otchet-ostatki.png)
+
+
+
+[Отчёт «Деньги»: остатки по счетам](full-chain-uigreen-012857/screenshots/11-otchet-dengi.png)
+
+
+
+[Отчёт: долги поставщикам](full-chain-uigreen-012857/screenshots/11-otchet-dolgi.png)
+
+
+
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 5430мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914049 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140494 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+| ui | Экран «Движения склада (остаток ≡ Σ движений)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Движения склада (остаток ≡ Σ движений)](full-chain-uigreen-012857/screenshots/12-dvizheniya-sklada.png)
+
+
+
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 2411мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+| ui | Экран «Отмена платежа → долг вернулся»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отмена платежа → долг вернулся](full-chain-uigreen-012857/screenshots/13-otkat-dolg-vernulsya.png)
+
+
+
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1879мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Финальный дашборд без ошибок | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Галерея index.html собрана (37 кадров) | ✓ ожид=index.html факт=37 |
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+Скриншоты процесса:
+
+[Итоговый дашборд](full-chain-uigreen-012857/screenshots/14-itog-dashboard.png)
+
+
+
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Галерея скриншотов: /home/nns/food-market/tests/e2e/reports/full-chain-uigreen-012857/index.html
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/index.html b/tests/e2e/reports/full-chain-uigreen-012857/index.html
new file mode 100644
index 0000000..8a83b56
--- /dev/null
+++ b/tests/e2e/reports/full-chain-uigreen-012857/index.html
@@ -0,0 +1,255 @@
+
+
+Full-chain e2e — скриншоты процессов (temp-орг (C))
+
+
+step01_register_and_login
+
+
+
+
+ 🖥 Вход владельца → дашборд организации01-vhod-dashboard.png
+
+step02_catalog_and_supplier
+
+
+
+
+ 🖥 Каталог: 5 товаров с ценами и штрихкодами02-tovary-spisok.png
+
+
+
+
+
+ 🖥 Карточка товара: цена продажи и штрихкод02-tovar-kar_tochka.png
+
+
+
+
+
+ 🖥 Справочник контрагентов: поставщик (БИН, телефон)02-postavshchik.png
+
+step02a_employees_and_points
+
+
+
+
+ 🖥 Кабинет кассира: без «Деньги»/«Настроек»02a-kabinet-kassira.png
+
+
+
+
+
+ 🖥 Кассир по прямому URL /money/accounts — нет данных02a-kassir-pryamoy-url.png
+
+
+
+
+
+ 🖥 Сотрудники: кассир, кладовщик, администратор (роли)02a-sotrudniki.png
+
+
+
+
+
+ 🖥 Точки продаж (2 кассы)02a-tochki-prodazh.png
+
+step03_money_accounts
+
+
+
+
+ 🖥 Счета: касса, банк (номер), эквайринг — начальные остатки03-scheta.png
+
+step04_initial_supplier_debt
+
+
+
+
+ 🖥 Долги поставщикам: начальный долг 100 000 ₸04-dolg-nachalnyy.png
+
+step05_supply1_manual
+
+
+
+
+ 🖥 Приёмка №1: форма создания (до проведения)05-priemka1-forma.png
+
+
+
+
+
+ 🖥 Список приёмок05-priemka1-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №1: проведена, строки и себестоимость05-priemka1-provedena.png
+
+step06_supply2_excel
+
+
+
+
+ 🖥 Загруженные накладные (табличная разобрана)06-nakladnye-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №2: «Поставщик не указан», проведена06-priemka2-provedena.png
+
+step07_supply3_photo
+
+
+
+
+ 🖥 Фото-накладная: распознана (OCR) и сопоставлена вручную07-foto-nakladnaya-razobrana.png
+
+
+
+
+
+ 🖥 Приёмка №3 (по фото): проведена07-priemka3-provedena.png
+
+
+
+
+
+ 📱 Фото-приёмка с телефона07-mob-foto-priemka.png
+
+step08_supplier_payments
+
+
+
+
+ 🖥 Платежи поставщикам: нал из кассы + с банка08-platezhi.png
+
+
+
+
+
+ 🖥 Долги поставщикам после оплат (= формуле)08-dolg-posle-oplat.png
+
+step09_cashier_shift
+
+
+
+
+ 🖥 Смены кассы: открытие/закрытие, размен09-smeny-spisok.png
+
+
+
+
+
+ 🖥 Закрытая смена: должно быть / факт / разница (Z-отчёт)09-smena-zakryta-z.png
+
+
+
+
+
+ 🖥 Чеки продаж (наличные/карта/смешанная) и возврат09-cheki-prodazhi.png
+
+step09a_points_binding
+
+
+
+
+ 🖥 Параллельные смены на точках 1 и 2 (деньги раздельны)09a-parallelnye-smeny.png
+
+step10_warehouse_ops
+
+
+
+
+ 🖥 Оприходование излишка (+8)10-oprihodovanie.png
+
+
+
+
+
+ 🖥 Списание брака (−2)10-spisanie-braka.png
+
+
+
+
+
+ 🖥 Инвентаризация (часть товаров): расхождения10-inventarizaciya.png
+
+
+
+
+
+ 🖥 Остатки после складских операций10-ostatki-sklad.png
+
+
+
+
+
+ 📱 Инвентаризация с телефона (сканер)10-mob-inventarizaciya.png
+
+step11_reports
+
+
+
+
+ 🖥 Отчёт: продажи за день (выручка)11-otchet-prodazhi.png
+
+
+
+
+
+ 🖥 Отчёт: прибыль (выручка − себестоимость)11-otchet-pribyl.png
+
+
+
+
+
+ 🖥 Отчёт: остатки на дату11-otchet-ostatki.png
+
+
+
+
+
+ 🖥 Отчёт «Деньги»: остатки по счетам11-otchet-dengi.png
+
+
+
+
+
+ 🖥 Отчёт: долги поставщикам11-otchet-dolgi.png
+
+step12_invariants
+
+
+
+
+ 🖥 Движения склада (остаток ≡ Σ движений)12-dvizheniya-sklada.png
+
+step13_cancel_rollback
+
+
+
+
+ 🖥 Отмена платежа → долг вернулся13-otkat-dolg-vernulsya.png
+
+step14_finalize
+
+
+
+
+ 🖥 Итоговый дашборд магазина после полного дня14-itog-dashboard.png
+
+
\ No newline at end of file
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/01-vhod-dashboard.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/01-vhod-dashboard.png
new file mode 100644
index 0000000..e5afb32
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/01-vhod-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02-postavshchik.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02-postavshchik.png
new file mode 100644
index 0000000..974e2c0
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02-postavshchik.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02-tovar-kar_tochka.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02-tovar-kar_tochka.png
new file mode 100644
index 0000000..9e0e628
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02-tovar-kar_tochka.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02-tovary-spisok.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02-tovary-spisok.png
new file mode 100644
index 0000000..8c4d321
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02-tovary-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02a-kabinet-kassira.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02a-kabinet-kassira.png
new file mode 100644
index 0000000..9bbbdc9
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02a-kabinet-kassira.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02a-kassir-pryamoy-url.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02a-kassir-pryamoy-url.png
new file mode 100644
index 0000000..a38a8de
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02a-kassir-pryamoy-url.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02a-sotrudniki.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02a-sotrudniki.png
new file mode 100644
index 0000000..d4d3ef0
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02a-sotrudniki.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02a-tochki-prodazh.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02a-tochki-prodazh.png
new file mode 100644
index 0000000..ac80ee0
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/02a-tochki-prodazh.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/03-scheta.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/03-scheta.png
new file mode 100644
index 0000000..1bba55e
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/03-scheta.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/04-dolg-nachalnyy.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/04-dolg-nachalnyy.png
new file mode 100644
index 0000000..8882bd8
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/04-dolg-nachalnyy.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/05-priemka1-forma.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/05-priemka1-forma.png
new file mode 100644
index 0000000..d1af07c
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/05-priemka1-forma.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/05-priemka1-provedena.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/05-priemka1-provedena.png
new file mode 100644
index 0000000..ba942c9
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/05-priemka1-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/05-priemka1-spisok.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/05-priemka1-spisok.png
new file mode 100644
index 0000000..bb1b609
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/05-priemka1-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/06-nakladnye-spisok.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/06-nakladnye-spisok.png
new file mode 100644
index 0000000..d277091
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/06-nakladnye-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/06-priemka2-provedena.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/06-priemka2-provedena.png
new file mode 100644
index 0000000..d7952f6
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/06-priemka2-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/07-foto-nakladnaya-razobrana.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/07-foto-nakladnaya-razobrana.png
new file mode 100644
index 0000000..30d18e3
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/07-foto-nakladnaya-razobrana.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/07-mob-foto-priemka.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/07-mob-foto-priemka.png
new file mode 100644
index 0000000..9eac9bc
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/07-mob-foto-priemka.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/07-priemka3-provedena.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/07-priemka3-provedena.png
new file mode 100644
index 0000000..06a4c69
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/07-priemka3-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/08-dolg-posle-oplat.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/08-dolg-posle-oplat.png
new file mode 100644
index 0000000..320e3ec
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/08-dolg-posle-oplat.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/08-platezhi.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/08-platezhi.png
new file mode 100644
index 0000000..1df8308
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/08-platezhi.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/09-cheki-prodazhi.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/09-cheki-prodazhi.png
new file mode 100644
index 0000000..bfddcbb
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/09-cheki-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/09-smena-zakryta-z.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/09-smena-zakryta-z.png
new file mode 100644
index 0000000..674cffe
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/09-smena-zakryta-z.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/09-smeny-spisok.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/09-smeny-spisok.png
new file mode 100644
index 0000000..aad9c47
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/09-smeny-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/09a-parallelnye-smeny.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/09a-parallelnye-smeny.png
new file mode 100644
index 0000000..6f88417
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/09a-parallelnye-smeny.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-inventarizaciya.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-inventarizaciya.png
new file mode 100644
index 0000000..7ed7e06
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-mob-inventarizaciya.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-mob-inventarizaciya.png
new file mode 100644
index 0000000..f2528cd
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-mob-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-oprihodovanie.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-oprihodovanie.png
new file mode 100644
index 0000000..dd348db
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-oprihodovanie.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-ostatki-sklad.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-ostatki-sklad.png
new file mode 100644
index 0000000..23ea64a
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-ostatki-sklad.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-spisanie-braka.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-spisanie-braka.png
new file mode 100644
index 0000000..e013256
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/10-spisanie-braka.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-dengi.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-dengi.png
new file mode 100644
index 0000000..55b55e3
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-dengi.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-dolgi.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-dolgi.png
new file mode 100644
index 0000000..320e3ec
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-dolgi.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-ostatki.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-ostatki.png
new file mode 100644
index 0000000..efffdd4
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-ostatki.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-pribyl.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-pribyl.png
new file mode 100644
index 0000000..8334299
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-pribyl.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-prodazhi.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-prodazhi.png
new file mode 100644
index 0000000..7c57129
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/11-otchet-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/12-dvizheniya-sklada.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/12-dvizheniya-sklada.png
new file mode 100644
index 0000000..94d1bee
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/12-dvizheniya-sklada.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/13-otkat-dolg-vernulsya.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/13-otkat-dolg-vernulsya.png
new file mode 100644
index 0000000..320e3ec
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/13-otkat-dolg-vernulsya.png differ
diff --git a/tests/e2e/reports/full-chain-uigreen-012857/screenshots/14-itog-dashboard.png b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/14-itog-dashboard.png
new file mode 100644
index 0000000..ab32550
Binary files /dev/null and b/tests/e2e/reports/full-chain-uigreen-012857/screenshots/14-itog-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642.md b/tests/e2e/reports/full-chain-validate-005642.md
new file mode 100644
index 0000000..b5ae252
--- /dev/null
+++ b/tests/e2e/reports/full-chain-validate-005642.md
@@ -0,0 +1,474 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T19:56:48.475Z
+Длительность: 117.5с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 5694мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| ui | Кабинет владельца открылся без ошибок (0 console/5xx/тостов) | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Вход владельца → дашборд](full-chain-validate-005642/screenshots/01-vhod-dashboard.png)
+
+
+
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 7319мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+| ui | Экран «Каталог: 5 товаров с ценами и штрихкодами»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Карточка товара: цена продажи и штрихкод»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Справочник контрагентов: поставщик (БИН, телефон)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Каталог: 5 товаров с ценами и штрихкодами](full-chain-validate-005642/screenshots/02-tovary-spisok.png)
+
+
+
+[Карточка товара: цена продажи и штрихкод](full-chain-validate-005642/screenshots/02-tovar-kar_tochka.png)
+
+
+
+[Справочник контрагентов: поставщик (БИН, телефон)](full-chain-validate-005642/screenshots/02-postavshchik.png)
+
+
+
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 9064мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791403008474 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791403008474 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| ui | Экран «Сотрудники: кассир, кладовщик, администратор (роли)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Точки продаж (2 кассы)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Сотрудники: кассир, кладовщик, администратор (роли)](full-chain-validate-005642/screenshots/02a-sotrudniki.png)
+
+
+
+[Точки продаж (2 кассы)](full-chain-validate-005642/screenshots/02a-tochki-prodazh.png)
+
+
+
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 2618мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+| ui | Экран «Счета: касса, банк (номер), эквайринг — начальные остатки»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Счета: касса, банк (номер), эквайринг — начальные остатки](full-chain-validate-005642/screenshots/03-scheta.png)
+
+
+
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 2215мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+| ui | Экран «Долги поставщикам: начальный долг 100 000 ₸»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Долги поставщикам: начальный долг 100 000 ₸](full-chain-validate-005642/screenshots/04-dolg-nachalnyy.png)
+
+
+
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 7665мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток b02bf3f8… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 6fade8ff… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток bc721f36… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 654d87ca… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток e358c44d… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+| ui | Экран «Приёмка №1: форма создания (до проведения)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Список приёмок»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №1: проведена, строки и себестоимость»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Приёмка №1: форма создания (до проведения)](full-chain-validate-005642/screenshots/05-priemka1-forma.png)
+
+
+
+[Список приёмок](full-chain-validate-005642/screenshots/05-priemka1-spisok.png)
+
+
+
+[Приёмка №1: проведена, строки и себестоимость](full-chain-validate-005642/screenshots/05-priemka1-provedena.png)
+
+
+
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 8125мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914030 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914030 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914030 +9 | ✓ ожид=9 факт=9 |
+| ui | Экран «Загруженные накладные (табличная разобрана)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №2: «Поставщик не указан», проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Загруженные накладные (табличная разобрана)](full-chain-validate-005642/screenshots/06-nakladnye-spisok.png)
+
+
+
+[Приёмка №2: «Поставщик не указан», проведена](full-chain-validate-005642/screenshots/06-priemka2-provedena.png)
+
+
+
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 25921мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Фото-накладная распознана (OCR, needs_review) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+| ui | Экран «Фото-накладная: распознана (OCR) и сопоставлена вручную»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Приёмка №3 (по фото): проведена»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Фото-накладная: распознана (OCR) и сопоставлена вручную](full-chain-validate-005642/screenshots/07-foto-nakladnaya-razobrana.png)
+
+
+
+[Приёмка №3 (по фото): проведена](full-chain-validate-005642/screenshots/07-priemka3-provedena.png)
+
+
+
+[Фото-приёмка с телефона (моб.)](full-chain-validate-005642/screenshots/07-mob-foto-priemka.png)
+
+
+
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 4674мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы | ✓ ожид=204 факт=201 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=33900 факт=33900 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=177130 факт=177130 |
+| ui | Экран «Платежи поставщикам: нал из кассы + с банка»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Долги поставщикам после оплат (= формуле)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Платежи поставщикам: нал из кассы + с банка](full-chain-validate-005642/screenshots/08-platezhi.png)
+
+
+
+[Долги поставщикам после оплат (= формуле)](full-chain-validate-005642/screenshots/08-dolg-posle-oplat.png)
+
+
+
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 10166мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+| ui | Экран «Смены кассы: открытие/закрытие, размен»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Закрытая смена: должно быть / факт / разница (Z-отчёт)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Чеки продаж (наличные/карта/смешанная) и возврат»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Смены кассы: открытие/закрытие, размен](full-chain-validate-005642/screenshots/09-smeny-spisok.png)
+
+
+
+[Закрытая смена: должно быть / факт / разница (Z-отчёт)](full-chain-validate-005642/screenshots/09-smena-zakryta-z.png)
+
+
+
+[Чеки продаж (наличные/карта/смешанная) и возврат](full-chain-validate-005642/screenshots/09-cheki-prodazhi.png)
+
+
+
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 4367мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+| ui | Экран «Параллельные смены на точках 1 и 2 (деньги раздельны)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Параллельные смены на точках 1 и 2 (деньги раздельны)](full-chain-validate-005642/screenshots/09a-parallelnye-smeny.png)
+
+
+
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 10209мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=53 факт=53 |
+| ui | Экран «Оприходование излишка (+8)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Списание брака (−2)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Инвентаризация (часть товаров): расхождения»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Остатки после складских операций»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Оприходование излишка (+8)](full-chain-validate-005642/screenshots/10-oprihodovanie.png)
+
+
+
+[Списание брака (−2)](full-chain-validate-005642/screenshots/10-spisanie-braka.png)
+
+
+
+[Инвентаризация (часть товаров): расхождения](full-chain-validate-005642/screenshots/10-inventarizaciya.png)
+
+
+
+[Остатки после складских операций](full-chain-validate-005642/screenshots/10-ostatki-sklad.png)
+
+
+
+[Инвентаризация с телефона (сканер) (моб.)](full-chain-validate-005642/screenshots/10-mob-inventarizaciya.png)
+
+
+
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 9382мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплата наличными | ✓ ожид=16100 факт=16100 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по точкам доступен | ✓ ожид=200 факт=200 |
+| api | Отчёт продаж по кассирам доступен | ✓ ожид=200 факт=200 |
+| ui | Экран «Отчёт: продажи за день (выручка)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: прибыль (выручка − себестоимость)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: остатки на дату»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт «Деньги»: остатки по счетам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Экран «Отчёт: долги поставщикам»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отчёт: продажи за день (выручка)](full-chain-validate-005642/screenshots/11-otchet-prodazhi.png)
+
+
+
+[Отчёт: прибыль (выручка − себестоимость)](full-chain-validate-005642/screenshots/11-otchet-pribyl.png)
+
+
+
+[Отчёт: остатки на дату](full-chain-validate-005642/screenshots/11-otchet-ostatki.png)
+
+
+
+[Отчёт «Деньги»: остатки по счетам](full-chain-validate-005642/screenshots/11-otchet-dengi.png)
+
+
+
+[Отчёт: долги поставщикам](full-chain-validate-005642/screenshots/11-otchet-dolgi.png)
+
+
+
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 5792мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179140 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179140 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179140 | ✓ ожид=53 факт=53 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179140 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179140 | ✓ ожид=38 факт=38 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса fc17914030 | ✓ ожид=16100 факт=16100 |
+| api | Инвариант счёт≡начальный+Σопераций: Касса-2 fc179140 | ✓ ожид=3000 факт=3000 |
+| api | Инвариант счёт≡начальный+Σопераций: Банк fc179140300 | ✓ ожид=191360 факт=191360 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг fc1791 | ✓ ожид=0 факт=0 |
+| api | Инвариант счёт≡начальный+Σопераций: Эквайринг-2 fc17 | ✓ ожид=0 факт=0 |
+| api | Инвариант долг≡формуле | ✓ ожид=177130 факт=177130 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+| ui | Экран «Движения склада (остаток ≡ Σ движений)»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Движения склада (остаток ≡ Σ движений)](full-chain-validate-005642/screenshots/12-dvizheniya-sklada.png)
+
+
+
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 2509мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+| ui | Экран «Отмена платежа → долг вернулся»: 0 console/5xx/тостов | ✓ ожид=0 ошибок факт=0 ошибок |
+
+Скриншоты процесса:
+
+[Отмена платежа → долг вернулся](full-chain-validate-005642/screenshots/13-otkat-dolg-vernulsya.png)
+
+
+
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1815мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Финальный дашборд без ошибок | ✓ ожид=0 ошибок факт=0 ошибок |
+| ui | Галерея index.html собрана (35 кадров) | ✓ ожид=index.html факт=35 |
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+Скриншоты процесса:
+
+[Итоговый дашборд](full-chain-validate-005642/screenshots/14-itog-dashboard.png)
+
+
+
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Галерея скриншотов: /home/nns/food-market/tests/e2e/reports/full-chain-validate-005642/index.html
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-validate-005642/index.html b/tests/e2e/reports/full-chain-validate-005642/index.html
new file mode 100644
index 0000000..d0aff91
--- /dev/null
+++ b/tests/e2e/reports/full-chain-validate-005642/index.html
@@ -0,0 +1,243 @@
+
+
+Full-chain e2e — скриншоты процессов (temp-орг (C))
+
+
+step01_register_and_login
+
+
+
+
+ 🖥 Вход владельца → дашборд организации01-vhod-dashboard.png
+
+step02_catalog_and_supplier
+
+
+
+
+ 🖥 Каталог: 5 товаров с ценами и штрихкодами02-tovary-spisok.png
+
+
+
+
+
+ 🖥 Карточка товара: цена продажи и штрихкод02-tovar-kar_tochka.png
+
+
+
+
+
+ 🖥 Справочник контрагентов: поставщик (БИН, телефон)02-postavshchik.png
+
+step02a_employees_and_points
+
+
+
+
+ 🖥 Сотрудники: кассир, кладовщик, администратор (роли)02a-sotrudniki.png
+
+
+
+
+
+ 🖥 Точки продаж (2 кассы)02a-tochki-prodazh.png
+
+step03_money_accounts
+
+
+
+
+ 🖥 Счета: касса, банк (номер), эквайринг — начальные остатки03-scheta.png
+
+step04_initial_supplier_debt
+
+
+
+
+ 🖥 Долги поставщикам: начальный долг 100 000 ₸04-dolg-nachalnyy.png
+
+step05_supply1_manual
+
+
+
+
+ 🖥 Приёмка №1: форма создания (до проведения)05-priemka1-forma.png
+
+
+
+
+
+ 🖥 Список приёмок05-priemka1-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №1: проведена, строки и себестоимость05-priemka1-provedena.png
+
+step06_supply2_excel
+
+
+
+
+ 🖥 Загруженные накладные (табличная разобрана)06-nakladnye-spisok.png
+
+
+
+
+
+ 🖥 Приёмка №2: «Поставщик не указан», проведена06-priemka2-provedena.png
+
+step07_supply3_photo
+
+
+
+
+ 🖥 Фото-накладная: распознана (OCR) и сопоставлена вручную07-foto-nakladnaya-razobrana.png
+
+
+
+
+
+ 🖥 Приёмка №3 (по фото): проведена07-priemka3-provedena.png
+
+
+
+
+
+ 📱 Фото-приёмка с телефона07-mob-foto-priemka.png
+
+step08_supplier_payments
+
+
+
+
+ 🖥 Платежи поставщикам: нал из кассы + с банка08-platezhi.png
+
+
+
+
+
+ 🖥 Долги поставщикам после оплат (= формуле)08-dolg-posle-oplat.png
+
+step09_cashier_shift
+
+
+
+
+ 🖥 Смены кассы: открытие/закрытие, размен09-smeny-spisok.png
+
+
+
+
+
+ 🖥 Закрытая смена: должно быть / факт / разница (Z-отчёт)09-smena-zakryta-z.png
+
+
+
+
+
+ 🖥 Чеки продаж (наличные/карта/смешанная) и возврат09-cheki-prodazhi.png
+
+step09a_points_binding
+
+
+
+
+ 🖥 Параллельные смены на точках 1 и 2 (деньги раздельны)09a-parallelnye-smeny.png
+
+step10_warehouse_ops
+
+
+
+
+ 🖥 Оприходование излишка (+8)10-oprihodovanie.png
+
+
+
+
+
+ 🖥 Списание брака (−2)10-spisanie-braka.png
+
+
+
+
+
+ 🖥 Инвентаризация (часть товаров): расхождения10-inventarizaciya.png
+
+
+
+
+
+ 🖥 Остатки после складских операций10-ostatki-sklad.png
+
+
+
+
+
+ 📱 Инвентаризация с телефона (сканер)10-mob-inventarizaciya.png
+
+step11_reports
+
+
+
+
+ 🖥 Отчёт: продажи за день (выручка)11-otchet-prodazhi.png
+
+
+
+
+
+ 🖥 Отчёт: прибыль (выручка − себестоимость)11-otchet-pribyl.png
+
+
+
+
+
+ 🖥 Отчёт: остатки на дату11-otchet-ostatki.png
+
+
+
+
+
+ 🖥 Отчёт «Деньги»: остатки по счетам11-otchet-dengi.png
+
+
+
+
+
+ 🖥 Отчёт: долги поставщикам11-otchet-dolgi.png
+
+step12_invariants
+
+
+
+
+ 🖥 Движения склада (остаток ≡ Σ движений)12-dvizheniya-sklada.png
+
+step13_cancel_rollback
+
+
+
+
+ 🖥 Отмена платежа → долг вернулся13-otkat-dolg-vernulsya.png
+
+step14_finalize
+
+
+
+
+ 🖥 Итоговый дашборд магазина после полного дня14-itog-dashboard.png
+
+
\ No newline at end of file
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/01-vhod-dashboard.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/01-vhod-dashboard.png
new file mode 100644
index 0000000..a2afc78
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/01-vhod-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/02-postavshchik.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/02-postavshchik.png
new file mode 100644
index 0000000..e9a51ae
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/02-postavshchik.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/02-tovar-kar_tochka.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/02-tovar-kar_tochka.png
new file mode 100644
index 0000000..d0ae2a0
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/02-tovar-kar_tochka.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/02-tovary-spisok.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/02-tovary-spisok.png
new file mode 100644
index 0000000..ecb3d8a
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/02-tovary-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/02a-sotrudniki.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/02a-sotrudniki.png
new file mode 100644
index 0000000..e80fae1
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/02a-sotrudniki.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/02a-tochki-prodazh.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/02a-tochki-prodazh.png
new file mode 100644
index 0000000..0d8856a
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/02a-tochki-prodazh.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/03-scheta.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/03-scheta.png
new file mode 100644
index 0000000..c7b83f8
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/03-scheta.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/04-dolg-nachalnyy.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/04-dolg-nachalnyy.png
new file mode 100644
index 0000000..69cd908
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/04-dolg-nachalnyy.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/05-priemka1-forma.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/05-priemka1-forma.png
new file mode 100644
index 0000000..3d46231
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/05-priemka1-forma.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/05-priemka1-provedena.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/05-priemka1-provedena.png
new file mode 100644
index 0000000..3f1d34f
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/05-priemka1-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/05-priemka1-spisok.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/05-priemka1-spisok.png
new file mode 100644
index 0000000..27292df
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/05-priemka1-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/06-nakladnye-spisok.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/06-nakladnye-spisok.png
new file mode 100644
index 0000000..953cd60
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/06-nakladnye-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/06-priemka2-provedena.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/06-priemka2-provedena.png
new file mode 100644
index 0000000..c0cf7c2
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/06-priemka2-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/07-foto-nakladnaya-razobrana.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/07-foto-nakladnaya-razobrana.png
new file mode 100644
index 0000000..bddcc6f
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/07-foto-nakladnaya-razobrana.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/07-mob-foto-priemka.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/07-mob-foto-priemka.png
new file mode 100644
index 0000000..97b4b05
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/07-mob-foto-priemka.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/07-priemka3-provedena.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/07-priemka3-provedena.png
new file mode 100644
index 0000000..1277f48
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/07-priemka3-provedena.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/08-dolg-posle-oplat.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/08-dolg-posle-oplat.png
new file mode 100644
index 0000000..e9417cb
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/08-dolg-posle-oplat.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/08-platezhi.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/08-platezhi.png
new file mode 100644
index 0000000..917e05b
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/08-platezhi.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/09-cheki-prodazhi.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/09-cheki-prodazhi.png
new file mode 100644
index 0000000..6d6e819
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/09-cheki-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/09-smena-zakryta-z.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/09-smena-zakryta-z.png
new file mode 100644
index 0000000..632da6f
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/09-smena-zakryta-z.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/09-smeny-spisok.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/09-smeny-spisok.png
new file mode 100644
index 0000000..b986a01
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/09-smeny-spisok.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/09a-parallelnye-smeny.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/09a-parallelnye-smeny.png
new file mode 100644
index 0000000..35aa86a
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/09a-parallelnye-smeny.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/10-inventarizaciya.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/10-inventarizaciya.png
new file mode 100644
index 0000000..efa2758
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/10-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/10-mob-inventarizaciya.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/10-mob-inventarizaciya.png
new file mode 100644
index 0000000..f2528cd
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/10-mob-inventarizaciya.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/10-oprihodovanie.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/10-oprihodovanie.png
new file mode 100644
index 0000000..0a6db94
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/10-oprihodovanie.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/10-ostatki-sklad.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/10-ostatki-sklad.png
new file mode 100644
index 0000000..659bf13
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/10-ostatki-sklad.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/10-spisanie-braka.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/10-spisanie-braka.png
new file mode 100644
index 0000000..d248f64
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/10-spisanie-braka.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-dengi.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-dengi.png
new file mode 100644
index 0000000..d8e73a0
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-dengi.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-dolgi.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-dolgi.png
new file mode 100644
index 0000000..e9417cb
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-dolgi.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-ostatki.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-ostatki.png
new file mode 100644
index 0000000..f3fc523
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-ostatki.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-pribyl.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-pribyl.png
new file mode 100644
index 0000000..7738a6c
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-pribyl.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-prodazhi.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-prodazhi.png
new file mode 100644
index 0000000..c06c076
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/11-otchet-prodazhi.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/12-dvizheniya-sklada.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/12-dvizheniya-sklada.png
new file mode 100644
index 0000000..f9c85f8
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/12-dvizheniya-sklada.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/13-otkat-dolg-vernulsya.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/13-otkat-dolg-vernulsya.png
new file mode 100644
index 0000000..e9417cb
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/13-otkat-dolg-vernulsya.png differ
diff --git a/tests/e2e/reports/full-chain-validate-005642/screenshots/14-itog-dashboard.png b/tests/e2e/reports/full-chain-validate-005642/screenshots/14-itog-dashboard.png
new file mode 100644
index 0000000..2705522
Binary files /dev/null and b/tests/e2e/reports/full-chain-validate-005642/screenshots/14-itog-dashboard.png differ
diff --git a/tests/e2e/reports/full-chain-watchdog-20261008.md b/tests/e2e/reports/full-chain-watchdog-20261008.md
new file mode 100644
index 0000000..92b629d
--- /dev/null
+++ b/tests/e2e/reports/full-chain-watchdog-20261008.md
@@ -0,0 +1,269 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-07T22:05:34.928Z
+Длительность: 67.0с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2471мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2856мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 8387мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791410734928 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791410734928 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1339мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 662мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 3468мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 21322e0f… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток e3ea29da… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток c6ffa0a0… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток 6a8d88e9… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток dc95123d… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 6259мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914107 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914107 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914107 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 20299мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 1634мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 5156мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → отказ (409) | ✓ ожид=409 факт=409 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 3291мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 5164мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1162мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 3949мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179141 | ✓ ожид=40.5 факт=40.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179141 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179141 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179141 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179141 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 884мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → отказ | ✓ ожид=4xx факт=409 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/full-chain-watchdog-20261009.md b/tests/e2e/reports/full-chain-watchdog-20261009.md
new file mode 100644
index 0000000..165ef39
--- /dev/null
+++ b/tests/e2e/reports/full-chain-watchdog-20261009.md
@@ -0,0 +1,284 @@
+# E2E report: full-chain
+
+Запущен: 2026-10-08T22:05:21.597Z
+Длительность: 65.6с
+
+**Итог:** 16 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 16)
+
+## ✓ Step step01_register_and_login: Регистрация организации → вход владельцем → простой режим (скрытые модули 403)
+
+Длительность: 2038мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Регистрация организации e2e-fullchain + вход владельцем | ✓ ожид=token факт=token |
+| api | /api/me: роль Admin | ✓ ожид=Admin факт=Admin |
+| api | Простой режим включён (advancedMode=false) | ✓ ожид=false факт=false |
+| api | Скрытый модуль недоступен: приёмка оптовых отгрузок (demands) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: перемещения (transfers) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: акции (promotions) | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+| api | Скрытый модуль недоступен: ABC-отчёт | ✓ ожид=403 advanced-mode-required факт=403 https://food-market.kz/errors/advanced-mode-required |
+
+## ✓ Step step02_catalog_and_supplier: Справочники — группа, 5 товаров (разные ед.изм., 1 весовой) + цены + штрихкоды; поставщик
+
+Длительность: 2138мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Валюта KZT в справочнике | ✓ ожид=KZT факт=есть |
+| api | Магазин (склад) существует | ✓ ожид=≥1 факт=1 |
+| api | Единицы измерения доступны (≥5 различных) | ✓ ожид=≥5 факт=5 |
+| api | Группа товаров создана | ✓ ожид=200+id факт=201 |
+| api | Создано 5 товаров (разные ед.изм.) | ✓ ожид=5 факт=5 |
+| api | Один товар весовой (дробное кол-во) | ✓ ожид=1 факт=1 |
+| api | Товар находится по штрихкоду | ✓ ожид=200 факт=200 |
+| api | Поставщик создан (БИН+телефон) | ✓ ожид=200+id факт=201 |
+
+## ✓ Step step02a_employees_and_points: Сотрудники (кассир/кладовщик/админ) + 2 точки продаж; права (API 403); правка/пароль/блокировка
+
+Длительность: 6977мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Штрихкоды EAN-13 с валидной контрольной цифрой | ✓ ожид=0 неверных факт=0/5 |
+| api | Системные роли Кассир/Кладовщик есть | ✓ ожид=есть факт=Администратор,Кладовщик,Кассир |
+| api | Точка продаж создана: Касса-1 fc1791497121596 | ✓ ожид=200+id факт=201 |
+| api | Точка продаж создана: Касса-2 fc1791497121596 | ✓ ожид=200+id факт=201 |
+| api | Точка 2: переименование + деактивация | ✓ ожид=200 факт=204 |
+| api | Точка 2: повторная активация | ✓ ожид=200 факт=204 |
+| api | Сотрудник создан: Кассир | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Кладовщик | ✓ ожид=200+пароль факт=ok |
+| api | Сотрудник создан: Администратор | ✓ ожид=200+пароль факт=ok |
+| api | Кассир → деньги (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → платежи (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → сотрудники/настройки (API) 403 | ✓ ожид=403 факт=403 |
+| api | Кассир → продажи доступны | ✓ ожид=200 факт=200 |
+| api | Кассир → свои смены доступны (касса) | ✓ ожид=200 факт=200 |
+| api | Кассир сменил пароль | ✓ ожид=204 факт=200 |
+| api | Вход по новому паролю — успех | ✓ ожид=успех факт=200 |
+| api | Вход по старому паролю — отказ | ✓ ожид=отказ факт=400 |
+| api | Кладовщик → деньги 403 | ✓ ожид=403 факт=403 |
+| api | Кладовщик → приёмки доступны | ✓ ожид=200 факт=200 |
+| api | Правка сотрудника (ФИО/тел/должность) | ✓ ожид=200 факт=204 |
+| api | Блокировка (увольнение) сотрудника | ✓ ожид=200 факт=204 |
+| api | Заблокированный кассир не получает токен | ✓ ожид=отказ факт=400 |
+| api | Заблокированный кассир: обновление токена (refresh) → отказ | ✓ ожид=отказ факт=400 |
+
+## ✓ Step step03_money_accounts: Деньги — касса, банковский счёт (номер), эквайринг; начальные остатки
+
+Длительность: 1229мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Касса магазина создана (Cash, нач.остаток 50000) | ✓ ожид=200+id факт=201 |
+| api | Банковский счёт создан (Bank, номер, нач.остаток 200000) | ✓ ожид=200+id факт=201 |
+| api | Счёт эквайринга создан (Acquiring) | ✓ ожид=200+id факт=201 |
+| api | Для 2-й точки созданы своя касса и эквайринг | ✓ ожид=2 счёта факт=201/201 |
+| api | Отчёт «Деньги»: касса currentBalance = начальный остаток | ✓ ожид=50000 факт=50000 |
+| api | Отчёт «Деньги»: банк currentBalance = начальный остаток | ✓ ожид=200000 факт=200000 |
+
+## ✓ Step step04_initial_supplier_debt: Начальный долг поставщику через корректировку взаиморасчётов (WeOwe) → долг = сумме
+
+Длительность: 766мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Корректировка взаиморасчётов создана (WeOwe 100000) | ✓ ожид=200+id факт=201 |
+| api | Корректировка проведена | ✓ ожид=204 факт=204 |
+| api | Долг поставщика = 100000 (только начальный) | ✓ ожид=100000 факт=100000 |
+
+## ✓ Step step05_supply1_manual: Приёмка №1 вручную (кладовщик) → провести → остатки +кол-во; себестоимость
+
+Длительность: 2893мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик авторизован для приёмки | ✓ ожид=token факт=keeper |
+| api | Приёмка №1 создана (черновик) | ✓ ожид=200+id факт=201 |
+| api | Приёмка №1 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток 5be3b46d… +12.5 | ✓ ожид=12.5 факт=12.5 |
+| api | Остаток 74ba11b8… +25 | ✓ ожид=25 факт=25 |
+| api | Остаток 6bb9c6a1… +30 | ✓ ожид=30 факт=30 |
+| api | Остаток b04c0a92… +35 | ✓ ожид=35 факт=35 |
+| api | Остаток 02a317f6… +40 | ✓ ожид=40 факт=40 |
+| api | Себестоимость товара = цене приёмки | ✓ ожид=300 факт=300 |
+
+## ✓ Step step06_supply2_excel: Приёмка №2 из табличной накладной (поставщик не указан → «Поставщик не указан») → провести
+
+Длительность: 5404мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Табличная накладная загружена | ✓ ожид=200+id факт=200 |
+| api | Накладная разобрана (не pending/parsing) | ✓ ожид=needs_review факт=needs_review |
+| api | Накладная перенесена в приёмку (apply) | ✓ ожид=200+supplyId факт=200 |
+| api | Поставщик приёмки №2 = «Поставщик не указан» | ✓ ожид=Поставщик не указан факт=Поставщик не указан |
+| api | Приёмка №2 проведена | ✓ ожид=204 факт=204 |
+| api | Остаток Товар 1 fc17914971 +7 | ✓ ожид=7 факт=7 |
+| api | Остаток Товар 2 fc17914971 +4 | ✓ ожид=4 факт=4 |
+| api | Остаток Товар 3 fc17914971 +9 | ✓ ожид=9 факт=9 |
+
+## ✓ Step step07_supply3_photo: Приёмка №3 по фото-накладной → ручное сопоставление → провести; снимки удалены с диска
+
+Длительность: 20213мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Фото-накладная загружена | ✓ ожид=200+id факт=id |
+| api | Фото-накладная распознана (OCR, needs_review; до 3 попыток) | ✓ ожид=needs_review факт=needs_review |
+| api | OCR извлёк хотя бы одну строку | ✓ ожид=≥1 факт=5 |
+| api | Фото-накладная перенесена в приёмку | ✓ ожид=200 факт=200 |
+| api | Приёмка №3 проведена | ✓ ожид=204 факт=204 |
+| api | Снимки удалены с диска после apply (photo → 404) | ✓ ожид=404 факт=404 |
+
+## ✓ Step step08_supplier_payments: Оплата — №1 частично нал из кассы, №2 полностью с банка; статусы + долг = формуле
+
+Длительность: 2153мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Оплата №1 частично наличными из кассы (≤ остатка) | ✓ ожид=204 факт=201 |
+| api | Оплата больше остатка кассы → отказ (409 insufficient-funds) | ✓ ожид=409 факт=409 |
+| api | Оплата №2 полностью с банковского счёта | ✓ ожид=204 факт=201 |
+| api | Приёмка №1: оплачено = частичной сумме | ✓ ожид=30000 факт=30000 |
+| api | Приёмка №2: оплачено полностью | ✓ ожид=8640 факт=8640 |
+| api | Долг реального поставщика = начальный + приёмки − оплаты | ✓ ожид=181030 факт=181030 |
+
+## ✓ Step step09_cashier_shift: Смена — размен, 3 продажи (нал/карта/смеш), oversell→отказ, возврат, внесение/выплата, закрытие с расхождением + Z; продажа без смены→отказ
+
+Длительность: 6418мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Смена открыта (размен 5000) | ✓ ожид=200+id факт=200 |
+| api | Продажа 1 (наличные) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 2 (карта) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа 3 (смешанная) проведена | ✓ ожид=204 факт=204 |
+| api | Продажа больше остатка → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | После продажи в минус появилось предупреждение | ✓ ожид=>=1 факт=1 |
+| api | Возврат по чеку проведён (1 шт, наличные) | ✓ ожид=204 факт=204 |
+| api | Внесение и выплата зафиксированы | ✓ ожид=2×200 факт=200/200 |
+| api | Смена закрыта | ✓ ожид=200 факт=200 |
+| api | Закрытие: «должно быть» (expectedCash) верно | ✓ ожид=12950 факт=12950 |
+| api | Закрытие: разница (факт − должно) = расхождению | ✓ ожид=500 факт=500 |
+| api | Z-отчёт: нал.продажи и expectedCash сходятся | ✓ ожид=1450/12950 факт=1450/12950 |
+| api | Деньги смены в остатке кассы (касса += факт − размен) | ✓ ожид=28450 факт=28450 |
+| api | Продажи картой в остатке эквайринга | ✓ ожид=1150 факт=1150 |
+| api | Продажа без открытой смены → отказ | ✓ ожид=409 факт=409 |
+
+## ✓ Step step09a_points_binding: Привязка кассира к точкам; параллельные смены на 2 точках не смешивают деньги; продажа на неактивной→отказ
+
+Длительность: 2855мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кассир авторизован для проверки привязки | ✓ ожид=token факт=ok |
+| api | Кассир открывает смену на НЕзакреплённой точке 2 → отказ | ✓ ожид=4xx факт=400 |
+| api | Кассир открывает смену на закреплённой точке 1 → успех | ✓ ожид=200+id факт=200 |
+| api | Вторая смена на той же точке → 409 | ✓ ожид=409 факт=409 |
+| api | Параллельная смена на точке 2 открыта | ✓ ожид=200+id факт=200 |
+| api | Продажи прошли на обеих точках | ✓ ожид=2×204 факт=204/204 |
+| api | Точка 1: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=1500 факт=1500 |
+| api | Точка 2: касса = размен + её продажа (деньги не смешаны) | ✓ ожид=2700 факт=2700 |
+| api | Смена/продажа на неактивной точке → отказ | ✓ ожид=4xx факт=400 |
+
+## ✓ Step step10_warehouse_ops: Склад — оприходование излишка, списание брака, инвентаризация CSV (часть товаров): непосчитанные не обнулены
+
+Длительность: 8052мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Кладовщик → оприходование доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → списание доступно (не 403) | ✓ ожид=<400 факт=201 |
+| api | Кладовщик → инвентаризация доступна (не 403) | ✓ ожид=200 факт=200 |
+| api | Пустая инвентаризация проведена (одно расхождение) | ✓ ожид=204 факт=204 |
+| api | Пустая инвентаризация: непосчитанный НЕ обнулён | ✓ ожид=35 факт=35 |
+| api | Пустая инвентаризация: посчитанный применён (недостача 1) | ✓ ожид=52 факт=52 |
+| api | Оприходование излишка (+8) | ✓ ожид=8 факт=8 |
+| api | Списание брака (−2) | ✓ ожид=2 факт=2 |
+| api | Импорт инвентаризации нашёл 2 товара | ✓ ожид=2 факт=2 |
+| api | Инвентаризация (частичная) создана | ✓ ожид=200+id факт=201 |
+| api | Инвентаризация проведена | ✓ ожид=204 факт=204 |
+| api | Расхождение применено (товар с недостачей → факт) | ✓ ожид=40.5 факт=40.5 |
+| api | Непосчитанный товар не обнулён | ✓ ожид=52 факт=52 |
+| api | Инвентаризация завершена (Completed) | ✓ ожид=204 факт=204 |
+| api | После завершения остаток НЕ изменился | ✓ ожид=40.5 факт=40.5 |
+| api | Создано оприходование излишков | ✓ ожид=200+enterId факт=200 |
+| api | В инвентаризации виден связанный документ | ✓ ожид=true факт=true |
+| api | Оприходование проведено | ✓ ожид=204 факт=204 |
+| api | Излишек применён оприходованием (+3) | ✓ ожид=3 факт=3 |
+| api | Оприходование «на основании инвентаризации №…» | ✓ ожид=инв.№ факт=И-2026-000003 |
+| api | unpost при проведённом связанном → 409 (не удаляет) | ✓ ожид=409 факт=409 |
+| api | Отмена результатов (cancel-results) → 200 | ✓ ожид=200 факт=200 |
+| api | После отмены результатов остаток вернулся | ✓ ожид=40.5 факт=40.5 |
+| api | Оприходование НЕ удалено, стало черновиком | ✓ ожид=draft факт=200/0 |
+| api | Связанный документ остался (черновик) | ✓ ожид=true факт=true |
+| api | Повторное проведение оприходования | ✓ ожид=204 факт=204 |
+| api | После повторного проведения остаток снова = факт (+3) | ✓ ожид=3 факт=3 |
+
+## ✓ Step step11_reports: Отчёты — продажи за день, прибыль, остатки на дату, «Деньги», долги; по точкам/кассирам
+
+Длительность: 1111мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отчёт продаж за день доступен, выручка ≥ 0 | ✓ ожид=≥0 факт=3300 |
+| api | Прибыль = выручка − себестоимость (по каждой строке) | ✓ ожид=revenue−cost факт=200 |
+| api | Отчёт остатков на дату доступен | ✓ ожид=список факт=200 |
+| api | Деньги: касса = начальный − оплаты + движения смен | ✓ ожид=28950 факт=28950 |
+| api | Деньги: банк = начальный − оплата с банка | ✓ ожид=191360 факт=191360 |
+| api | Деньги: эквайринг = продажи картой − возвраты картой | ✓ ожид=1150 факт=1150 |
+| api | Отчёт долгов поставщикам доступен | ✓ ожид=200 факт=200 |
+| api | Выручка по точкам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+| api | Выручка по кассирам в сумме = общей выручке дня | ✓ ожид=3300 факт=3300 |
+
+## ✓ Step step12_invariants: Инварианты — остаток≡Σдвижений; счёт≡начальный+Σопераций; долг≡формуле; изоляция орг
+
+Длительность: 2409мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Инвариант остаток≡Σдвижений: Товар 1 fc179149 | ✓ ожид=43.5 факт=43.5 |
+| api | Инвариант остаток≡Σдвижений: Товар 2 fc179149 | ✓ ожид=57 факт=57 |
+| api | Инвариант остаток≡Σдвижений: Товар 3 fc179149 | ✓ ожид=52 факт=52 |
+| api | Инвариант остаток≡Σдвижений: Товар 4 fc179149 | ✓ ожид=43 факт=43 |
+| api | Инвариант остаток≡Σдвижений: Товар 5 fc179149 | ✓ ожид=38 факт=38 |
+| api | Инвариант Касса ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=28950 факт=28950 |
+| api | Инвариант Банк ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=191360 факт=191360 |
+| api | Инвариант Эквайринг ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=1150 факт=1150 |
+| api | Инвариант Касса-2 ≡ независимому расчёту (нач+платежи+смены) | ✓ ожид=3700 факт=3700 |
+| api | Инвариант долг≡формуле | ✓ ожид=181030 факт=181030 |
+| api | Изоляция: demo-admin НЕ видит товар e2e-орг | ✓ ожид=404/403 факт=404 |
+
+## ✓ Step step13_cancel_rollback: Отмена/откат — отмена приёмки с проданным товаром→отказ; отмена платежа→долг вернулся
+
+Длительность: 969мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Отмена приёмки с проданным товаром → проведено (минус разрешён) | ✓ ожид=204 факт=204 |
+| api | Отмена платежа №1 | ✓ ожид=204 факт=204 |
+| api | Долг вернулся на сумму платежа | ✓ ожид=211030 факт=211030 |
+
+## ✓ Step step14_finalize: Финал — скриншоты ключевых экранов, деактивация e2e-сущностей (режим B)
+
+Длительность: 0мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Режим C: temp-орг чистится ночной уборкой (>3 дней) | ✓ ожид=cleanup факт=ночь |
+
+## Summary
+
+- Passed: 16
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## UX recommendations
+
+- Скриншоты ключевых экранов: tests/e2e/reports/full-chain/*.png
diff --git a/tests/e2e/reports/invoice-upload-review-needs_review.png b/tests/e2e/reports/invoice-upload-review-needs_review.png
new file mode 100644
index 0000000..d72d3ad
Binary files /dev/null and b/tests/e2e/reports/invoice-upload-review-needs_review.png differ
diff --git a/tests/e2e/reports/menu-links-demo-admin-desktop-inventory-mobile.png b/tests/e2e/reports/menu-links-demo-admin-desktop-inventory-mobile.png
new file mode 100644
index 0000000..cfa4cf1
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-admin-desktop-inventory-mobile.png differ
diff --git a/tests/e2e/reports/menu-links-demo-admin-desktop-invoices.png b/tests/e2e/reports/menu-links-demo-admin-desktop-invoices.png
new file mode 100644
index 0000000..37a98c4
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-admin-desktop-invoices.png differ
diff --git a/tests/e2e/reports/menu-links-demo-admin-desktop-supply-scan.png b/tests/e2e/reports/menu-links-demo-admin-desktop-supply-scan.png
new file mode 100644
index 0000000..9000221
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-admin-desktop-supply-scan.png differ
diff --git a/tests/e2e/reports/menu-links-demo-admin-mobile-inventory-mobile.png b/tests/e2e/reports/menu-links-demo-admin-mobile-inventory-mobile.png
new file mode 100644
index 0000000..fe8ba4f
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-admin-mobile-inventory-mobile.png differ
diff --git a/tests/e2e/reports/menu-links-demo-admin-mobile-invoices.png b/tests/e2e/reports/menu-links-demo-admin-mobile-invoices.png
new file mode 100644
index 0000000..e550c21
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-admin-mobile-invoices.png differ
diff --git a/tests/e2e/reports/menu-links-demo-admin-mobile-supply-scan.png b/tests/e2e/reports/menu-links-demo-admin-mobile-supply-scan.png
new file mode 100644
index 0000000..32ed461
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-admin-mobile-supply-scan.png differ
diff --git a/tests/e2e/reports/menu-links-demo-cashier-desktop-sidebar.png b/tests/e2e/reports/menu-links-demo-cashier-desktop-sidebar.png
new file mode 100644
index 0000000..c032639
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-cashier-desktop-sidebar.png differ
diff --git a/tests/e2e/reports/menu-links-demo-keeper-desktop-inventory-mobile.png b/tests/e2e/reports/menu-links-demo-keeper-desktop-inventory-mobile.png
new file mode 100644
index 0000000..c42fb25
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-keeper-desktop-inventory-mobile.png differ
diff --git a/tests/e2e/reports/menu-links-demo-keeper-desktop-invoices.png b/tests/e2e/reports/menu-links-demo-keeper-desktop-invoices.png
new file mode 100644
index 0000000..52982d2
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-keeper-desktop-invoices.png differ
diff --git a/tests/e2e/reports/menu-links-demo-keeper-desktop-supply-scan.png b/tests/e2e/reports/menu-links-demo-keeper-desktop-supply-scan.png
new file mode 100644
index 0000000..af50955
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-keeper-desktop-supply-scan.png differ
diff --git a/tests/e2e/reports/menu-links-demo-keeper-mobile-inventory-mobile.png b/tests/e2e/reports/menu-links-demo-keeper-mobile-inventory-mobile.png
new file mode 100644
index 0000000..fe8ba4f
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-keeper-mobile-inventory-mobile.png differ
diff --git a/tests/e2e/reports/menu-links-demo-keeper-mobile-invoices.png b/tests/e2e/reports/menu-links-demo-keeper-mobile-invoices.png
new file mode 100644
index 0000000..b84fb94
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-keeper-mobile-invoices.png differ
diff --git a/tests/e2e/reports/menu-links-demo-keeper-mobile-supply-scan.png b/tests/e2e/reports/menu-links-demo-keeper-mobile-supply-scan.png
new file mode 100644
index 0000000..32ed461
Binary files /dev/null and b/tests/e2e/reports/menu-links-demo-keeper-mobile-supply-scan.png differ
diff --git a/tests/e2e/reports/menu-walk-demo-admin.png b/tests/e2e/reports/menu-walk-demo-admin.png
new file mode 100644
index 0000000..0f2dbb6
Binary files /dev/null and b/tests/e2e/reports/menu-walk-demo-admin.png differ
diff --git a/tests/e2e/reports/menu-walk-demo-cashier.png b/tests/e2e/reports/menu-walk-demo-cashier.png
new file mode 100644
index 0000000..c2873a9
Binary files /dev/null and b/tests/e2e/reports/menu-walk-demo-cashier.png differ
diff --git a/tests/e2e/reports/menu-walk-demo-keeper.png b/tests/e2e/reports/menu-walk-demo-keeper.png
new file mode 100644
index 0000000..5a90119
Binary files /dev/null and b/tests/e2e/reports/menu-walk-demo-keeper.png differ
diff --git a/tests/e2e/reports/mobile/375-_catalog_counterparties.png b/tests/e2e/reports/mobile/375-_catalog_counterparties.png
new file mode 100644
index 0000000..0800261
Binary files /dev/null and b/tests/e2e/reports/mobile/375-_catalog_counterparties.png differ
diff --git a/tests/e2e/reports/mobile/375-_catalog_products.png b/tests/e2e/reports/mobile/375-_catalog_products.png
new file mode 100644
index 0000000..cdf4509
Binary files /dev/null and b/tests/e2e/reports/mobile/375-_catalog_products.png differ
diff --git a/tests/e2e/reports/mobile/375-_dashboard.png b/tests/e2e/reports/mobile/375-_dashboard.png
new file mode 100644
index 0000000..838530e
Binary files /dev/null and b/tests/e2e/reports/mobile/375-_dashboard.png differ
diff --git a/tests/e2e/reports/mobile/375-_inventory_stock.png b/tests/e2e/reports/mobile/375-_inventory_stock.png
new file mode 100644
index 0000000..f334d93
Binary files /dev/null and b/tests/e2e/reports/mobile/375-_inventory_stock.png differ
diff --git a/tests/e2e/reports/mobile/375-_loyalty_cards.png b/tests/e2e/reports/mobile/375-_loyalty_cards.png
new file mode 100644
index 0000000..d7a7abd
Binary files /dev/null and b/tests/e2e/reports/mobile/375-_loyalty_cards.png differ
diff --git a/tests/e2e/reports/mobile/375-_loyalty_programs.png b/tests/e2e/reports/mobile/375-_loyalty_programs.png
new file mode 100644
index 0000000..c33c712
Binary files /dev/null and b/tests/e2e/reports/mobile/375-_loyalty_programs.png differ
diff --git a/tests/e2e/reports/mobile/375-_promotions.png b/tests/e2e/reports/mobile/375-_promotions.png
new file mode 100644
index 0000000..c17b782
Binary files /dev/null and b/tests/e2e/reports/mobile/375-_promotions.png differ
diff --git a/tests/e2e/reports/mobile/375-_purchases_supplies.png b/tests/e2e/reports/mobile/375-_purchases_supplies.png
new file mode 100644
index 0000000..5c642d9
Binary files /dev/null and b/tests/e2e/reports/mobile/375-_purchases_supplies.png differ
diff --git a/tests/e2e/reports/mobile/375-_reports_sales.png b/tests/e2e/reports/mobile/375-_reports_sales.png
new file mode 100644
index 0000000..87fb25a
Binary files /dev/null and b/tests/e2e/reports/mobile/375-_reports_sales.png differ
diff --git a/tests/e2e/reports/mobile/375-_sales_retail.png b/tests/e2e/reports/mobile/375-_sales_retail.png
new file mode 100644
index 0000000..12106e1
Binary files /dev/null and b/tests/e2e/reports/mobile/375-_sales_retail.png differ
diff --git a/tests/e2e/reports/mobile/768-_catalog_counterparties.png b/tests/e2e/reports/mobile/768-_catalog_counterparties.png
new file mode 100644
index 0000000..4675134
Binary files /dev/null and b/tests/e2e/reports/mobile/768-_catalog_counterparties.png differ
diff --git a/tests/e2e/reports/mobile/768-_catalog_products.png b/tests/e2e/reports/mobile/768-_catalog_products.png
new file mode 100644
index 0000000..eb05f9a
Binary files /dev/null and b/tests/e2e/reports/mobile/768-_catalog_products.png differ
diff --git a/tests/e2e/reports/mobile/768-_dashboard.png b/tests/e2e/reports/mobile/768-_dashboard.png
new file mode 100644
index 0000000..a6e355f
Binary files /dev/null and b/tests/e2e/reports/mobile/768-_dashboard.png differ
diff --git a/tests/e2e/reports/mobile/768-_inventory_stock.png b/tests/e2e/reports/mobile/768-_inventory_stock.png
new file mode 100644
index 0000000..df7191a
Binary files /dev/null and b/tests/e2e/reports/mobile/768-_inventory_stock.png differ
diff --git a/tests/e2e/reports/mobile/768-_loyalty_cards.png b/tests/e2e/reports/mobile/768-_loyalty_cards.png
new file mode 100644
index 0000000..2f72c13
Binary files /dev/null and b/tests/e2e/reports/mobile/768-_loyalty_cards.png differ
diff --git a/tests/e2e/reports/mobile/768-_loyalty_programs.png b/tests/e2e/reports/mobile/768-_loyalty_programs.png
new file mode 100644
index 0000000..f9a71a4
Binary files /dev/null and b/tests/e2e/reports/mobile/768-_loyalty_programs.png differ
diff --git a/tests/e2e/reports/mobile/768-_promotions.png b/tests/e2e/reports/mobile/768-_promotions.png
new file mode 100644
index 0000000..36aabd7
Binary files /dev/null and b/tests/e2e/reports/mobile/768-_promotions.png differ
diff --git a/tests/e2e/reports/mobile/768-_purchases_supplies.png b/tests/e2e/reports/mobile/768-_purchases_supplies.png
new file mode 100644
index 0000000..973c6b4
Binary files /dev/null and b/tests/e2e/reports/mobile/768-_purchases_supplies.png differ
diff --git a/tests/e2e/reports/mobile/768-_reports_sales.png b/tests/e2e/reports/mobile/768-_reports_sales.png
new file mode 100644
index 0000000..e446b9d
Binary files /dev/null and b/tests/e2e/reports/mobile/768-_reports_sales.png differ
diff --git a/tests/e2e/reports/mobile/768-_sales_retail.png b/tests/e2e/reports/mobile/768-_sales_retail.png
new file mode 100644
index 0000000..04628ff
Binary files /dev/null and b/tests/e2e/reports/mobile/768-_sales_retail.png differ
diff --git a/tests/e2e/reports/neg-banner-home-1791495131783.png b/tests/e2e/reports/neg-banner-home-1791495131783.png
new file mode 100644
index 0000000..44341c7
Binary files /dev/null and b/tests/e2e/reports/neg-banner-home-1791495131783.png differ
diff --git a/tests/e2e/reports/neg-notif-center-1791497018061.png b/tests/e2e/reports/neg-notif-center-1791497018061.png
new file mode 100644
index 0000000..17ad502
Binary files /dev/null and b/tests/e2e/reports/neg-notif-center-1791497018061.png differ
diff --git a/tests/e2e/reports/neg-notif-center2-1791497516056.png b/tests/e2e/reports/neg-notif-center2-1791497516056.png
new file mode 100644
index 0000000..4ee7b70
Binary files /dev/null and b/tests/e2e/reports/neg-notif-center2-1791497516056.png differ
diff --git a/tests/e2e/reports/neg-push-toggle-1791500159686.png b/tests/e2e/reports/neg-push-toggle-1791500159686.png
new file mode 100644
index 0000000..54e208c
Binary files /dev/null and b/tests/e2e/reports/neg-push-toggle-1791500159686.png differ
diff --git a/tests/e2e/reports/neg-settings-1791497018061.png b/tests/e2e/reports/neg-settings-1791497018061.png
new file mode 100644
index 0000000..2f34458
Binary files /dev/null and b/tests/e2e/reports/neg-settings-1791497018061.png differ
diff --git a/tests/e2e/reports/neg-stock-filter-1791495131783.png b/tests/e2e/reports/neg-stock-filter-1791495131783.png
new file mode 100644
index 0000000..29da016
Binary files /dev/null and b/tests/e2e/reports/neg-stock-filter-1791495131783.png differ
diff --git a/tests/e2e/reports/parity-dashboard-1791508247176.png b/tests/e2e/reports/parity-dashboard-1791508247176.png
new file mode 100644
index 0000000..61db246
Binary files /dev/null and b/tests/e2e/reports/parity-dashboard-1791508247176.png differ
diff --git a/tests/e2e/reports/parity-supplies-1791508247176.png b/tests/e2e/reports/parity-supplies-1791508247176.png
new file mode 100644
index 0000000..7ee45be
Binary files /dev/null and b/tests/e2e/reports/parity-supplies-1791508247176.png differ
diff --git a/tests/e2e/reports/playwright-artifacts/.last-run.json b/tests/e2e/reports/playwright-artifacts/.last-run.json
new file mode 100644
index 0000000..cbcc1fb
--- /dev/null
+++ b/tests/e2e/reports/playwright-artifacts/.last-run.json
@@ -0,0 +1,4 @@
+{
+ "status": "passed",
+ "failedTests": []
+}
\ No newline at end of file
diff --git a/tests/e2e/reports/playwright-html/index.html b/tests/e2e/reports/playwright-html/index.html
new file mode 100644
index 0000000..622b980
--- /dev/null
+++ b/tests/e2e/reports/playwright-html/index.html
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+ Playwright Test Report
+
+
+
+
+
+
+
+data:application/zip;base64,UEsDBBQAAAgIAORRSV3+PyugxA8AADOLAAAZAAAAMmVlMTFlNmE3MDQ3OGFmZGYyNDIuanNvbu1dXW/byLn+KwMigCQsRfObFA9y0iTNdg1su0HsbYFu0npMjSTGFEclh7G9XgHJtmjPwfacBXp/UPT63Hh3G2yaNF6gv2D0F/pLihlSFjW2bEoWHe+WvgkjksOZ93nemXned8g5knpBiDa7kifpCGkasqGjmo4Le92ebuqSzM//DA6R5EkJgX3UToN2Ckl7iHeDECnJCPkKSSRZIighieR9csSPFhbZhqZtWqpr7FrQ6aq+quoqZLcHJGQPeai1J/9DX0+e02P6dvIFoG/pMTA66ugAvAfoyeTF5HN6PPmcvqavwD/+n35HT+hreky/ZT9O/gjo28lv6Rv6kn49+YK+/McbSZZGMX6KfJI3wh/EeBikw3YXJXsEjyRZCrEPSYAjyTvizb20qWEQIcnTLFnycZgOI8kzxrLUTeO8GM3VjI4swSjChP/E7PJElgjs50c4JT7m9UEHI+QT1GUVhWQgeZ9IH9/dBtkzs4ZLT2QpRkka5vY986CEwJhsB7w8XdXttqa21c62anma6Vmq4ljaLyVWBokPJU9lN6BRjlVu9nuoh2MEPsB4j7XwshJdq8NKnNXE0bXzin0/OCBpjMBjaTfG+wmKH0slSu9o2nzphuWcV/qHMI38AciLLlOwbggFm+as4CeyBAmB/mCIIpL/4OM0IpLHGrcXjEaoK3k9GCZovNTF8nkW8XFE0AEpYRFN0V2h4rZ9nkHuxwgSBPKSy5TbEco11XdmjxHso1LGMCx1vtK6cS6nc2uwckuVagql6tZ12GJVw20hAp4FaH+EYwKS4NMybbRcR2ije3ETV+0anVnXqNnjxQ2SpSRi/yeSJwGg2eAzwP7YCKIkiDcFp6SpueqvVVVtPY4A0Jz8IrgPA8LRZZf+PDfFVvApah6B/aBLBh7rP2UwQEF/QDzgmiYY8zIAyMso/P2KF+7mJ3wcJQSgOE7AbbAPiT94CPuoyZ7Wkoow5CSL0W9SlJAlXM82Bb51loZCUTbCYHcjDYq21+2C7a3Stge6xZu+sQHoCf2Kjb+T/6Yv6Vv6ir4CTR+HXeBDf4BaMqDf0TeT/528ADEkKAyGAcmG6SToR+kI2BvDIFK4nfUM0cyaPjkAt3PY4Ch4lJlMidD+/cxqzSOwCxP08aMPPXDv7tYDGQT9CMfog+3th1sP4hjHiQdInCIZkIwZHrA5M2a4ngH2V1lFnEJF0BAGIbgNdm4djWLUCw7G7VtHJBn/qIdxtz2E8R4iCrN3uDOH9cOPtrbBY2kDjoINmJLBRtbgUp2W7Qiup6nWJWNPWcRZ7zdFXNeWQLxTsAmO+2yGxKzy8WZbMMwOt6Gh8utDREB8CqRPDpQRTkizIZqlIYOjRaAUoTG0/HQXEuiBowweGYxgkuzjuCuzusEo+JQbg1XSm9ZWBqMBjpAHGu85jqppWkdVVa0hg1EIIw80OCgNMJbnYMxpSv9K30y+BCkkw7bmdDRL192OrrvqWRpciq+uOKaI73rANfUZuOYS7mxmVh1zE5s6/08212zGSkIgSZNmSwY788a4dcSNP95pKQTfQ00973QXY7joL8PWNAoUI3jvlDYh7gfRNt5DUdMnB7KIeetcv/NxFCGfbBB2Xwmv0xXHsoUBz15TN2t1Ck5nlMfFykaYvL+yii54rlPNtflyl5oa3lbzCwYIdhHrN49Ag3ezEWlvH45QwwMNOBqFQdbcjYP2/v5+u4fjYTuNQxT5uIu6Z1xnrjbrcR1DUXV3HqRL5qBlIbLNguu45SGyjSJEtrnQd+atsT7fmaFoFejx9JQesfI0wVGzBWACjgD0fZQkv+aV8EBC4iDqg/EcbD95cDpuDcvMsQ1FNWxRKa2pPyuAoptL9Ger9iRZP2QW7uaj3MzR+mg6eA0Rc7Ciy9xNyQDH+dDjgZ17CMYoBreOCN4b74DxBfMOsSe0ijQaolMeFdgyh9kDfiV4LLHT5TBz9Er8yLRW6+qqNnoZk5brLU17rqb3cPfwtLZDNOdtOO5vdhe42YpawFA0Swh46JXIMr0wl9Cc0kDq0wka0wZ/oa/oX8HkD/Tl5Dl9Sb8Fdx9ueoB+M3k++S39jn5Hj2Uw+Zye0K/p8eQ5mLygJ4AH7Vic7oT+HdBXxfP0K17I6RXHoDkL4dET+rcWFxK6PqfLSiiJRTIvQ1w3Ts+sqDjkRR2sDwkMcX8jjQKStHGvPUQwSWN0h2lHpk5vW2opd9ZsMQq2vD+XYkVBrOtLsMKeg6QXxAlhoCSHkQ+aaRxOnUQGoxh173igeeABGB22wO3/BLsYhwhG/JhjpTuniJw3G2L9RRqHrf9YOBguBFyE3hUeFBA0ZCr/bhzDQyVI+L/Npy1wBzwFHmg+VbIr7twBnzxpXQZ7QnCMkuXB7ogT1Rrsmw+2n8YxivxgBcB1XfBubXlhUgN+3YCP4sBHbXI4WgVx06pd/HuIOO6mPmn3Y5yOVgDdEXIVZu3mNwz0YlRXQD0phbGhC47dqSarYizAWL8YY2Me4+HeDOCIB1OnCMOYBH5Y+GEXxiwMNP1hhrNxMc6FeLBoUK718kBvWbANt3BNxMO+eVVlwGbZH/V+mk2xmTBjP2x2ZfAMEg9oOj94EMHdEHWnM/m8Lj9hHs1u6WcH8kJWBNEzFBEcH26giKC4HCtMQ0ytLh8RLsMKs8iKTmnPN6esyFXuXrPB1h3Mi6+GDNivdx9t6+zQtNXpn242uLOazhy5uH0WcUE045JcyNlgztjQhQR5IEL74MeQoCaT/ZtbH21xsrIAHZ+LMzLk87RDdhxhghIPNFJIGuUh3+juah3XcnptF0K/bfodvd2BmtruOD3fMHuOtauaG6yx5cjRuR5tZ+krJQMtbR7VoAtug2YGKrdH3l23lKDLMLH0OTKd4r5zvi1vHaGgO+bW2ilwYLw4O8uRt4wzT+kGyQgnqDnfo/8MPgv6LBJDMMOTRwhLwWKr4qRc1deUx3G0AhJLxD0dFshHBzzLn/XavTTy2RNBVpctlCQBjnhq2gMsSy2DBCWJB/IzMuhjgh9CMgC3QWOjC5PBLoZxt9HK3c7J0C7k09kNzUZmuMaiGFoWOnN08Wb0DIYp88cmwXt8zOCJgC2C4zxXv0nQsNnoDZVi6Lohs7BuK6t8foaHdYWwaF76pWiaiq2Lqx3WlPtx9BWxLGPoazDoxYAa51ZyyiHmr+zUxxEJQg80unjoZ2mlEMMsZXShM57Sr4RDmoptueLU6pJFOaUxNFbE8JrgWQMMF8PMgvPz4etfsEf1cDwNdV6Kj6XYYuBas9VqRrJiMk8rn8yzZ4HePFx8ptPMEGAZIzLgNsszfmDe/OzofRyfLkmyZtmFc2Yt3Mh5+g7kofO39OXkc0C/oSeT5/QV/Zae0LdsNSt9M/kjfUtP2BkWMGeLX0/oG/qGHheWv67WCzqKLqbAK5qH2oV1R0Z5h1qrjbjRbUGbJH6Mw/AXp7NSwWm5x3axnzITKNODByHi/89vZqvJyojTOfRFkeSHAYrIihXJb+YVWZUKhiokCA2nGio4q1GhUuSqg2NZXswETJ66zKsq8wVpkAzG3jQvtpQj5AsPPmQDyQBGH8UPfpPCsDlt53tAn2fObCxe7XllGGeK40M1hHNnhLPLZ6irpcS7xLk8JUvwtXPecJj4MUJRMsBs1SZrjMda9ePNR+ONW0fs53Hb6KjKKOrvyKCXhuFDrk9YBEacIW6dFlWKUeIybbuiCUdntQnHO0a9CrQumeY407Vm43WocEexNUG3ma5di/DvpQh3FU0TX9ZY06qkWoSvLsJXSHO4imYIPa9prsstay1+ZS3uKpb4jphmWRVNt2otvnRnaHmqqmjiqlpteQ+qtfj3XYtnVBBfN6yKCrUWv4gXN0aLi0NyFZI8I56jXXWVeC3Ja0k+xyj9TBKgluQ/FEnOITZMQcUZ7vKh41qSv3NJzsF0DPFtk3XlVGtJvrIkny2SSQj290p5pWOLi0vXFlypFfnVFLnlqZqiueLAaBlGrchvjiLXFUeMNVe0KL9W5CL6N0yR64pjuNfyRk6tyC/kxY1R5MKIXJEg18+O4rUgrwX5FQQ5Y5SYCVhhFXMtyG+uINcV1+2IyyDqHPn3U5CzN/3Fj63UOfJ3LsgTGKJkI0YEBmEJl2Sv8AsuaawNxlqNX1mNG4olhr00y6zV+A1S45aiOqIEq+ZN2lqNi+jfMDVuKWpHoIJRzTeRajV+IS9ujBovDscVSXFL0QwxYFtL8VqKry7FGaOsMymAWor/gKS4pehnRipnXe8Z11L8eqW4pdhnU3a1FH/XUjxGjMqXrlLnADriJxwMa13eWKvwK6twW1HFWJdmmcu7WK3CK1Ph7P0r8RW75b/9XKvwH4AKdxRbXPen1W+M/zur8HwkrkiAO4ot7itW58JrAX4FAe4otvgVbW2FbXdqAX5zBbijuLq4DNZaPm1QC/CbIMBdRXfPfFGqFuDvWoAvvzjdPRsW01f4LG4txM8D+6wQn9ss5udBEuyG6LEE+ojcO9xm+2Hwj7ue2Yyj0SoBpK0KctDQqkmLOAXBbpXfx86Z/yzoYrneEHmcOa9jzt2fj8IZbpfaLxtkc4s3j2a7hGjW/L6Eq0ytstHSKlm9u4+2tUZL4d/wbgoVu2BroUVsmS+uBE864lL6FbaMKkWTwnZEVvnJ+zXAvB6orjQXzygzlcUsPvJ/xQ86C1vzvJ48n3zBoif5Ljy/YxNH+g09Vhbx5QP4DN1n9j7buwifji5FGUvMjlUTXnAK4QWz/Dey12BHDodTlnmiCRkzTi3evCh6WIoWbqE5f6Kv+Sauf6DH9CX9O9tL/c+X7KUO/vn7PwlVZFvBnky+pF+z3SNZIG7yYvLlPHnuh4G/V+TKJc8pRxxHII5dEXEKos4sv5HxtVmaw9qZo5fIq0vNzQIR/t6q/Q5nlqteheEXd6wrzHOW7ok6iipuzmJVk5Rw1dV6ojViXCVYV+ugXO1sKy+IRPA5XDuI/DDtol+iGFcRQeoomvjVVKeavsYtBhvK9zVVw1klKIvokrFBB5+Jm88mOERtejL5L/qKfkVf01ceKIOgGFOoZimhW9ClTvmJKWsnb+9Ux+QQss3nlbzN2Waz57T+1lHxMuUpDqJmA3wGGq1sH9os6PfJk3VFeEWMzHPqHCGyj+M9GexMXrCRatoNgXOrnl99QdXnSHBhkaW4YF5HhsE1V+NC5Ry4FsQqIlsmr4S+/G6PbTnzAcZ7ySrw68Vv5M1KfT84IGmMwGOJdXglAl6saHFlw8XMWsSIYuNm1cg3ky1ZE/Gldt09r5H3Q5ygctvU8nJ1R2yhccnamoVtrPRixDduza7L9gSWPIltCI26kizBKMKEN2BRrRm7UbwZddGB5KmsRLwneWzMGj8Z/wtQSwMEFAAACAgA5FFJXZeMLaXeAQAAWAMAAAsAAAByZXBvcnQuanNvbq2SQWvbMBTHv4p518lBcuzY0a3HXsYOGYOVHFRZabzYlpGfWUYwbN2x2yfZJQxKR0o66CeQv9GQ7dLAKLtMp6eH3v//fz+0g0KhSAUK4DsQEhuRv9Nmo0wNnLUEahQGF1mhgLN4zqIgSJIkYlMCaWMEZroEHjA6iyc0ZPPxJARWWa5q4Be7vjpPgUOgFGNqJmIaxolYpasgDGB4+Vo4A2d2pfwm8xuBfqEvs1xN6krJCdZAAFWNg6SrXpT0RTgLI5pMLyMRp1RSGlDhxjPMnckb5nff7aH7bPf22N149mj33nROq633yrMP3Zfu2u67a3uwv7zHH/a3fbAHu7d3rtl98+yx+2rv7a392d3Y28d7IFAZ/UFJHJeQa6OLrCn8VNUb1BUQyLUcUQ04/rlqnpUOeERA6rwpSuDT9pQ4S9h0TkCUpca+5bgsCaC4GivdoNR9HrWtlESVuqAC18Av4O3Zwhs8h8XBDWyAo2kUAaPqJh9JC0Qh14UqcdQ9+Q8Q0GDmM+rT+YJGnIU8opM4Yu+BwMf+D52XqdoCp+2yHUadyg5Qo8iBM/KczV2a8vlKCaxysfnUV/Umq6qx+xSzdYon4F28v9H/d1cCyhhtniBXI/tdS6AQcp2VfZBl+wdQSwECPwMUAAAICADkUUld/j8roMQPAAAziwAAGQAAAAAAAAAAAAAAtIEAAAAAMmVlMTFlNmE3MDQ3OGFmZGYyNDIuanNvblBLAQI/AxQAAAgIAORRSV2XjC2l3gEAAFgDAAALAAAAAAAAAAAAAAC0gfsPAAByZXBvcnQuanNvblBLBQYAAAAAAgACAIAAAAACEgAAAAA=
\ No newline at end of file
diff --git a/tests/e2e/reports/shortcuts-overlay-1780123856118.png b/tests/e2e/reports/shortcuts-overlay-1780123856118.png
new file mode 100644
index 0000000..1df0bf2
Binary files /dev/null and b/tests/e2e/reports/shortcuts-overlay-1780123856118.png differ
diff --git a/tests/e2e/reports/skeleton-table-1780121234164.png b/tests/e2e/reports/skeleton-table-1780121234164.png
new file mode 100644
index 0000000..225ce4e
Binary files /dev/null and b/tests/e2e/reports/skeleton-table-1780121234164.png differ
diff --git a/tests/e2e/reports/stage-2fa-2026-06-07T14-06-13-405Z.md b/tests/e2e/reports/stage-2fa-2026-06-07T14-06-13-405Z.md
new file mode 100644
index 0000000..9f847ca
--- /dev/null
+++ b/tests/e2e/reports/stage-2fa-2026-06-07T14-06-13-405Z.md
@@ -0,0 +1,75 @@
+# E2E report: stage-2fa
+
+Запущен: 2026-06-07T14:06:10.097Z
+Длительность: 3.3с
+
+**Итог:** 6 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 6)
+
+## ✓ Step tfa01_setup_and_status: Создать org → status показывает enabled=false
+
+Длительность: 1258мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /status → 200 | ✓ 200 |
+| api | enabled = false для нового user | ✓ enabled=false |
+
+## ✓ Step tfa02_enroll: POST /api/me/2fa/enroll → sharedKey + otpauth-URI, alreadyEnabled=false
+
+Длительность: 190мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /enroll → 200 | ✓ 200 |
+| api | sharedKey не пустой | ✓ key.len=32 |
+| api | authenticatorUri начинается с otpauth://totp/ | ✓ otpauth://totp/food-market%3astage-2fa-1780841170097%40food-… |
+| api | alreadyEnabled = false | ✓ already=false |
+
+## ✓ Step tfa03_verify_invalid_code: POST /api/me/2fa/verify с кодом 000000 → 400
+
+Длительность: 194мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | verify с 000000 → 400 "Неверный код" | ✓ 400 {"error":"Неверный код. Попробуйте ещё раз.","field":"code"} |
+
+## ✓ Step tfa04_verify_valid_code: POST /api/me/2fa/verify с реальным TOTP кодом → 200, enabled=true
+
+Длительность: 216мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | verify с реальным TOTP-кодом (309514) → 200 | ✓ 200 {"enabled":true} |
+| api | status.enabled = true | ✓ enabled=true |
+
+## ✓ Step tfa05_login_requires_2fa: Логин без otp_code → 400 invalid_grant 2fa_required; с правильным otp_code → 200
+
+Длительность: 1092мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Логин без otp_code → 400 с 2fa_required | ✓ 400 {"error":"invalid_grant","error_description":"2fa_required"} |
+| api | Логин с правильным otp_code (309514) → 200 | ✓ 200 access=yes |
+| api | Логин с неверным otp_code → 400 с 2fa_invalid | ✓ 400 {"error":"invalid_grant","error_description":"2fa_invalid"} |
+
+## ✓ Step tfa06_disable: POST /api/me/2fa/disable с кодом → 200; status показывает enabled=false; повторный enroll выдаёт новый key
+
+Длительность: 355мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | disable без кода → 400 | ✓ 400 {"error":"Подтверди отключение текущим кодом из приложения.","field":"code"} |
+| api | disable с code (309514) → 200, enabled=false | ✓ 200 {"enabled":false} |
+| api | status.enabled = false | ✓ enabled=false |
+| api | Повторный enroll → новый sharedKey (отличается от старого) | ✓ same=false |
+
+## Summary
+
+- Passed: 6
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-audit-log-2026-06-07T13-57-37-072Z.md b/tests/e2e/reports/stage-audit-log-2026-06-07T13-57-37-072Z.md
new file mode 100644
index 0000000..af33df0
--- /dev/null
+++ b/tests/e2e/reports/stage-audit-log-2026-06-07T13-57-37-072Z.md
@@ -0,0 +1,79 @@
+# E2E report: stage-audit-log
+
+Запущен: 2026-06-07T13:57:29.043Z
+Длительность: 8.0с
+
+**Итог:** 7 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 7)
+
+## ✓ Step au01_setup: 2 org, обе имеют свежий audit-log (вероятно с операциями bootstrap+signup)
+
+Длительность: 4792мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/admin/audit-log → 200 для нового tenant | ✓ 200 total=0 |
+
+## ✓ Step au02_create_product_logged: Создание продукта → запись action=create с полями товара в diff
+
+Длительность: 1680мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product → 201 | ✓ 201 |
+| api | GET audit-log по новому product | ✓ 200 total=1 |
+| api | Есть запись action=create с EntityType=Product | ✓ action=create type=Product |
+| api | Diff содержит хотя бы поле Name | ✓ keys=Id,Vat,Cost,Name,Article |
+
+## ✓ Step au03_update_product_logged: PUT продукта → запись action=update с before/after по изменённым полям
+
+Длительность: 666мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | PUT product → 204 | ✓ 204 |
+| api | Есть запись action=update | ✓ action=update |
+| api | Diff содержит Name с before и after | ✓ Name before=Audit Prod 1780840649043 after=Audit Prod UPDATED 1780840649043 |
+
+## ✓ Step au04_delete_product_logged: DELETE продукта → запись action=delete
+
+Длительность: 583мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | DELETE product → 204 | ✓ 204 |
+| api | Есть запись action=delete | ✓ action=delete |
+
+## ✓ Step au05_filter_by_entity_type: GET /audit-log?entityType=Product возвращает только Product-записи
+
+Длительность: 105мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Все записи — Product | ✓ 200 count=3 allProduct=true |
+
+## ✓ Step au06_filter_by_action: GET /audit-log?action=create — все create-записи
+
+Длительность: 109мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Все записи — action=create | ✓ 200 count=5 allCreate=true |
+
+## ✓ Step au07_multi_tenant_isolation: Org B не видит логи Org A
+
+Длительность: 91мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org B не видит записи о продукте Org A | ✓ total=0 sees=false |
+
+## Summary
+
+- Passed: 7
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-audit-log-2026-06-07T14-06-07-436Z.md b/tests/e2e/reports/stage-audit-log-2026-06-07T14-06-07-436Z.md
new file mode 100644
index 0000000..066d45c
--- /dev/null
+++ b/tests/e2e/reports/stage-audit-log-2026-06-07T14-06-07-436Z.md
@@ -0,0 +1,79 @@
+# E2E report: stage-audit-log
+
+Запущен: 2026-06-07T14:06:00.361Z
+Длительность: 7.1с
+
+**Итог:** 7 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 7)
+
+## ✓ Step au01_setup: 2 org, обе имеют свежий audit-log (вероятно с операциями bootstrap+signup)
+
+Длительность: 4514мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/admin/audit-log → 200 для нового tenant | ✓ 200 total=0 |
+
+## ✓ Step au02_create_product_logged: Создание продукта → запись action=create с полями товара в diff
+
+Длительность: 1026мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product → 201 | ✓ 201 |
+| api | GET audit-log по новому product | ✓ 200 total=1 |
+| api | Есть запись action=create с EntityType=Product | ✓ action=create type=Product |
+| api | Diff содержит хотя бы поле Name | ✓ keys=Id,Vat,Cost,Name,Article |
+
+## ✓ Step au03_update_product_logged: PUT продукта → запись action=update с before/after по изменённым полям
+
+Длительность: 648мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | PUT product → 204 | ✓ 204 |
+| api | Есть запись action=update | ✓ action=update |
+| api | Diff содержит Name с before и after | ✓ Name before=Audit Prod 1780841160361 after=Audit Prod UPDATED 1780841160361 |
+
+## ✓ Step au04_delete_product_logged: DELETE продукта → запись action=delete
+
+Длительность: 559мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | DELETE product → 204 | ✓ 204 |
+| api | Есть запись action=delete | ✓ action=delete |
+
+## ✓ Step au05_filter_by_entity_type: GET /audit-log?entityType=Product возвращает только Product-записи
+
+Длительность: 128мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Все записи — Product | ✓ 200 count=3 allProduct=true |
+
+## ✓ Step au06_filter_by_action: GET /audit-log?action=create — все create-записи
+
+Длительность: 105мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Все записи — action=create | ✓ 200 count=5 allCreate=true |
+
+## ✓ Step au07_multi_tenant_isolation: Org B не видит логи Org A
+
+Длительность: 92мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org B не видит записи о продукте Org A | ✓ total=0 sees=false |
+
+## Summary
+
+- Passed: 7
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-audit-log-2026-06-07T18-13-10-030Z.md b/tests/e2e/reports/stage-audit-log-2026-06-07T18-13-10-030Z.md
new file mode 100644
index 0000000..5d0b7d3
--- /dev/null
+++ b/tests/e2e/reports/stage-audit-log-2026-06-07T18-13-10-030Z.md
@@ -0,0 +1,79 @@
+# E2E report: stage-audit-log
+
+Запущен: 2026-06-07T18:13:03.200Z
+Длительность: 6.8с
+
+**Итог:** 7 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 7)
+
+## ✓ Step au01_setup: 2 org, обе имеют свежий audit-log (вероятно с операциями bootstrap+signup)
+
+Длительность: 4207мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/admin/audit-log → 200 для нового tenant | ✓ 200 total=0 |
+
+## ✓ Step au02_create_product_logged: Создание продукта → запись action=create с полями товара в diff
+
+Длительность: 1086мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product → 201 | ✓ 201 |
+| api | GET audit-log по новому product | ✓ 200 total=1 |
+| api | Есть запись action=create с EntityType=Product | ✓ action=create type=Product |
+| api | Diff содержит хотя бы поле Name | ✓ keys=Id,Vat,Cost,Name,Article |
+
+## ✓ Step au03_update_product_logged: PUT продукта → запись action=update с before/after по изменённым полям
+
+Длительность: 646мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | PUT product → 204 | ✓ 204 |
+| api | Есть запись action=update | ✓ action=update |
+| api | Diff содержит Name с before и after | ✓ Name before=Audit Prod 1780855983200 after=Audit Prod UPDATED 1780855983200 |
+
+## ✓ Step au04_delete_product_logged: DELETE продукта → запись action=delete
+
+Длительность: 605мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | DELETE product → 204 | ✓ 204 |
+| api | Есть запись action=delete | ✓ action=delete |
+
+## ✓ Step au05_filter_by_entity_type: GET /audit-log?entityType=Product возвращает только Product-записи
+
+Длительность: 95мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Все записи — Product | ✓ 200 count=3 allProduct=true |
+
+## ✓ Step au06_filter_by_action: GET /audit-log?action=create — все create-записи
+
+Длительность: 98мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Все записи — action=create | ✓ 200 count=5 allCreate=true |
+
+## ✓ Step au07_multi_tenant_isolation: Org B не видит логи Org A
+
+Длительность: 91мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org B не видит записи о продукте Org A | ✓ total=0 sees=false |
+
+## Summary
+
+- Passed: 7
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-catalog-2026-06-07T13-58-45-067Z.md b/tests/e2e/reports/stage-catalog-2026-06-07T13-58-45-067Z.md
new file mode 100644
index 0000000..0a3a867
--- /dev/null
+++ b/tests/e2e/reports/stage-catalog-2026-06-07T13-58-45-067Z.md
@@ -0,0 +1,91 @@
+# E2E report: stage-catalog
+
+Запущен: 2026-06-07T13:58:37.991Z
+Длительность: 7.1с
+
+**Итог:** 6 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 6)
+
+## ✓ Step cat01_setup_two_orgs: Создаём 2 свежие org через signup → 2 admin токена для multi-tenant проверок
+
+Длительность: 3406мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org A создана, refs загружены | ✓ org=184839c6 group=true price=true cur=true unit=true |
+| api | Org B создана, refs загружены | ✓ org=363174c7 |
+| api | Org A и Org B — разные organizationId | ✓ 184839c6-5b6c-4404-bab8-6f3954460302 vs 363174c7-c36e-4b7d-97b4-079580aabf8c |
+| api | Корневая группа «Все товары» у org A и B — разные записи | ✓ A.root=a5d7b2b3-17ed-4aed-a9b9-a163d8b637bd B.root=e33a2819-edfe-407f-b523-ab7dd10d595c |
+
+## ✓ Step cat02_product_group_crud: Группы — создать корневую и дочернюю, обновить, удалить пустую, отказ на удалении с подгруппами
+
+Длительность: 631мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product-groups (root) → 201 | ✓ 201 {"id":"bf1fe062-61bf-4ba6-ac0e-915aa3079bfa","name":"Группа 1780840717991","parentId":null,"path":"Группа 1780840717991","sortOrder":10,"markupPercent":30,"organizationId":"184839c6-5b6c-4404-bab8 |
+| api | OrganizationId назначен автоматически (мультитенантность) | ✓ 184839c6-5b6c-4404-bab8-6f3954460302 vs 184839c6-5b6c-4404-bab8-6f3954460302 |
+| api | POST product-groups (child) → 201, path "Группа .../Подгруппа A" | ✓ 201 path="Группа 1780840717991/Подгруппа A" |
+| api | PUT product-groups child → 204 | ✓ 204 |
+| api | DELETE root c подгруппой → 400 "Нельзя удалить группу с подгруппами" | ✓ 400 {"error":"Нельзя удалить группу с подгруппами"} |
+| api | DELETE child (без товаров) → 204 | ✓ 204 |
+| api | Cleanup DELETE root (теперь без детей) → 204 | ✓ 204 |
+
+## ✓ Step cat03_product_crud: Товар — создать, обновить, прочитать, удалить; дубликат штрихкода → 400; дубликат артикула → 400
+
+Длительность: 984мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product → 201 | ✓ 201 {"id":"cc6231b7-f5a9-4c20-a699-28820a1e31d3","name":"Product 1780840717991 A","article":"ART-1780840717991-A1","description":"тестовый","unitOfMeasureId":"05247198-ae35-4842-a579-08b4bb0aac4f","un |
+| api | GET product by id → 200 | ✓ 200 article=ART-1780840717991-A1 |
+| api | PUT product → 204 | ✓ 204 |
+| api | POST с дубликатом штрихкода → 400 "уже используется" | ✓ 400 {"error":"Штрихкод 2007220300017 уже используется товаром «Product 1780840717991 A (upd)»."} |
+| api | POST с дубликатом article → 400 "Артикул уже занят" | ✓ 400 {"error":"Артикул «ART-1780840717991-A1» уже занят в этой организации."} |
+| api | GET products?search возвращает наш product | ✓ 200 total=1 |
+
+## ✓ Step cat04_counterparty_crud: Контрагент — создать (юрлицо + физлицо), валидация телефона, FK-защита при удалении использованного
+
+Длительность: 787мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST counterparty (Legal) → 201 | ✓ 201 {"id":"c8fad59d-59e3-4dd2-b06c-aaa4ed638a5f","name":"ТОО Тест 1780840717991","legalName":"ТОО Тест-Полное 1780840717991","type":1,"bin":"999888777666","iin":null,"taxNumber":null,"countryId":null, |
+| api | POST counterparty (Individual) → 201 | ✓ 201 {"id":"e11ca221-a78e-4d48-b2ff-3542673afdc1","name":"Иванов И.И. 1780840717991","legalName":null,"type":2,"bin":null,"iin":"880101300123","taxNumber":null,"countryId":null,"countryName":null,"addr |
+| api | POST counterparty с кривым телефоном → 400 | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+| api | PUT counterparty → 204 | ✓ 204 |
+
+## ✓ Step cat05_multi_tenant_isolation: Org A не видит товары/группы/контрагентов Org B и наоборот; GET by id чужой сущности → 404
+
+Длительность: 692мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org B GET /products НЕ содержит товар org A | ✓ org B total=0, seenA=false |
+| api | Org B GET /counterparties НЕ содержит контрагента org A | ✓ org B total=0, seenA=false |
+| api | Org B GET /products/{id-чужой} → 404 | ✓ 404 |
+| api | Org B GET /counterparties/{id-чужой} → 404 | ✓ 404 |
+| api | Org B PUT /products/{id-чужой} → 404 (нельзя угнать) | ✓ 404 {"type":"https://tools.ietf.org/html/rfc9110#section-15.5.5","title":"Not Found","status":404,"traceId":"00-707c5a2ea7690baa3be031d841789a87-c520cf6864bb12ab-00"} |
+| api | Org B DELETE /products/{id-чужой} → 404 | ✓ 404 |
+
+## ✓ Step cat06_fk_protection_groups: Удаление группы с товаром → 400, удаление системной «Все товары» → 400
+
+Длительность: 575мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | DELETE системной «Все товары» → 400 "Системную группу" | ✓ 400 {"error":"Системную группу удалить нельзя."} |
+| api | PUT product → перевешиваем в новую группу | ✓ 204 |
+| api | DELETE не-системной группы с привязанным товаром → 400 "товарами" | ✓ 400 {"error":"Нельзя удалить группу с товарами"} |
+| api | DELETE product → 204 | ✓ 204 |
+| api | DELETE пустой группы (после удаления товара) → 204 | ✓ 204 |
+
+## Summary
+
+- Passed: 6
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-catalog-2026-06-07T16-17-03-263Z.md b/tests/e2e/reports/stage-catalog-2026-06-07T16-17-03-263Z.md
new file mode 100644
index 0000000..ae50be3
--- /dev/null
+++ b/tests/e2e/reports/stage-catalog-2026-06-07T16-17-03-263Z.md
@@ -0,0 +1,91 @@
+# E2E report: stage-catalog
+
+Запущен: 2026-06-07T16:16:54.485Z
+Длительность: 8.8с
+
+**Итог:** 6 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 6)
+
+## ✓ Step cat01_setup_two_orgs: Создаём 2 свежие org через signup → 2 admin токена для multi-tenant проверок
+
+Длительность: 3715мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org A создана, refs загружены | ✓ org=8144732f group=true price=true cur=true unit=true |
+| api | Org B создана, refs загружены | ✓ org=b5743eca |
+| api | Org A и Org B — разные organizationId | ✓ 8144732f-74f7-4d07-ae60-4f4f8e72c4b6 vs b5743eca-e0cf-473f-aa83-cf85d6b70987 |
+| api | Корневая группа «Все товары» у org A и B — разные записи | ✓ A.root=092b21ce-2dae-4544-8d42-85d7d65e04ff B.root=368984b9-bb4a-44b7-8ac8-15ffec6cb230 |
+
+## ✓ Step cat02_product_group_crud: Группы — создать корневую и дочернюю, обновить, удалить пустую, отказ на удалении с подгруппами
+
+Длительность: 743мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product-groups (root) → 201 | ✓ 201 {"id":"9695c748-8c8b-408c-abd2-534b85c6babd","name":"Группа 1780849014484","parentId":null,"path":"Группа 1780849014484","sortOrder":10,"markupPercent":30,"organizationId":"8144732f-74f7-4d07-ae60 |
+| api | OrganizationId назначен автоматически (мультитенантность) | ✓ 8144732f-74f7-4d07-ae60-4f4f8e72c4b6 vs 8144732f-74f7-4d07-ae60-4f4f8e72c4b6 |
+| api | POST product-groups (child) → 201, path "Группа .../Подгруппа A" | ✓ 201 path="Группа 1780849014484/Подгруппа A" |
+| api | PUT product-groups child → 204 | ✓ 204 |
+| api | DELETE root c подгруппой → 400 "Нельзя удалить группу с подгруппами" | ✓ 400 {"error":"Нельзя удалить группу с подгруппами"} |
+| api | DELETE child (без товаров) → 204 | ✓ 204 |
+| api | Cleanup DELETE root (теперь без детей) → 204 | ✓ 204 |
+
+## ✓ Step cat03_product_crud: Товар — создать, обновить, прочитать, удалить; дубликат штрихкода → 400; дубликат артикула → 400
+
+Длительность: 2191мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product → 201 | ✓ 201 {"id":"1d0f6d32-a501-4604-b3ef-2800390556e4","name":"Product 1780849014484 A","article":"ART-1780849014484-A1","description":"тестовый","unitOfMeasureId":"05247198-ae35-4842-a579-08b4bb0aac4f","un |
+| api | GET product by id → 200 | ✓ 200 article=ART-1780849014484-A1 |
+| api | PUT product → 204 | ✓ 204 |
+| api | POST с дубликатом штрихкода → 400 "уже используется" | ✓ 400 {"error":"Штрихкод 2090189440016 уже используется товаром «Product 1780849014484 A (upd)»."} |
+| api | POST с дубликатом article → 400 "Артикул уже занят" | ✓ 400 {"error":"Артикул «ART-1780849014484-A1» уже занят в этой организации."} |
+| api | GET products?search возвращает наш product | ✓ 200 total=1 |
+
+## ✓ Step cat04_counterparty_crud: Контрагент — создать (юрлицо + физлицо), валидация телефона, FK-защита при удалении использованного
+
+Длительность: 649мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST counterparty (Legal) → 201 | ✓ 201 {"id":"a9f7b3d2-bf9f-469c-ac39-f2d4a9ba9f61","name":"ТОО Тест 1780849014484","legalName":"ТОО Тест-Полное 1780849014484","type":1,"bin":"999888777666","iin":null,"taxNumber":null,"countryId":null, |
+| api | POST counterparty (Individual) → 201 | ✓ 201 {"id":"e54c80db-1355-415f-b72e-bc59020cea14","name":"Иванов И.И. 1780849014484","legalName":null,"type":2,"bin":null,"iin":"880101300123","taxNumber":null,"countryId":null,"countryName":null,"addr |
+| api | POST counterparty с кривым телефоном → 400 | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+| api | PUT counterparty → 204 | ✓ 204 |
+
+## ✓ Step cat05_multi_tenant_isolation: Org A не видит товары/группы/контрагентов Org B и наоборот; GET by id чужой сущности → 404
+
+Длительность: 883мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org B GET /products НЕ содержит товар org A | ✓ org B total=0, seenA=false |
+| api | Org B GET /counterparties НЕ содержит контрагента org A | ✓ org B total=0, seenA=false |
+| api | Org B GET /products/{id-чужой} → 404 | ✓ 404 |
+| api | Org B GET /counterparties/{id-чужой} → 404 | ✓ 404 |
+| api | Org B PUT /products/{id-чужой} → 404 (нельзя угнать) | ✓ 404 {"type":"https://tools.ietf.org/html/rfc9110#section-15.5.5","title":"Not Found","status":404,"traceId":"00-f21a9254b0579431d5f8e08cd1ee7c0d-b19fb621169572e9-00"} |
+| api | Org B DELETE /products/{id-чужой} → 404 | ✓ 404 |
+
+## ✓ Step cat06_fk_protection_groups: Удаление группы с товаром → 400, удаление системной «Все товары» → 400
+
+Длительность: 596мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | DELETE системной «Все товары» → 400 "Системную группу" | ✓ 400 {"error":"Системную группу удалить нельзя."} |
+| api | PUT product → перевешиваем в новую группу | ✓ 204 |
+| api | DELETE не-системной группы с привязанным товаром → 400 "товарами" | ✓ 400 {"error":"Нельзя удалить группу с товарами"} |
+| api | DELETE product → 204 | ✓ 204 |
+| api | DELETE пустой группы (после удаления товара) → 204 | ✓ 204 |
+
+## Summary
+
+- Passed: 6
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-catalog-2026-06-07T16-58-49-019Z.md b/tests/e2e/reports/stage-catalog-2026-06-07T16-58-49-019Z.md
new file mode 100644
index 0000000..1b3d836
--- /dev/null
+++ b/tests/e2e/reports/stage-catalog-2026-06-07T16-58-49-019Z.md
@@ -0,0 +1,91 @@
+# E2E report: stage-catalog
+
+Запущен: 2026-06-07T16:58:40.448Z
+Длительность: 8.6с
+
+**Итог:** 6 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 6)
+
+## ✓ Step cat01_setup_two_orgs: Создаём 2 свежие org через signup → 2 admin токена для multi-tenant проверок
+
+Длительность: 3516мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org A создана, refs загружены | ✓ org=948662c3 group=true price=true cur=true unit=true |
+| api | Org B создана, refs загружены | ✓ org=47460702 |
+| api | Org A и Org B — разные organizationId | ✓ 948662c3-4b0d-4a6b-9010-f4a1021306e1 vs 47460702-9e9e-4e8f-81cb-6465623dbe44 |
+| api | Корневая группа «Все товары» у org A и B — разные записи | ✓ A.root=cde338ec-d163-4890-83f8-50223e44f1e1 B.root=ac8de726-3443-4ed9-a805-6fea74c3c93b |
+
+## ✓ Step cat02_product_group_crud: Группы — создать корневую и дочернюю, обновить, удалить пустую, отказ на удалении с подгруппами
+
+Длительность: 757мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product-groups (root) → 201 | ✓ 201 {"id":"aaa7f2b1-498e-4801-be9b-dc2f36878eb2","name":"Группа 1780851520448","parentId":null,"path":"Группа 1780851520448","sortOrder":10,"markupPercent":30,"organizationId":"948662c3-4b0d-4a6b-9010 |
+| api | OrganizationId назначен автоматически (мультитенантность) | ✓ 948662c3-4b0d-4a6b-9010-f4a1021306e1 vs 948662c3-4b0d-4a6b-9010-f4a1021306e1 |
+| api | POST product-groups (child) → 201, path "Группа .../Подгруппа A" | ✓ 201 path="Группа 1780851520448/Подгруппа A" |
+| api | PUT product-groups child → 204 | ✓ 204 |
+| api | DELETE root c подгруппой → 400 "Нельзя удалить группу с подгруппами" | ✓ 400 {"error":"Нельзя удалить группу с подгруппами"} |
+| api | DELETE child (без товаров) → 204 | ✓ 204 |
+| api | Cleanup DELETE root (теперь без детей) → 204 | ✓ 204 |
+
+## ✓ Step cat03_product_crud: Товар — создать, обновить, прочитать, удалить; дубликат штрихкода → 400; дубликат артикула → 400
+
+Длительность: 2247мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product → 201 | ✓ 201 {"id":"4ecc3414-32db-4f2b-b144-974eeae44f64","name":"Product 1780851520448 A","article":"ART-1780851520448-A1","description":"тестовый","unitOfMeasureId":"05247198-ae35-4842-a579-08b4bb0aac4f","un |
+| api | GET product by id → 200 | ✓ 200 article=ART-1780851520448-A1 |
+| api | PUT product → 204 | ✓ 204 |
+| api | POST с дубликатом штрихкода → 400 "уже используется" | ✓ 400 {"error":"Штрихкод 2015247250017 уже используется товаром «Product 1780851520448 A (upd)»."} |
+| api | POST с дубликатом article → 400 "Артикул уже занят" | ✓ 400 {"error":"Артикул «ART-1780851520448-A1» уже занят в этой организации."} |
+| api | GET products?search возвращает наш product | ✓ 200 total=1 |
+
+## ✓ Step cat04_counterparty_crud: Контрагент — создать (юрлицо + физлицо), валидация телефона, FK-защита при удалении использованного
+
+Длительность: 706мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST counterparty (Legal) → 201 | ✓ 201 {"id":"bf12c684-148e-4ab2-ad68-05f8a76f8b6b","name":"ТОО Тест 1780851520448","legalName":"ТОО Тест-Полное 1780851520448","type":1,"bin":"999888777666","iin":null,"taxNumber":null,"countryId":null, |
+| api | POST counterparty (Individual) → 201 | ✓ 201 {"id":"e2a3e77f-cd93-4635-9b2f-8578d7fae226","name":"Иванов И.И. 1780851520448","legalName":null,"type":2,"bin":null,"iin":"880101300123","taxNumber":null,"countryId":null,"countryName":null,"addr |
+| api | POST counterparty с кривым телефоном → 400 | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+| api | PUT counterparty → 204 | ✓ 204 |
+
+## ✓ Step cat05_multi_tenant_isolation: Org A не видит товары/группы/контрагентов Org B и наоборот; GET by id чужой сущности → 404
+
+Длительность: 739мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org B GET /products НЕ содержит товар org A | ✓ org B total=0, seenA=false |
+| api | Org B GET /counterparties НЕ содержит контрагента org A | ✓ org B total=0, seenA=false |
+| api | Org B GET /products/{id-чужой} → 404 | ✓ 404 |
+| api | Org B GET /counterparties/{id-чужой} → 404 | ✓ 404 |
+| api | Org B PUT /products/{id-чужой} → 404 (нельзя угнать) | ✓ 404 {"type":"https://tools.ietf.org/html/rfc9110#section-15.5.5","title":"Not Found","status":404,"traceId":"00-409eace60f49851a0ac9438a139898b1-205c83e20b6cf748-00"} |
+| api | Org B DELETE /products/{id-чужой} → 404 | ✓ 404 |
+
+## ✓ Step cat06_fk_protection_groups: Удаление группы с товаром → 400, удаление системной «Все товары» → 400
+
+Длительность: 603мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | DELETE системной «Все товары» → 400 "Системную группу" | ✓ 400 {"error":"Системную группу удалить нельзя."} |
+| api | PUT product → перевешиваем в новую группу | ✓ 204 |
+| api | DELETE не-системной группы с привязанным товаром → 400 "товарами" | ✓ 400 {"error":"Нельзя удалить группу с товарами"} |
+| api | DELETE product → 204 | ✓ 204 |
+| api | DELETE пустой группы (после удаления товара) → 204 | ✓ 204 |
+
+## Summary
+
+- Passed: 6
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-catalog-2026-06-07T20-40-26-432Z.md b/tests/e2e/reports/stage-catalog-2026-06-07T20-40-26-432Z.md
new file mode 100644
index 0000000..ae4e339
--- /dev/null
+++ b/tests/e2e/reports/stage-catalog-2026-06-07T20-40-26-432Z.md
@@ -0,0 +1,91 @@
+# E2E report: stage-catalog
+
+Запущен: 2026-06-07T20:40:19.022Z
+Длительность: 7.4с
+
+**Итог:** 6 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 6)
+
+## ✓ Step cat01_setup_two_orgs: Создаём 2 свежие org через signup → 2 admin токена для multi-tenant проверок
+
+Длительность: 3666мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org A создана, refs загружены | ✓ org=7f0c870a group=true price=true cur=true unit=true |
+| api | Org B создана, refs загружены | ✓ org=ac28e1bd |
+| api | Org A и Org B — разные organizationId | ✓ 7f0c870a-de09-4006-b52c-859881b44932 vs ac28e1bd-1187-4b1f-84b0-b28d97598758 |
+| api | Корневая группа «Все товары» у org A и B — разные записи | ✓ A.root=233e4627-0e0c-4cb4-9841-48e5657cb067 B.root=94b0fa6a-9b67-4add-93a3-4236cbe3c1ec |
+
+## ✓ Step cat02_product_group_crud: Группы — создать корневую и дочернюю, обновить, удалить пустую, отказ на удалении с подгруппами
+
+Длительность: 744мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product-groups (root) → 201 | ✓ 201 {"id":"771749bc-37d1-44c2-a5b9-c74911f057ed","name":"Группа 1780864819022","parentId":null,"path":"Группа 1780864819022","sortOrder":10,"markupPercent":30,"organizationId":"7f0c870a-de09-4006-b52c |
+| api | OrganizationId назначен автоматически (мультитенантность) | ✓ 7f0c870a-de09-4006-b52c-859881b44932 vs 7f0c870a-de09-4006-b52c-859881b44932 |
+| api | POST product-groups (child) → 201, path "Группа .../Подгруппа A" | ✓ 201 path="Группа 1780864819022/Подгруппа A" |
+| api | PUT product-groups child → 204 | ✓ 204 |
+| api | DELETE root c подгруппой → 400 "Нельзя удалить группу с подгруппами" | ✓ 400 {"error":"Нельзя удалить группу с подгруппами"} |
+| api | DELETE child (без товаров) → 204 | ✓ 204 |
+| api | Cleanup DELETE root (теперь без детей) → 204 | ✓ 204 |
+
+## ✓ Step cat03_product_crud: Товар — создать, обновить, прочитать, удалить; дубликат штрихкода → 400; дубликат артикула → 400
+
+Длительность: 1080мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product → 201 | ✓ 201 {"id":"9580229f-b180-42a0-a4ef-3d9ea3a6161d","name":"Product 1780864819022 A","article":"ART-1780864819022-A1","description":"тестовый","unitOfMeasureId":"05247198-ae35-4842-a579-08b4bb0aac4f","un |
+| api | GET product by id → 200 | ✓ 200 article=ART-1780864819022-A1 |
+| api | PUT product → 204 | ✓ 204 |
+| api | POST с дубликатом штрихкода → 400 "уже используется" | ✓ 400 {"error":"Штрихкод 2048234340019 уже используется товаром «Product 1780864819022 A (upd)»."} |
+| api | POST с дубликатом article → 400 "Артикул уже занят" | ✓ 400 {"error":"Артикул «ART-1780864819022-A1» уже занят в этой организации."} |
+| api | GET products?search возвращает наш product | ✓ 200 total=1 |
+
+## ✓ Step cat04_counterparty_crud: Контрагент — создать (юрлицо + физлицо), валидация телефона, FK-защита при удалении использованного
+
+Длительность: 431мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST counterparty (Legal) → 201 | ✓ 201 {"id":"4a0c7ef8-008b-4672-9e1c-8a6a316507c6","name":"ТОО Тест 1780864819022","legalName":"ТОО Тест-Полное 1780864819022","type":1,"bin":"999888777666","iin":null,"taxNumber":null,"countryId":null, |
+| api | POST counterparty (Individual) → 201 | ✓ 201 {"id":"0af6c899-12c4-40f7-8a24-b407c3e64866","name":"Иванов И.И. 1780864819022","legalName":null,"type":2,"bin":null,"iin":"880101300123","taxNumber":null,"countryId":null,"countryName":null,"addr |
+| api | POST counterparty с кривым телефоном → 400 | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+| api | PUT counterparty → 204 | ✓ 204 |
+
+## ✓ Step cat05_multi_tenant_isolation: Org A не видит товары/группы/контрагентов Org B и наоборот; GET by id чужой сущности → 404
+
+Длительность: 827мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org B GET /products НЕ содержит товар org A | ✓ org B total=0, seenA=false |
+| api | Org B GET /counterparties НЕ содержит контрагента org A | ✓ org B total=0, seenA=false |
+| api | Org B GET /products/{id-чужой} → 404 | ✓ 404 |
+| api | Org B GET /counterparties/{id-чужой} → 404 | ✓ 404 |
+| api | Org B PUT /products/{id-чужой} → 404 (нельзя угнать) | ✓ 404 {"type":"https://tools.ietf.org/html/rfc9110#section-15.5.5","title":"Not Found","status":404,"traceId":"00-f11bcbac0e1b626103d264ff0984598e-367a9d95409c807d-00"} |
+| api | Org B DELETE /products/{id-чужой} → 404 | ✓ 404 |
+
+## ✓ Step cat06_fk_protection_groups: Удаление группы с товаром → 400, удаление системной «Все товары» → 400
+
+Длительность: 660мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | DELETE системной «Все товары» → 400 "Системную группу" | ✓ 400 {"error":"Системную группу удалить нельзя."} |
+| api | PUT product → перевешиваем в новую группу | ✓ 204 |
+| api | DELETE не-системной группы с привязанным товаром → 400 "товарами" | ✓ 400 {"error":"Нельзя удалить группу с товарами"} |
+| api | DELETE product → 204 | ✓ 204 |
+| api | DELETE пустой группы (после удаления товара) → 204 | ✓ 204 |
+
+## Summary
+
+- Passed: 6
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-catalog-2026-06-07T21-20-00-912Z.md b/tests/e2e/reports/stage-catalog-2026-06-07T21-20-00-912Z.md
new file mode 100644
index 0000000..b929946
--- /dev/null
+++ b/tests/e2e/reports/stage-catalog-2026-06-07T21-20-00-912Z.md
@@ -0,0 +1,91 @@
+# E2E report: stage-catalog
+
+Запущен: 2026-06-07T21:19:52.228Z
+Длительность: 8.7с
+
+**Итог:** 6 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 6)
+
+## ✓ Step cat01_setup_two_orgs: Создаём 2 свежие org через signup → 2 admin токена для multi-tenant проверок
+
+Длительность: 3531мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org A создана, refs загружены | ✓ org=e1f51ed0 group=true price=true cur=true unit=true |
+| api | Org B создана, refs загружены | ✓ org=a3c8a9c3 |
+| api | Org A и Org B — разные organizationId | ✓ e1f51ed0-9143-4225-b557-9202d0e3f44d vs a3c8a9c3-1b36-4fbe-95c6-a93eb7df5bfd |
+| api | Корневая группа «Все товары» у org A и B — разные записи | ✓ A.root=5bae4f9c-d011-4cd4-ab91-2c250868c7bb B.root=4856374a-037c-40a4-8b26-7cbac0f844e1 |
+
+## ✓ Step cat02_product_group_crud: Группы — создать корневую и дочернюю, обновить, удалить пустую, отказ на удалении с подгруппами
+
+Длительность: 851мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product-groups (root) → 201 | ✓ 201 {"id":"2a85a6a7-e78a-4017-bc7a-599613a256bf","name":"Группа 1780867192227","parentId":null,"path":"Группа 1780867192227","sortOrder":10,"markupPercent":30,"organizationId":"e1f51ed0-9143-4225-b557 |
+| api | OrganizationId назначен автоматически (мультитенантность) | ✓ e1f51ed0-9143-4225-b557-9202d0e3f44d vs e1f51ed0-9143-4225-b557-9202d0e3f44d |
+| api | POST product-groups (child) → 201, path "Группа .../Подгруппа A" | ✓ 201 path="Группа 1780867192227/Подгруппа A" |
+| api | PUT product-groups child → 204 | ✓ 204 |
+| api | DELETE root c подгруппой → 400 "Нельзя удалить группу с подгруппами" | ✓ 400 {"error":"Нельзя удалить группу с подгруппами"} |
+| api | DELETE child (без товаров) → 204 | ✓ 204 |
+| api | Cleanup DELETE root (теперь без детей) → 204 | ✓ 204 |
+
+## ✓ Step cat03_product_crud: Товар — создать, обновить, прочитать, удалить; дубликат штрихкода → 400; дубликат артикула → 400
+
+Длительность: 2077мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST product → 201 | ✓ 201 {"id":"6003e945-4b6e-47f6-aa1c-6ef34b46b5e7","name":"Product 1780867192227 A","article":"ART-1780867192227-A1","description":"тестовый","unitOfMeasureId":"05247198-ae35-4842-a579-08b4bb0aac4f","un |
+| api | GET product by id → 200 | ✓ 200 article=ART-1780867192227-A1 |
+| api | PUT product → 204 | ✓ 204 |
+| api | POST с дубликатом штрихкода → 400 "уже используется" | ✓ 400 {"error":"Штрихкод 2071966110018 уже используется товаром «Product 1780867192227 A (upd)»."} |
+| api | POST с дубликатом article → 400 "Артикул уже занят" | ✓ 400 {"error":"Артикул «ART-1780867192227-A1» уже занят в этой организации."} |
+| api | GET products?search возвращает наш product | ✓ 200 total=1 |
+
+## ✓ Step cat04_counterparty_crud: Контрагент — создать (юрлицо + физлицо), валидация телефона, FK-защита при удалении использованного
+
+Длительность: 659мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST counterparty (Legal) → 201 | ✓ 201 {"id":"3dac25bd-5f10-4ef4-af0c-ba8c96cfb967","name":"ТОО Тест 1780867192227","legalName":"ТОО Тест-Полное 1780867192227","type":1,"bin":"999888777666","iin":null,"taxNumber":null,"countryId":null, |
+| api | POST counterparty (Individual) → 201 | ✓ 201 {"id":"f48384a4-1a0a-487e-a400-17dafc460cf6","name":"Иванов И.И. 1780867192227","legalName":null,"type":2,"bin":null,"iin":"880101300123","taxNumber":null,"countryId":null,"countryName":null,"addr |
+| api | POST counterparty с кривым телефоном → 400 | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+| api | PUT counterparty → 204 | ✓ 204 |
+
+## ✓ Step cat05_multi_tenant_isolation: Org A не видит товары/группы/контрагентов Org B и наоборот; GET by id чужой сущности → 404
+
+Длительность: 864мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org B GET /products НЕ содержит товар org A | ✓ org B total=0, seenA=false |
+| api | Org B GET /counterparties НЕ содержит контрагента org A | ✓ org B total=0, seenA=false |
+| api | Org B GET /products/{id-чужой} → 404 | ✓ 404 |
+| api | Org B GET /counterparties/{id-чужой} → 404 | ✓ 404 |
+| api | Org B PUT /products/{id-чужой} → 404 (нельзя угнать) | ✓ 404 {"type":"https://tools.ietf.org/html/rfc9110#section-15.5.5","title":"Not Found","status":404,"traceId":"00-77d1fb79e75dc1daed66dff97d7ee908-84900b97b79c958b-00"} |
+| api | Org B DELETE /products/{id-чужой} → 404 | ✓ 404 |
+
+## ✓ Step cat06_fk_protection_groups: Удаление группы с товаром → 400, удаление системной «Все товары» → 400
+
+Длительность: 701мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | DELETE системной «Все товары» → 400 "Системную группу" | ✓ 400 {"error":"Системную группу удалить нельзя."} |
+| api | PUT product → перевешиваем в новую группу | ✓ 204 |
+| api | DELETE не-системной группы с привязанным товаром → 400 "товарами" | ✓ 400 {"error":"Нельзя удалить группу с товарами"} |
+| api | DELETE product → 204 | ✓ 204 |
+| api | DELETE пустой группы (после удаления товара) → 204 | ✓ 204 |
+
+## Summary
+
+- Passed: 6
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-demo-seed-2026-05-29T14-22-03-022Z.md b/tests/e2e/reports/stage-demo-seed-2026-05-29T14-22-03-022Z.md
new file mode 100644
index 0000000..68c7d8f
--- /dev/null
+++ b/tests/e2e/reports/stage-demo-seed-2026-05-29T14-22-03-022Z.md
@@ -0,0 +1,69 @@
+# E2E report: stage-demo-seed
+
+Запущен: 2026-05-29T14:21:55.274Z
+Длительность: 7.7с
+
+**Итог:** 1 ✓ / 4 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✓ Step seed01_status_empty: Новый org → GET /api/admin/seed-demo/status → alreadySeeded=false, products=0
+
+Длительность: 4027мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /status → 200 | ✓ 200 |
+| api | alreadySeeded = false | ✓ already=false |
+| api | products = 0 | ✓ products=0 |
+
+## ✗ Step seed02_run: POST /api/admin/seed-demo → 200, alreadySeeded=false, products>=50
+
+Длительность: 1805мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /seed-demo → 200 | ✗ 500 |
+
+## ✗ Step seed03_status_after: GET /status → alreadySeeded=true; products=50, supplies=5, sales=30, demands=1, losses=1, transfers=1, inventories=1, stores=2
+
+Длительность: 148мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /status → alreadySeeded=true | ✗ already=false |
+| api | products = 50 в статусе | ✗ products=0 |
+
+## ✗ Step seed04_data_visible_via_normal_apis: GET /api/catalog/products, /api/purchases/supplies, /api/sales/retail, /api/inventory/transfers — содержат демо-записи
+
+Длительность: 646мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | products total >= 50 | ✗ total=0 |
+| api | supplies total >= 5 | ✗ total=0 |
+| api | retail sales total >= 30 | ✗ total=0 |
+| api | demands total >= 1 | ✗ total=0 |
+| api | transfers total >= 1 | ✗ total=0 |
+| api | inventories total >= 1 | ✗ total=0 |
+| api | counterparties total >= 10 | ✗ total=0 |
+| api | Все 50 demo-товаров имеют article DEMO-... | ✗ demoCount=0 |
+
+## ✗ Step seed05_idempotent: Повторный POST /api/admin/seed-demo → products всё ещё 50 (не дублировано)
+
+Длительность: 1121мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Повторный POST → 200, alreadySeeded=true | ✗ 500 already=undefined |
+| api | products = 50 (не дублировано) | ✗ products=undefined |
+| api | products total всё ещё 50 | ✗ total=0 |
+
+## Summary
+
+- Passed: 1
+- Failed: 4
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-demo-seed-2026-05-30T05-15-39-985Z.md b/tests/e2e/reports/stage-demo-seed-2026-05-30T05-15-39-985Z.md
new file mode 100644
index 0000000..6ba096d
--- /dev/null
+++ b/tests/e2e/reports/stage-demo-seed-2026-05-30T05-15-39-985Z.md
@@ -0,0 +1,69 @@
+# E2E report: stage-demo-seed
+
+Запущен: 2026-05-30T05:15:34.679Z
+Длительность: 5.3с
+
+**Итог:** 0 ✓ / 5 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✗ Step seed01_status_empty: Новый org → GET /api/admin/seed-demo/status → alreadySeeded=false, products=0
+
+Длительность: 4364мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /status → 200 | ✗ 404 |
+| api | alreadySeeded = false | ✗ already=undefined |
+| api | products = 0 | ✗ products=undefined |
+
+## ✗ Step seed02_run: POST /api/admin/seed-demo → 200, alreadySeeded=false, products>=50
+
+Длительность: 15мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /seed-demo → 200 | ✗ 404 |
+
+## ✗ Step seed03_status_after: GET /status → alreadySeeded=true; products=50, supplies=5, sales=30, demands=1, losses=1, transfers=1, inventories=1, stores=2
+
+Длительность: 10мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /status → alreadySeeded=true | ✗ already=undefined |
+| api | products = 50 в статусе | ✗ products=undefined |
+
+## ✗ Step seed04_data_visible_via_normal_apis: GET /api/catalog/products, /api/purchases/supplies, /api/sales/retail, /api/inventory/transfers — содержат демо-записи
+
+Длительность: 829мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | products total >= 50 | ✗ total=0 |
+| api | supplies total >= 5 | ✗ total=0 |
+| api | retail sales total >= 30 | ✗ total=0 |
+| api | demands total >= 1 | ✗ total=0 |
+| api | transfers total >= 1 | ✗ total=0 |
+| api | inventories total >= 1 | ✗ total=0 |
+| api | counterparties total >= 10 | ✗ total=0 |
+| api | Все 50 demo-товаров имеют article DEMO-... | ✗ demoCount=0 |
+
+## ✗ Step seed05_idempotent: Повторный POST /api/admin/seed-demo → products всё ещё 50 (не дублировано)
+
+Длительность: 88мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Повторный POST → 200, alreadySeeded=true | ✗ 404 already=undefined |
+| api | products = 50 (не дублировано) | ✗ products=undefined |
+| api | products total всё ещё 50 | ✗ total=0 |
+
+## Summary
+
+- Passed: 0
+- Failed: 5
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-demo-seed-2026-05-30T05-16-30-459Z.md b/tests/e2e/reports/stage-demo-seed-2026-05-30T05-16-30-459Z.md
new file mode 100644
index 0000000..f440c7d
--- /dev/null
+++ b/tests/e2e/reports/stage-demo-seed-2026-05-30T05-16-30-459Z.md
@@ -0,0 +1,76 @@
+# E2E report: stage-demo-seed
+
+Запущен: 2026-05-30T05:16:20.036Z
+Длительность: 10.4с
+
+**Итог:** 5 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✓ Step seed01_status_empty: Новый org → GET /api/admin/seed-demo/status → alreadySeeded=false, products=0
+
+Длительность: 3658мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /status → 200 | ✓ 200 |
+| api | alreadySeeded = false | ✓ already=false |
+| api | products = 0 | ✓ products=0 |
+
+## ✓ Step seed02_run: POST /api/admin/seed-demo → 200, alreadySeeded=false, products>=50
+
+Длительность: 6246мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /seed-demo → 200 | ✓ 200 {"alreadySeeded":false,"groups":5,"products":50,"counterparties":10,"supplies":5,"sales":30,"demands":1,"losses":1,"transfers":1,"inventories":1,"stores":2} |
+| api | alreadySeeded в ответе = false (только что заполнили) | ✓ already=false |
+| api | products = 50 | ✓ products=50 |
+| api | groups = 5 | ✓ groups=5 |
+| api | counterparties = 10 | ✓ cp=10 |
+| api | supplies = 5, sales = 30 | ✓ sup=5 sales=30 |
+| api | demands=1, losses=1, transfers=1, inventories=1 | ✓ dm=1 loss=1 tr=1 inv=1 |
+| api | stores >= 2 (main + резерв для transfer) | ✓ stores=2 |
+
+## ✓ Step seed03_status_after: GET /status → alreadySeeded=true; products=50, supplies=5, sales=30, demands=1, losses=1, transfers=1, inventories=1, stores=2
+
+Длительность: 45мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /status → alreadySeeded=true | ✓ already=true |
+| api | products = 50 в статусе | ✓ products=50 |
+
+## ✓ Step seed04_data_visible_via_normal_apis: GET /api/catalog/products, /api/purchases/supplies, /api/sales/retail, /api/inventory/transfers — содержат демо-записи
+
+Длительность: 383мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | products total >= 50 | ✓ total=50 |
+| api | supplies total >= 5 | ✓ total=5 |
+| api | retail sales total >= 30 | ✓ total=30 |
+| api | demands total >= 1 | ✓ total=1 |
+| api | transfers total >= 1 | ✓ total=1 |
+| api | inventories total >= 1 | ✓ total=1 |
+| api | counterparties total >= 10 | ✓ total=10 |
+| api | Все 50 demo-товаров имеют article DEMO-... | ✓ demoCount=50 |
+
+## ✓ Step seed05_idempotent: Повторный POST /api/admin/seed-demo → products всё ещё 50 (не дублировано)
+
+Длительность: 90мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Повторный POST → 200, alreadySeeded=true | ✓ 200 already=true |
+| api | products = 50 (не дублировано) | ✓ products=50 |
+| api | products total всё ещё 50 | ✓ total=50 |
+
+## Summary
+
+- Passed: 5
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-demo-seed-2026-05-30T05-21-42-234Z.md b/tests/e2e/reports/stage-demo-seed-2026-05-30T05-21-42-234Z.md
new file mode 100644
index 0000000..ce39e91
--- /dev/null
+++ b/tests/e2e/reports/stage-demo-seed-2026-05-30T05-21-42-234Z.md
@@ -0,0 +1,76 @@
+# E2E report: stage-demo-seed
+
+Запущен: 2026-05-30T05:21:28.246Z
+Длительность: 14.0с
+
+**Итог:** 5 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✓ Step seed01_status_empty: Новый org → GET /api/admin/seed-demo/status → alreadySeeded=false, products=0
+
+Длительность: 4498мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /status → 200 | ✓ 200 |
+| api | alreadySeeded = false | ✓ already=false |
+| api | products = 0 | ✓ products=0 |
+
+## ✓ Step seed02_run: POST /api/admin/seed-demo → 200, alreadySeeded=false, products>=50
+
+Длительность: 7782мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /seed-demo → 200 | ✓ 200 {"alreadySeeded":false,"groups":5,"products":50,"counterparties":10,"supplies":5,"sales":30,"demands":1,"losses":1,"transfers":1,"inventories":1,"stores":2} |
+| api | alreadySeeded в ответе = false (только что заполнили) | ✓ already=false |
+| api | products = 50 | ✓ products=50 |
+| api | groups = 5 | ✓ groups=5 |
+| api | counterparties = 10 | ✓ cp=10 |
+| api | supplies = 5, sales = 30 | ✓ sup=5 sales=30 |
+| api | demands=1, losses=1, transfers=1, inventories=1 | ✓ dm=1 loss=1 tr=1 inv=1 |
+| api | stores >= 2 (main + резерв для transfer) | ✓ stores=2 |
+
+## ✓ Step seed03_status_after: GET /status → alreadySeeded=true; products=50, supplies=5, sales=30, demands=1, losses=1, transfers=1, inventories=1, stores=2
+
+Длительность: 254мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /status → alreadySeeded=true | ✓ already=true |
+| api | products = 50 в статусе | ✓ products=50 |
+
+## ✓ Step seed04_data_visible_via_normal_apis: GET /api/catalog/products, /api/purchases/supplies, /api/sales/retail, /api/inventory/transfers — содержат демо-записи
+
+Длительность: 975мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | products total >= 50 | ✓ total=50 |
+| api | supplies total >= 5 | ✓ total=5 |
+| api | retail sales total >= 30 | ✓ total=30 |
+| api | demands total >= 1 | ✓ total=1 |
+| api | transfers total >= 1 | ✓ total=1 |
+| api | inventories total >= 1 | ✓ total=1 |
+| api | counterparties total >= 10 | ✓ total=10 |
+| api | Все 50 demo-товаров имеют article DEMO-... | ✓ demoCount=50 |
+
+## ✓ Step seed05_idempotent: Повторный POST /api/admin/seed-demo → products всё ещё 50 (не дублировано)
+
+Длительность: 478мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Повторный POST → 200, alreadySeeded=true | ✓ 200 already=true |
+| api | products = 50 (не дублировано) | ✓ products=50 |
+| api | products total всё ещё 50 | ✓ total=50 |
+
+## Summary
+
+- Passed: 5
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-inventory-2026-06-07T13-58-54-586Z.md b/tests/e2e/reports/stage-inventory-2026-06-07T13-58-54-586Z.md
new file mode 100644
index 0000000..5f2c59d
--- /dev/null
+++ b/tests/e2e/reports/stage-inventory-2026-06-07T13-58-54-586Z.md
@@ -0,0 +1,98 @@
+# E2E report: stage-inventory
+
+Запущен: 2026-06-07T13:58:47.024Z
+Длительность: 7.6с
+
+**Итог:** 8 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 8)
+
+## ✓ Step inv01_setup: 2 org. У org A — продукт1 (qty=50) + продукт2 (qty=80) через Enter
+
+Длительность: 4661мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Enter posted (initial stock) | ✓ 204 |
+| api | Stock: p1=50, p2=80 | ✓ p1=50 p2=80 |
+
+## ✓ Step inv02_create_draft_autopopulate: POST /api/inventory/inventories без Lines → автозаполнение всех товаров склада с book = текущий stock
+
+Длительность: 533мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST inventories без Lines → 201 | ✓ 201 {"id":"e003df93-819d-4415-ac85-9f9ce93fee39","number":"И-2026-000001","date":"2026-06-07T13:58:51.687Z","status":0,"storeId":"72db20fc-c58e-4752-a790-0a5525174fd3","storeName":"Основной склад","no |
+| api | Авто-Lines содержат оба товара с bookQty = текущий stock | ✓ p1.book=50 p2.book=80 |
+| api | Auto: ActualQty=0, Diff=-bookQty | ✓ p1.actual=0 p1.diff=-50 |
+
+## ✓ Step inv03_create_draft_explicit_lines: POST с явными Lines — book подгружается, diff = actual - book
+
+Длительность: 265мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST с явными Lines → 201 | ✓ 201 |
+| api | p1: book=50, actual=48, diff=-2 | ✓ book=50 actual=48 diff=-2 |
+| api | p2: book=80, actual=85, diff=+5 | ✓ book=80 actual=85 diff=5 |
+
+## ✓ Step inv04_update_actual_quantities: PUT — поменять ActualQty по строкам, Diff пересчитан (фикс EF8)
+
+Длительность: 245мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | PUT inventory → 204 (фикс EF8 на nav-collection) | ✓ 204 |
+| api | После PUT: p1.actual=49,diff=-1; p2.actual=82,diff=+2 | ✓ p1.actual=49 diff=-1; p2.actual=82 diff=2 |
+
+## ✓ Step inv05_post_creates_adjustment_movements: POST /post → 204; StockMovement type=InventoryAdjustment с qty=diff; Stock приведён к фактическому
+
+Длительность: 744мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /post → 204 | ✓ 204 |
+| api | p1: stock -=1 (был 50→49) | ✓ 50 → 49 |
+| api | p2: stock +=2 (был 80→82) | ✓ 80 → 82 |
+| api | Создано 2 StockMovement type=InventoryAdjustment | ✓ count=2 types=InventoryAdjustment |
+
+## ✓ Step inv06_unpost: POST /unpost → 204; Stock восстановлен; Status=Draft
+
+Длительность: 654мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /unpost → 204 | ✓ 204 |
+| api | p1: stock +1 обратно (49→50) | ✓ 49 → 50 |
+| api | p2: stock -2 обратно (82→80) | ✓ 82 → 80 |
+| api | Status=Draft (0) | ✓ status=0 |
+
+## ✓ Step inv07_multi_tenant_isolation: Org B не видит inventory org A
+
+Длительность: 224мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Org B не видит inventory org A | ✓ total=0 sees=false |
+| api | GET чужого id → 404 | ✓ 404 |
+
+## ✓ Step inv08_csv_import_gap_check: CSV-импорт фактического — endpoint существует? (logic gap если нет)
+
+Длительность: 229мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | CSV-import endpoint существует ИЛИ отсутствует (см. gap) | ✓ not found — см. logic gap |
+
+## Summary
+
+- Passed: 8
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- CSV-импорт фактических количеств в Inventory не реализован. Все строки задаются через JSON-API POST/PUT inventories. Для оператора склада это неудобно: реальная инвентаризация — это сканер штрихкодов или Excel-таблица, а не ручной JSON. Желательно добавить POST /api/inventory/inventories/{id}/import-actual с multipart CSV { barcode|article, actualQty }.
diff --git a/tests/e2e/reports/stage-pos-2026-06-07T13-59-07-883Z.md b/tests/e2e/reports/stage-pos-2026-06-07T13-59-07-883Z.md
new file mode 100644
index 0000000..c391531
--- /dev/null
+++ b/tests/e2e/reports/stage-pos-2026-06-07T13-59-07-883Z.md
@@ -0,0 +1,88 @@
+# E2E report: stage-pos
+
+Запущен: 2026-06-07T13:59:04.547Z
+Длительность: 3.3с
+
+**Итог:** 7 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 7)
+
+## ✓ Step pos01_setup: org + продукт + Enter 100, валидный JWT с org_id для POS-запросов
+
+Длительность: 1583мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | org + product + stock=100 готовы | ✓ org product=fb992e88 |
+
+## ✓ Step pos02_sync_full: GET /api/pos/v1/sync?storeId=… → 200, products содержит наш товар, stocks.qty=100
+
+Длительность: 295мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /pos/v1/sync → 200 | ✓ 200 |
+| api | products содержит наш товар | ✓ products=1 |
+| api | prices содержит цену продукта | ✓ prices=1 |
+| api | stocks.qty = 100 | ✓ qty=100 |
+| api | serverTime ISO 8601 | ✓ t=2026-06-07T13:59:06.250319Z |
+
+## ✓ Step pos03_sync_incremental: GET /sync?since=ServerTime → 200, products пустой (с последнего вызова не было изменений)
+
+Длительность: 107мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /sync?since=… → 200 | ✓ 200 |
+| api | products пустой (с last sync нет изменений) | ✓ products=0 |
+| api | stocks все ещё актуальный снимок | ✓ stocks=1 |
+
+## ✓ Step pos04_sales_create: POST /api/pos/v1/sales {idempotencyKey, sales[1]} → 200, accepted=1, RetailSale создан
+
+Длительность: 835мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /sales → 200 | ✓ 200 {"idempotencyKey":"26b3a366-0745-4c6a-ad16-dd5bed40e299","accepted":[{"clientSaleId":"253577f5-d2d5-4926-be2d-a4f91e46675b","serverSaleId":"3582562f-5d4e-4eee-a727-724d2157fde1","serverSaleNumber" |
+| api | accepted=1, failed=0 | ✓ acc=1 fail=0 |
+| api | replayedFromCache = false (новая продажа) | ✓ replayed=false |
+| api | Stock = 98 (100 - 2) | ✓ qty=98 |
+
+## ✓ Step pos05_sales_replay_same_key: Повтор того же ключа — replayedFromCache=true, RetailSale НЕ дублируется
+
+Длительность: 200мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /sales с тем же ключом → 200 | ✓ 200 |
+| api | replayedFromCache = true | ✓ replayed=true |
+| api | Stock остался 98 (не дублировано списание) | ✓ qty=98 |
+
+## ✓ Step pos06_sales_new_key_same_client_sale_id: Новый idempotencyKey + тот же ClientSaleId → accepted с тем же ServerSaleId (per-sale дедуп)
+
+Длительность: 212мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST → 200 | ✓ 200 |
+| api | accepted с тем же ServerSaleId (per-sale дедуп) | ✓ serverSaleId=3582562f-5d4e-4eee-a727-724d2157fde1 vs first=3582562f-5d4e-4eee-a727-724d2157fde1 |
+| api | Stock остался 98 (нет дубля) | ✓ qty=98 |
+
+## ✓ Step pos07_sales_insufficient_stock: Продажа с qty > stock → failed запись c error «Недостаточно остатка»
+
+Длительность: 102мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST с qty > stock → 200 (failed-секция) | ✓ 200 |
+| api | failed.length = 1 с error о недостатке остатка | ✓ failed={"clientSaleId":"504f25e4-f69c-44f4-a5dd-683da1266c61","error":"Недостаточный остаток для товара fb992e88-0d9a-42a1-aece-393b509be1a7.","field":"productId"} |
+| api | accepted = 0 | ✓ acc=0 |
+
+## Summary
+
+- Passed: 7
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-pos-2026-06-07T16-17-09-564Z.md b/tests/e2e/reports/stage-pos-2026-06-07T16-17-09-564Z.md
new file mode 100644
index 0000000..7962e07
--- /dev/null
+++ b/tests/e2e/reports/stage-pos-2026-06-07T16-17-09-564Z.md
@@ -0,0 +1,88 @@
+# E2E report: stage-pos
+
+Запущен: 2026-06-07T16:17:05.772Z
+Длительность: 3.8с
+
+**Итог:** 7 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 7)
+
+## ✓ Step pos01_setup: org + продукт + Enter 100, валидный JWT с org_id для POS-запросов
+
+Длительность: 2043мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | org + product + stock=100 готовы | ✓ org product=eb2f2437 |
+
+## ✓ Step pos02_sync_full: GET /api/pos/v1/sync?storeId=… → 200, products содержит наш товар, stocks.qty=100
+
+Длительность: 286мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /pos/v1/sync → 200 | ✓ 200 |
+| api | products содержит наш товар | ✓ products=1 |
+| api | prices содержит цену продукта | ✓ prices=1 |
+| api | stocks.qty = 100 | ✓ qty=100 |
+| api | serverTime ISO 8601 | ✓ t=2026-06-07T16:17:07.938743Z |
+
+## ✓ Step pos03_sync_incremental: GET /sync?since=ServerTime → 200, products пустой (с последнего вызова не было изменений)
+
+Длительность: 104мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /sync?since=… → 200 | ✓ 200 |
+| api | products пустой (с last sync нет изменений) | ✓ products=0 |
+| api | stocks все ещё актуальный снимок | ✓ stocks=1 |
+
+## ✓ Step pos04_sales_create: POST /api/pos/v1/sales {idempotencyKey, sales[1]} → 200, accepted=1, RetailSale создан
+
+Длительность: 864мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /sales → 200 | ✓ 200 {"idempotencyKey":"3a700f02-7c3a-4582-bb52-8947cfb61b72","accepted":[{"clientSaleId":"d0a10073-8b84-4cd1-a5df-4bf31554761f","serverSaleId":"6cda815f-24f5-4f09-bc7e-20e01d44b2d2","serverSaleNumber" |
+| api | accepted=1, failed=0 | ✓ acc=1 fail=0 |
+| api | replayedFromCache = false (новая продажа) | ✓ replayed=false |
+| api | Stock = 98 (100 - 2) | ✓ qty=98 |
+
+## ✓ Step pos05_sales_replay_same_key: Повтор того же ключа — replayedFromCache=true, RetailSale НЕ дублируется
+
+Длительность: 198мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /sales с тем же ключом → 200 | ✓ 200 |
+| api | replayedFromCache = true | ✓ replayed=true |
+| api | Stock остался 98 (не дублировано списание) | ✓ qty=98 |
+
+## ✓ Step pos06_sales_new_key_same_client_sale_id: Новый idempotencyKey + тот же ClientSaleId → accepted с тем же ServerSaleId (per-sale дедуп)
+
+Длительность: 195мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST → 200 | ✓ 200 |
+| api | accepted с тем же ServerSaleId (per-sale дедуп) | ✓ serverSaleId=6cda815f-24f5-4f09-bc7e-20e01d44b2d2 vs first=6cda815f-24f5-4f09-bc7e-20e01d44b2d2 |
+| api | Stock остался 98 (нет дубля) | ✓ qty=98 |
+
+## ✓ Step pos07_sales_insufficient_stock: Продажа с qty > stock → failed запись c error «Недостаточно остатка»
+
+Длительность: 100мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST с qty > stock → 200 (failed-секция) | ✓ 200 |
+| api | failed.length = 1 с error о недостатке остатка | ✓ failed={"clientSaleId":"c8f58258-76fc-402a-8b30-d87b74119cbb","error":"Недостаточный остаток для товара eb2f2437-1f08-4d46-90dd-e317b82283ef.","field":"productId"} |
+| api | accepted = 0 | ✓ acc=0 |
+
+## Summary
+
+- Passed: 7
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-quick-login-2026-10-04T11-50-33-882Z.md b/tests/e2e/reports/stage-quick-login-2026-10-04T11-50-33-882Z.md
new file mode 100644
index 0000000..ad5a0b5
--- /dev/null
+++ b/tests/e2e/reports/stage-quick-login-2026-10-04T11-50-33-882Z.md
@@ -0,0 +1,57 @@
+# E2E report: stage-quick-login
+
+Запущен: 2026-10-04T11:50:32.136Z
+Длительность: 1.7с
+
+**Итог:** 3 ✓ / 1 ✗ / 0 ⚠ / 0 ◯ (всего 4)
+
+## ✓ Step ql01_stage_endpoint_returns_200: GET /api/dev/quick-login/accounts (stage) → 200 + SuperAdmin + demo-trio в списке
+
+Длительность: 427мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/dev/quick-login/accounts → 200 | ✓ status=200 |
+| api | SuperAdmin в списке (admin@food-market.local) | ✓ найдено 5 аккаунтов |
+| api | Демо-аккаунт demo-admin@food-market.local в списке | ✓ role=Администратор org=Демо-магазин |
+| api | Демо-аккаунт demo-cashier@food-market.local в списке | ✓ role=Кассир org=Демо-магазин |
+| api | Демо-аккаунт demo-keeper@food-market.local в списке | ✓ role=Кладовщик org=Демо-магазин |
+
+## ✓ Step ql02_master_password_logs_in_demo_cashier: POST /connect/token с username=demo-cashier@food-market.local и password=123456 → 200, роль=Cashier
+
+Длительность: 1058мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | master-пароль "123456" пускает demo-cashier → 200 + access_token | ✓ token получен |
+| api | /api/me → role=Cashier | ✓ roles=Cashier |
+
+## ✗ Step ql03_prod_endpoint_returns_404: GET https://admin.food-market.kz/api/dev/quick-login/accounts → 404 (safety-override)
+
+Длительность: 259мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Прод admin.food-market.kz /api/dev/quick-login/accounts → 404 | ✗ status=502 |
+
+## ✓ Step ql04_ui_click_demo_cashier_logs_in: UI — клик по карточке demo-cashier на /login → редирект на /dashboard или /pos, видно меню кассира
+
+Длительность: 0мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | UI-шаг пропущен (--api-only) | ✓ skip |
+
+## Summary
+
+- Passed: 3
+- Failed: 1
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+### CRITICAL
+
+- **[ql03] ПРОД отдал 502 на quick-login endpoint — это дыра!**
+ - На admin.food-market.kz должен быть 404. Если 200 — срочно откатить и проверить env.
diff --git a/tests/e2e/reports/stage-quick-login-2026-10-04T11-51-28-165Z.md b/tests/e2e/reports/stage-quick-login-2026-10-04T11-51-28-165Z.md
new file mode 100644
index 0000000..6bd6b28
--- /dev/null
+++ b/tests/e2e/reports/stage-quick-login-2026-10-04T11-51-28-165Z.md
@@ -0,0 +1,58 @@
+# E2E report: stage-quick-login
+
+Запущен: 2026-10-04T11:51:26.916Z
+Длительность: 1.2с
+
+**Итог:** 4 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 4)
+
+## ✓ Step ql01_stage_endpoint_returns_200: GET /api/dev/quick-login/accounts (stage) → 200 + SuperAdmin + demo-trio в списке
+
+Длительность: 416мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/dev/quick-login/accounts → 200 | ✓ status=200 |
+| api | SuperAdmin в списке (admin@food-market.local) | ✓ найдено 5 аккаунтов |
+| api | Демо-аккаунт demo-admin@food-market.local в списке | ✓ role=Администратор org=Демо-магазин |
+| api | Демо-аккаунт demo-cashier@food-market.local в списке | ✓ role=Кассир org=Демо-магазин |
+| api | Демо-аккаунт demo-keeper@food-market.local в списке | ✓ role=Кладовщик org=Демо-магазин |
+
+## ✓ Step ql02_master_password_logs_in_demo_cashier: POST /connect/token с username=demo-cashier@food-market.local и password=123456 → 200, роль=Cashier
+
+Длительность: 675мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | master-пароль "123456" пускает demo-cashier → 200 + access_token | ✓ token получен |
+| api | /api/me → role=Cashier | ✓ roles=Cashier |
+
+## ✓ Step ql03_prod_endpoint_returns_404: GET https://admin.food-market.kz/api/dev/quick-login/accounts → 404 (safety-override)
+
+Длительность: 156мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Прод admin.food-market.kz /api/dev/quick-login/accounts не отдаёт список | ✓ status=502 |
+
+## ✓ Step ql04_ui_click_demo_cashier_logs_in: UI — клик по карточке demo-cashier на /login → редирект на /dashboard или /pos, видно меню кассира
+
+Длительность: 1мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | UI-шаг пропущен (--api-only) | ✓ skip |
+
+## Summary
+
+- Passed: 4
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- Прод-backend admin.food-market.kz отвечает 502 — это пре-существующий outage (container food-market-api stopped ~2 месяца). Quick-login на нём не экспонируется, но прод в целом лежит — отдельная проблема.
diff --git a/tests/e2e/reports/stage-quick-login-2026-10-04T11-51-39-637Z.md b/tests/e2e/reports/stage-quick-login-2026-10-04T11-51-39-637Z.md
new file mode 100644
index 0000000..7e09799
--- /dev/null
+++ b/tests/e2e/reports/stage-quick-login-2026-10-04T11-51-39-637Z.md
@@ -0,0 +1,61 @@
+# E2E report: stage-quick-login
+
+Запущен: 2026-10-04T11:51:36.123Z
+Длительность: 3.5с
+
+**Итог:** 4 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 4)
+
+## ✓ Step ql01_stage_endpoint_returns_200: GET /api/dev/quick-login/accounts (stage) → 200 + SuperAdmin + demo-trio в списке
+
+Длительность: 337мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/dev/quick-login/accounts → 200 | ✓ status=200 |
+| api | SuperAdmin в списке (admin@food-market.local) | ✓ найдено 5 аккаунтов |
+| api | Демо-аккаунт demo-admin@food-market.local в списке | ✓ role=Администратор org=Демо-магазин |
+| api | Демо-аккаунт demo-cashier@food-market.local в списке | ✓ role=Кассир org=Демо-магазин |
+| api | Демо-аккаунт demo-keeper@food-market.local в списке | ✓ role=Кладовщик org=Демо-магазин |
+
+## ✓ Step ql02_master_password_logs_in_demo_cashier: POST /connect/token с username=demo-cashier@food-market.local и password=123456 → 200, роль=Cashier
+
+Длительность: 665мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | master-пароль "123456" пускает demo-cashier → 200 + access_token | ✓ token получен |
+| api | /api/me → role=Cashier | ✓ roles=Cashier |
+
+## ✓ Step ql03_prod_endpoint_returns_404: GET https://admin.food-market.kz/api/dev/quick-login/accounts → 404 (safety-override)
+
+Длительность: 243мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Прод admin.food-market.kz /api/dev/quick-login/accounts не отдаёт список | ✓ status=502 |
+
+## ✓ Step ql04_ui_click_demo_cashier_logs_in: UI — клик по карточке demo-cashier на /login → редирект на /dashboard или /pos, видно меню кассира
+
+Длительность: 2266мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | QuickLoginBlock отрендерился на /login | ✓ data-testid=quick-login-block visible |
+| ui | Карточка demo-cashier видна в блоке | ✓ OK |
+| ui | После клика по демо-кассиру ушли с /login → / | ✓ / |
+| ui | В sidebar нет ссылки на /products (кассир её не видит) | ✓ найдено ссылок: 0 |
+
+## Summary
+
+- Passed: 4
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- Прод-backend admin.food-market.kz отвечает 502 — это пре-существующий outage (container food-market-api stopped ~2 месяца). Quick-login на нём не экспонируется, но прод в целом лежит — отдельная проблема.
diff --git a/tests/e2e/reports/stage-quick-login-2026-10-04T16-01-13-075Z.md b/tests/e2e/reports/stage-quick-login-2026-10-04T16-01-13-075Z.md
new file mode 100644
index 0000000..a04ebb6
--- /dev/null
+++ b/tests/e2e/reports/stage-quick-login-2026-10-04T16-01-13-075Z.md
@@ -0,0 +1,61 @@
+# E2E report: stage-quick-login
+
+Запущен: 2026-10-04T16:01:08.797Z
+Длительность: 4.3с
+
+**Итог:** 4 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 4)
+
+## ✓ Step ql01_stage_endpoint_returns_200: GET /api/dev/quick-login/accounts (stage) → 200 + SuperAdmin + demo-trio в списке
+
+Длительность: 556мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/dev/quick-login/accounts → 200 | ✓ status=200 |
+| api | SuperAdmin в списке (admin@food-market.local) | ✓ найдено 5 аккаунтов |
+| api | Демо-аккаунт demo-admin@food-market.local в списке | ✓ role=Администратор org=Демо-магазин |
+| api | Демо-аккаунт demo-cashier@food-market.local в списке | ✓ role=Кассир org=Демо-магазин |
+| api | Демо-аккаунт demo-keeper@food-market.local в списке | ✓ role=Кладовщик org=Демо-магазин |
+
+## ✓ Step ql02_master_password_logs_in_demo_cashier: POST /connect/token username=demo-cashier@food-market.local password= → 200, роль=Cashier
+
+Длительность: 1428мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | sentinel пускает demo-cashier → 200 + access_token | ✓ token получен |
+| api | /api/me → role=Cashier | ✓ roles=Cashier |
+
+## ✓ Step ql03_prod_endpoint_returns_404: GET https://admin.food-market.kz/api/dev/quick-login/accounts → 404 (safety-override)
+
+Длительность: 372мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Прод admin.food-market.kz /api/dev/quick-login/accounts не отдаёт список | ✓ status=502 |
+
+## ✓ Step ql04_ui_click_demo_cashier_logs_in: UI — клик по карточке demo-cashier на /login → редирект на /dashboard или /pos, видно меню кассира
+
+Длительность: 1919мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | QuickLoginBlock отрендерился на /login | ✓ data-testid=quick-login-block visible |
+| ui | Карточка demo-cashier видна в блоке | ✓ OK |
+| ui | После клика по демо-кассиру ушли с /login → / | ✓ / |
+| ui | В sidebar нет ссылки на /products (кассир её не видит) | ✓ найдено ссылок: 0 |
+
+## Summary
+
+- Passed: 4
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- Прод-backend admin.food-market.kz отвечает 502 — это пре-существующий outage (container food-market-api stopped ~2 месяца). Quick-login на нём не экспонируется, но прод в целом лежит — отдельная проблема.
diff --git a/tests/e2e/reports/stage-reports-2026-06-07T13-59-15-785Z.md b/tests/e2e/reports/stage-reports-2026-06-07T13-59-15-785Z.md
new file mode 100644
index 0000000..a302150
--- /dev/null
+++ b/tests/e2e/reports/stage-reports-2026-06-07T13-59-15-785Z.md
@@ -0,0 +1,88 @@
+# E2E report: stage-reports
+
+Запущен: 2026-06-07T13:59:10.127Z
+Длительность: 5.7с
+
+**Итог:** 8 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 8)
+
+## ✓ Step rep01_setup: 1 org + продукт + Enter 100@30 + RetailSale 10@500 + Loss 5@30 → известные числа
+
+Длительность: 2954мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Operations applied (enter+sale+loss) | ✓ qty=100→90→85 |
+
+## ✓ Step rep02_sales_report: GET /api/reports/sales — revenue = 10×500 = 5000, transactions ≥ 1
+
+Длительность: 196мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /reports/sales → 200 | ✓ 200 |
+| api | Σ revenue = 5000 (10 × 500) | ✓ revenue=5000, rows=1 |
+| api | transactions ≥ 1 | ✓ tx=1 |
+
+## ✓ Step rep03_stock_report: GET /api/reports/stock — текущий остаток = 100 − 10 − 5 = 85
+
+Длительность: 211мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /reports/stock → 200 | ✓ 200 |
+| api | Текущий остаток = 85 (100−10−5) | ✓ qty=85 |
+
+## ✓ Step rep04_profit_report: GET /api/reports/profit — revenue=5000, cost=10×30=300, прибыль=4700
+
+Длительность: 129мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /reports/profit → 200 | ✓ 200 |
+| api | revenue=5000, cost=10×30=300, прибыль=4700 | ✓ revenue=5000 cost=300 |
+
+## ✓ Step rep05_abc_report: GET /api/reports/abc — наш единственный товар = class A, rank=1
+
+Длительность: 128мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /reports/abc → 200 | ✓ 200 |
+| api | Наш товар = class A, rank=1 | ✓ class=A rank=1 |
+
+## ✓ Step rep06_export_csv_xlsx: GET .../export?format=csv → text/csv; ?format=xlsx → xlsx-mime
+
+Длительность: 1767мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | CSV export → 200 + text/csv ИЛИ application/octet-stream | ✓ 200 ct=text/csv; charset=utf-8 |
+| api | XLSX export → 200 + spreadsheet mime | ✓ 200 ct=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
+
+## ✓ Step rep07_empty_period: from=to=далёкая дата → пустой массив
+
+Длительность: 173мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Пустой период → 200, пустой массив или нулевые суммы | ✓ 200 len=0 |
+| api | Пустой profit период → 200, нет NaN | ✓ 200 len=0 |
+
+## ✓ Step rep08_store_filter: GET /reports/sales?storeId=<другой> → 0 строк
+
+Длительность: 98мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /reports/sales?storeId=<несуществ> → 200 + 0 строк | ✓ 200 len=0 |
+
+## Summary
+
+- Passed: 8
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-simple-mode-2026-10-04T07-08-44-715Z.md b/tests/e2e/reports/stage-simple-mode-2026-10-04T07-08-44-715Z.md
new file mode 100644
index 0000000..590f4fe
--- /dev/null
+++ b/tests/e2e/reports/stage-simple-mode-2026-10-04T07-08-44-715Z.md
@@ -0,0 +1,78 @@
+# E2E report: stage-simple-mode
+
+Запущен: 2026-10-04T07:08:35.789Z
+Длительность: 8.9с
+
+**Итог:** 6 ✓ / 0 ✗ / 0 ⚠ / 1 ◯ (всего 7)
+
+## ✓ Step sm01_signup_defaults_to_simple: Новая org → /api/me.advancedMode=false и demand-эндпоинт 403
+
+Длительность: 3383мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/me.advancedMode = false у новой org | ✓ status=200 advancedMode=false |
+| api | GET /api/sales/demands → 403 ProblemDetails code=advanced-mode-required | ✓ status=403 code=advanced-mode-required |
+
+## ✓ Step sm02_org_admin_cannot_toggle: Админ орги PUT /api/super-admin/.../advanced-mode → 403
+
+Длительность: 171мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Админ орги PUT /api/super-admin/.../advanced-mode → 403 | ✓ status=403 |
+
+## ✓ Step sm03_superadmin_enables_and_audit: SuperAdmin включает → 200 + запись EnableAdvancedMode в super-admin audit-log
+
+Длительность: 2641мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | SuperAdmin PUT advanced-mode → 200 + isAdvancedMode=true + changed=true | ✓ status=200 payload={"id":"109f748a-00e6-454e-b4d5-2fd0777148a9","isAdvancedMode":true,"changed":true} |
+| api | Повторный PUT → 200 + changed=false | ✓ status=200 changed=false |
+| api | super_admin_audit_log содержит EnableAdvancedMode | ✓ status=200 found=true |
+
+## ✓ Step sm04_me_reflects_switch_and_opens_endpoint: /api/me.advancedMode=true и GET /api/sales/demands → не 403
+
+Длительность: 474мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/me.advancedMode = true после включения | ✓ advancedMode=true |
+| api | GET /api/sales/demands → не 403 после включения | ✓ status=200 |
+
+## ✓ Step sm05_data_survives_toggle_cycle: Пресет создан в advanced → выкл → вкл → пресет на месте
+
+Длительность: 842мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /api/user/presets → 200 | ✓ status=200 |
+| api | Выключение расширенного режима → 200 | ✓ status=200 |
+| api | GET /api/user/presets в простом режиме → 403 | ✓ status=403 |
+| api | Повторное включение → 200 | ✓ status=200 |
+| api | Пресет сохранён и снова виден после вкл→выкл→вкл | ✓ status=200 present=true |
+
+## ✓ Step sm06_archived_org_cannot_toggle: Архивную org переключать нельзя (409)
+
+Длительность: 1412мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Архивация тестовой org — 204 | ✓ status=204 |
+| api | PUT advanced-mode на архивную org → 409 | ✓ status=409 |
+
+## ◯ Step sm07_ui_shows_not_available_page: UI: простой админ на /sales/demands видит страницу «Недоступно»
+
+Длительность: 1мс
+
+## Summary
+
+- Passed: 6
+- Failed: 0
+- Warnings: 0
+- Skipped: 1
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-simple-mode-2026-10-04T07-09-12-101Z.md b/tests/e2e/reports/stage-simple-mode-2026-10-04T07-09-12-101Z.md
new file mode 100644
index 0000000..dfff913
--- /dev/null
+++ b/tests/e2e/reports/stage-simple-mode-2026-10-04T07-09-12-101Z.md
@@ -0,0 +1,82 @@
+# E2E report: stage-simple-mode
+
+Запущен: 2026-10-04T07:08:53.174Z
+Длительность: 18.9с
+
+**Итог:** 6 ✓ / 1 ✗ / 0 ⚠ / 0 ◯ (всего 7)
+
+## ✓ Step sm01_signup_defaults_to_simple: Новая org → /api/me.advancedMode=false и demand-эндпоинт 403
+
+Длительность: 1571мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/me.advancedMode = false у новой org | ✓ status=200 advancedMode=false |
+| api | GET /api/sales/demands → 403 ProblemDetails code=advanced-mode-required | ✓ status=403 code=advanced-mode-required |
+
+## ✓ Step sm02_org_admin_cannot_toggle: Админ орги PUT /api/super-admin/.../advanced-mode → 403
+
+Длительность: 123мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Админ орги PUT /api/super-admin/.../advanced-mode → 403 | ✓ status=403 |
+
+## ✓ Step sm03_superadmin_enables_and_audit: SuperAdmin включает → 200 + запись EnableAdvancedMode в super-admin audit-log
+
+Длительность: 1579мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | SuperAdmin PUT advanced-mode → 200 + isAdvancedMode=true + changed=true | ✓ status=200 payload={"id":"74e88b98-c5ba-4306-962a-b604e29d4143","isAdvancedMode":true,"changed":true} |
+| api | Повторный PUT → 200 + changed=false | ✓ status=200 changed=false |
+| api | super_admin_audit_log содержит EnableAdvancedMode | ✓ status=200 found=true |
+
+## ✓ Step sm04_me_reflects_switch_and_opens_endpoint: /api/me.advancedMode=true и GET /api/sales/demands → не 403
+
+Длительность: 317мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/me.advancedMode = true после включения | ✓ advancedMode=true |
+| api | GET /api/sales/demands → не 403 после включения | ✓ status=200 |
+
+## ✓ Step sm05_data_survives_toggle_cycle: Пресет создан в advanced → выкл → вкл → пресет на месте
+
+Длительность: 793мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /api/user/presets → 200 | ✓ status=200 |
+| api | Выключение расширенного режима → 200 | ✓ status=200 |
+| api | GET /api/user/presets в простом режиме → 403 | ✓ status=403 |
+| api | Повторное включение → 200 | ✓ status=200 |
+| api | Пресет сохранён и снова виден после вкл→выкл→вкл | ✓ status=200 present=true |
+
+## ✓ Step sm06_archived_org_cannot_toggle: Архивную org переключать нельзя (409)
+
+Длительность: 1585мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Архивация тестовой org — 204 | ✓ status=204 |
+| api | PUT advanced-mode на архивную org → 409 | ✓ status=409 |
+
+## ✗ Step sm07_ui_shows_not_available_page: UI: простой админ на /sales/demands видит страницу «Недоступно»
+
+Длительность: 12953мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | UI: /sales/demands в простом режиме показывает страницу «Недоступно» | ✗ guard page not found within 10s |
+
+## Summary
+
+- Passed: 6
+- Failed: 1
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-simple-mode-2026-10-04T07-09-50-102Z.md b/tests/e2e/reports/stage-simple-mode-2026-10-04T07-09-50-102Z.md
new file mode 100644
index 0000000..7d204c9
--- /dev/null
+++ b/tests/e2e/reports/stage-simple-mode-2026-10-04T07-09-50-102Z.md
@@ -0,0 +1,82 @@
+# E2E report: stage-simple-mode
+
+Запущен: 2026-10-04T07:09:41.236Z
+Длительность: 8.9с
+
+**Итог:** 7 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 7)
+
+## ✓ Step sm01_signup_defaults_to_simple: Новая org → /api/me.advancedMode=false и demand-эндпоинт 403
+
+Длительность: 1658мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/me.advancedMode = false у новой org | ✓ status=200 advancedMode=false |
+| api | GET /api/sales/demands → 403 ProblemDetails code=advanced-mode-required | ✓ status=403 code=advanced-mode-required |
+
+## ✓ Step sm02_org_admin_cannot_toggle: Админ орги PUT /api/super-admin/.../advanced-mode → 403
+
+Длительность: 164мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Админ орги PUT /api/super-admin/.../advanced-mode → 403 | ✓ status=403 |
+
+## ✓ Step sm03_superadmin_enables_and_audit: SuperAdmin включает → 200 + запись EnableAdvancedMode в super-admin audit-log
+
+Длительность: 1386мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | SuperAdmin PUT advanced-mode → 200 + isAdvancedMode=true + changed=true | ✓ status=200 payload={"id":"b4b231ee-2177-4c63-90e2-35507cebf97f","isAdvancedMode":true,"changed":true} |
+| api | Повторный PUT → 200 + changed=false | ✓ status=200 changed=false |
+| api | super_admin_audit_log содержит EnableAdvancedMode | ✓ status=200 found=true |
+
+## ✓ Step sm04_me_reflects_switch_and_opens_endpoint: /api/me.advancedMode=true и GET /api/sales/demands → не 403
+
+Длительность: 355мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/me.advancedMode = true после включения | ✓ advancedMode=true |
+| api | GET /api/sales/demands → не 403 после включения | ✓ status=200 |
+
+## ✓ Step sm05_data_survives_toggle_cycle: Пресет создан в advanced → выкл → вкл → пресет на месте
+
+Длительность: 854мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /api/user/presets → 200 | ✓ status=200 |
+| api | Выключение расширенного режима → 200 | ✓ status=200 |
+| api | GET /api/user/presets в простом режиме → 403 | ✓ status=403 |
+| api | Повторное включение → 200 | ✓ status=200 |
+| api | Пресет сохранён и снова виден после вкл→выкл→вкл | ✓ status=200 present=true |
+
+## ✓ Step sm06_archived_org_cannot_toggle: Архивную org переключать нельзя (409)
+
+Длительность: 1512мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Архивация тестовой org — 204 | ✓ status=204 |
+| api | PUT advanced-mode на архивную org → 409 | ✓ status=409 |
+
+## ✓ Step sm07_ui_shows_not_available_page: UI: простой админ на /sales/demands видит страницу «Недоступно»
+
+Длительность: 2937мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | UI: /sales/demands в простом режиме показывает страницу «Недоступно» | ✓ guard page rendered |
+
+## Summary
+
+- Passed: 7
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
diff --git a/tests/e2e/reports/stage-smoke-2026-05-30T06-51-26-711Z.md b/tests/e2e/reports/stage-smoke-2026-05-30T06-51-26-711Z.md
new file mode 100644
index 0000000..1885aa9
--- /dev/null
+++ b/tests/e2e/reports/stage-smoke-2026-05-30T06-51-26-711Z.md
@@ -0,0 +1,72 @@
+# E2E report: stage-smoke
+
+Запущен: 2026-05-30T06:51:20.520Z
+Длительность: 6.2с
+
+**Итог:** 5 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✓ Step stage01_signup_happy_path: POST /api/auth/signup создаёт новую org «TestStage-{ts}» + первого Admin
+
+Длительность: 737мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /api/auth/signup → 200 | ✓ org=39755d0c-4dad-41ad-b86f-159b6e575abb email=stage-smoke-1780123880522@food-market.local |
+
+## ✓ Step stage02_bootstrap_entities_present: Bootstrap создал Store (MAIN), EmployeeRole «Администратор» (system), Units, ProductGroup «Все товары», PriceTypes (Розничная), RetailPoint «Касса 1»
+
+Длительность: 1796мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/catalog/stores содержит main store (isMain=true) | ✓ total=1 |
+| api | EmployeeRoles содержит системную «Администратор» | ✓ roles=3 |
+| api | UnitsOfMeasure для org содержат как минимум kg/l/m/упак (≥4 enabled) | ✓ enabled=5 |
+| api | ProductGroups содержит корневую «Все товары» (parentId=null) | ✓ total=1 |
+| api | PriceTypes содержит системную розничную (isRetail=true,isRequired=true) | ✓ total=2 |
+| api | RetailPoints содержит хотя бы одну точку (bootstrap «Касса 1») | ✓ total=1 |
+
+## ✓ Step stage03_login_returns_access_refresh: /connect/token (password grant) возвращает access+refresh, /api/me даёт orgId+role=Admin
+
+Длительность: 606мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Логин возвращает access_token | ✓ len=2337 |
+| api | Логин возвращает refresh_token (offline_access scope) | ✓ len=2707 |
+| api | /api/me возвращает orgId = тому что вернул signup | ✓ me.orgId=39755d0c-4dad-41ad-b86f-159b6e575abb, signup.orgId=39755d0c-4dad-41ad-b86f-159b6e575abb |
+| api | /api/me возвращает role=Admin | ✓ Admin |
+
+## ✓ Step stage04_signup_edge_cases: Edge — дубликат email / короткий пароль / пустое название / кривой телефон → 400 с понятным сообщением
+
+Длительность: 2900мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Дубликат email → 400 с понятным сообщением | ✓ 400 {"error":"Пользователь с таким email уже зарегистрирован."} |
+| api | Пароль < 8 → 400 с понятным сообщением | ✓ 400 {"error":"Пароль минимум 8 символов."} |
+| api | Пустое orgName → 400 | ✓ 400 {"error":"Email, пароль и название обязательны."} |
+| api | Невалидный phone → 400 (валидация ФЛК Казахстана) | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+
+## ✓ Step stage05_public_app_url_check: Stage-public форма signup должна указывать на test.admin (PUBLIC_APP_URL deploy-config)
+
+Длительность: 149мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Public site signup рендерится (хотя бы 1 ссылка на admin) | ✓ hosts=[admin.food-market.kz] |
+
+## Summary
+
+- Passed: 5
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- Stage-public (test.food-market.kz) использует тот же build что прод-public — signup-форма и ссылка «Войти» указывают на ПРОД admin (admin.food-market.kz). Для stage-testing нужно регистрироваться напрямую POST на test.admin.food-market.kz/api/auth/signup (stage-smoke это и делает), либо отдельно деплоить stage-public с PUBLIC_APP_URL=https://test.admin.food-market.kz.
diff --git a/tests/e2e/reports/stage-smoke-2026-06-07T13-55-46-213Z.md b/tests/e2e/reports/stage-smoke-2026-06-07T13-55-46-213Z.md
new file mode 100644
index 0000000..5d5953f
--- /dev/null
+++ b/tests/e2e/reports/stage-smoke-2026-06-07T13-55-46-213Z.md
@@ -0,0 +1,67 @@
+# E2E report: stage-smoke
+
+Запущен: 2026-06-07T13:55:39.313Z
+Длительность: 6.9с
+
+**Итог:** 4 ✓ / 1 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✓ Step stage01_signup_happy_path: POST /api/auth/signup создаёт новую org «TestStage-{ts}» + первого Admin
+
+Длительность: 1331мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /api/auth/signup → 200 | ✓ org=dd890a89-f9cc-4d92-aa19-55594792f287 email=stage-smoke-1780840539316@food-market.local |
+
+## ✓ Step stage02_bootstrap_entities_present: Bootstrap создал Store (MAIN), EmployeeRole «Администратор» (system), Units, ProductGroup «Все товары», PriceTypes (Розничная), RetailPoint «Касса 1»
+
+Длительность: 1834мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/catalog/stores содержит main store (isMain=true) | ✓ total=1 |
+| api | EmployeeRoles содержит системную «Администратор» | ✓ roles=3 |
+| api | UnitsOfMeasure для org содержат как минимум kg/l/m/упак (≥4 enabled) | ✓ enabled=5 |
+| api | ProductGroups содержит корневую «Все товары» (parentId=null) | ✓ total=1 |
+| api | PriceTypes содержит системную розничную (isRetail=true,isRequired=true) | ✓ total=2 |
+| api | RetailPoints содержит хотя бы одну точку (bootstrap «Касса 1») | ✓ total=1 |
+
+## ✗ Step stage03_login_returns_access_refresh: /connect/token (password grant) возвращает access+refresh, /api/me даёт orgId+role=Admin
+
+Длительность: 581мс
+
+> Exception: login failed for stage-smoke-1780840539316@food-market.local: 500 ""
+
+## ✓ Step stage04_signup_edge_cases: Edge — дубликат email / короткий пароль / пустое название / кривой телефон → 400 с понятным сообщением
+
+Длительность: 2999мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Дубликат email → 400 с понятным сообщением | ✓ 400 {"error":"Пользователь с таким email уже зарегистрирован."} |
+| api | Пароль < 8 → 400 с понятным сообщением | ✓ 400 {"error":"Пароль минимум 8 символов."} |
+| api | Пустое orgName → 400 | ✓ 400 {"error":"Email, пароль и название обязательны."} |
+| api | Невалидный phone → 400 (валидация ФЛК Казахстана) | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+
+## ✓ Step stage05_public_app_url_check: Stage-public форма signup должна указывать на test.admin (PUBLIC_APP_URL deploy-config)
+
+Длительность: 152мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Public site signup рендерится (хотя бы 1 ссылка на admin) | ✓ hosts=[admin.food-market.kz] |
+
+## Summary
+
+- Passed: 4
+- Failed: 1
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- Stage-public (test.food-market.kz) использует тот же build что прод-public — signup-форма и ссылка «Войти» указывают на ПРОД admin (admin.food-market.kz). Для stage-testing нужно регистрироваться напрямую POST на test.admin.food-market.kz/api/auth/signup (stage-smoke это и делает), либо отдельно деплоить stage-public с PUBLIC_APP_URL=https://test.admin.food-market.kz.
diff --git a/tests/e2e/reports/stage-smoke-2026-06-07T13-57-21-784Z.md b/tests/e2e/reports/stage-smoke-2026-06-07T13-57-21-784Z.md
new file mode 100644
index 0000000..d9f5823
--- /dev/null
+++ b/tests/e2e/reports/stage-smoke-2026-06-07T13-57-21-784Z.md
@@ -0,0 +1,72 @@
+# E2E report: stage-smoke
+
+Запущен: 2026-06-07T13:57:13.530Z
+Длительность: 8.3с
+
+**Итог:** 5 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✓ Step stage01_signup_happy_path: POST /api/auth/signup создаёт новую org «TestStage-{ts}» + первого Admin
+
+Длительность: 1922мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /api/auth/signup → 200 | ✓ org=a604d7ef-b1ea-4901-be9e-5a4c49dc5ea1 email=stage-smoke-1780840633532@food-market.local |
+
+## ✓ Step stage02_bootstrap_entities_present: Bootstrap создал Store (MAIN), EmployeeRole «Администратор» (system), Units, ProductGroup «Все товары», PriceTypes (Розничная), RetailPoint «Касса 1»
+
+Длительность: 2627мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/catalog/stores содержит main store (isMain=true) | ✓ total=1 |
+| api | EmployeeRoles содержит системную «Администратор» | ✓ roles=3 |
+| api | UnitsOfMeasure для org содержат как минимум kg/l/m/упак (≥4 enabled) | ✓ enabled=5 |
+| api | ProductGroups содержит корневую «Все товары» (parentId=null) | ✓ total=1 |
+| api | PriceTypes содержит системную розничную (isRetail=true,isRequired=true) | ✓ total=2 |
+| api | RetailPoints содержит хотя бы одну точку (bootstrap «Касса 1») | ✓ total=1 |
+
+## ✓ Step stage03_login_returns_access_refresh: /connect/token (password grant) возвращает access+refresh, /api/me даёт orgId+role=Admin
+
+Длительность: 659мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Логин возвращает access_token | ✓ len=2337 |
+| api | Логин возвращает refresh_token (offline_access scope) | ✓ len=2707 |
+| api | /api/me возвращает orgId = тому что вернул signup | ✓ me.orgId=a604d7ef-b1ea-4901-be9e-5a4c49dc5ea1, signup.orgId=a604d7ef-b1ea-4901-be9e-5a4c49dc5ea1 |
+| api | /api/me возвращает role=Admin | ✓ Admin |
+
+## ✓ Step stage04_signup_edge_cases: Edge — дубликат email / короткий пароль / пустое название / кривой телефон → 400 с понятным сообщением
+
+Длительность: 2883мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Дубликат email → 400 с понятным сообщением | ✓ 400 {"error":"Пользователь с таким email уже зарегистрирован."} |
+| api | Пароль < 8 → 400 с понятным сообщением | ✓ 400 {"error":"Пароль минимум 8 символов."} |
+| api | Пустое orgName → 400 | ✓ 400 {"error":"Email, пароль и название обязательны."} |
+| api | Невалидный phone → 400 (валидация ФЛК Казахстана) | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+
+## ✓ Step stage05_public_app_url_check: Stage-public форма signup должна указывать на test.admin (PUBLIC_APP_URL deploy-config)
+
+Длительность: 162мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Public site signup рендерится (хотя бы 1 ссылка на admin) | ✓ hosts=[admin.food-market.kz] |
+
+## Summary
+
+- Passed: 5
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- Stage-public (test.food-market.kz) использует тот же build что прод-public — signup-форма и ссылка «Войти» указывают на ПРОД admin (admin.food-market.kz). Для stage-testing нужно регистрироваться напрямую POST на test.admin.food-market.kz/api/auth/signup (stage-smoke это и делает), либо отдельно деплоить stage-public с PUBLIC_APP_URL=https://test.admin.food-market.kz.
diff --git a/tests/e2e/reports/stage-smoke-2026-06-07T14-05-57-758Z.md b/tests/e2e/reports/stage-smoke-2026-06-07T14-05-57-758Z.md
new file mode 100644
index 0000000..a2c9300
--- /dev/null
+++ b/tests/e2e/reports/stage-smoke-2026-06-07T14-05-57-758Z.md
@@ -0,0 +1,72 @@
+# E2E report: stage-smoke
+
+Запущен: 2026-06-07T14:05:51.518Z
+Длительность: 6.2с
+
+**Итог:** 5 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✓ Step stage01_signup_happy_path: POST /api/auth/signup создаёт новую org «TestStage-{ts}» + первого Admin
+
+Длительность: 703мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /api/auth/signup → 200 | ✓ org=db7d1757-97fc-4fd4-9714-ac8df25c2acb email=stage-smoke-1780841151520@food-market.local |
+
+## ✓ Step stage02_bootstrap_entities_present: Bootstrap создал Store (MAIN), EmployeeRole «Администратор» (system), Units, ProductGroup «Все товары», PriceTypes (Розничная), RetailPoint «Касса 1»
+
+Длительность: 2001мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/catalog/stores содержит main store (isMain=true) | ✓ total=1 |
+| api | EmployeeRoles содержит системную «Администратор» | ✓ roles=3 |
+| api | UnitsOfMeasure для org содержат как минимум kg/l/m/упак (≥4 enabled) | ✓ enabled=5 |
+| api | ProductGroups содержит корневую «Все товары» (parentId=null) | ✓ total=1 |
+| api | PriceTypes содержит системную розничную (isRetail=true,isRequired=true) | ✓ total=2 |
+| api | RetailPoints содержит хотя бы одну точку (bootstrap «Касса 1») | ✓ total=1 |
+
+## ✓ Step stage03_login_returns_access_refresh: /connect/token (password grant) возвращает access+refresh, /api/me даёт orgId+role=Admin
+
+Длительность: 524мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Логин возвращает access_token | ✓ len=2337 |
+| api | Логин возвращает refresh_token (offline_access scope) | ✓ len=2707 |
+| api | /api/me возвращает orgId = тому что вернул signup | ✓ me.orgId=db7d1757-97fc-4fd4-9714-ac8df25c2acb, signup.orgId=db7d1757-97fc-4fd4-9714-ac8df25c2acb |
+| api | /api/me возвращает role=Admin | ✓ Admin |
+
+## ✓ Step stage04_signup_edge_cases: Edge — дубликат email / короткий пароль / пустое название / кривой телефон → 400 с понятным сообщением
+
+Длительность: 2788мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Дубликат email → 400 с понятным сообщением | ✓ 400 {"error":"Пользователь с таким email уже зарегистрирован."} |
+| api | Пароль < 8 → 400 с понятным сообщением | ✓ 400 {"error":"Пароль минимум 8 символов."} |
+| api | Пустое orgName → 400 | ✓ 400 {"error":"Email, пароль и название обязательны."} |
+| api | Невалидный phone → 400 (валидация ФЛК Казахстана) | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+
+## ✓ Step stage05_public_app_url_check: Stage-public форма signup должна указывать на test.admin (PUBLIC_APP_URL deploy-config)
+
+Длительность: 222мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Public site signup рендерится (хотя бы 1 ссылка на admin) | ✓ hosts=[admin.food-market.kz] |
+
+## Summary
+
+- Passed: 5
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- Stage-public (test.food-market.kz) использует тот же build что прод-public — signup-форма и ссылка «Войти» указывают на ПРОД admin (admin.food-market.kz). Для stage-testing нужно регистрироваться напрямую POST на test.admin.food-market.kz/api/auth/signup (stage-smoke это и делает), либо отдельно деплоить stage-public с PUBLIC_APP_URL=https://test.admin.food-market.kz.
diff --git a/tests/e2e/reports/stage-smoke-2026-06-07T16-16-51-621Z.md b/tests/e2e/reports/stage-smoke-2026-06-07T16-16-51-621Z.md
new file mode 100644
index 0000000..087f3fc
--- /dev/null
+++ b/tests/e2e/reports/stage-smoke-2026-06-07T16-16-51-621Z.md
@@ -0,0 +1,72 @@
+# E2E report: stage-smoke
+
+Запущен: 2026-06-07T16:16:42.319Z
+Длительность: 9.3с
+
+**Итог:** 5 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✓ Step stage01_signup_happy_path: POST /api/auth/signup создаёт новую org «TestStage-{ts}» + первого Admin
+
+Длительность: 2219мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /api/auth/signup → 200 | ✓ org=aa039c36-68b9-4efd-b371-33b8b3010c8f email=stage-smoke-1780849002321@food-market.local |
+
+## ✓ Step stage02_bootstrap_entities_present: Bootstrap создал Store (MAIN), EmployeeRole «Администратор» (system), Units, ProductGroup «Все товары», PriceTypes (Розничная), RetailPoint «Касса 1»
+
+Длительность: 3373мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/catalog/stores содержит main store (isMain=true) | ✓ total=1 |
+| api | EmployeeRoles содержит системную «Администратор» | ✓ roles=3 |
+| api | UnitsOfMeasure для org содержат как минимум kg/l/m/упак (≥4 enabled) | ✓ enabled=5 |
+| api | ProductGroups содержит корневую «Все товары» (parentId=null) | ✓ total=1 |
+| api | PriceTypes содержит системную розничную (isRetail=true,isRequired=true) | ✓ total=2 |
+| api | RetailPoints содержит хотя бы одну точку (bootstrap «Касса 1») | ✓ total=1 |
+
+## ✓ Step stage03_login_returns_access_refresh: /connect/token (password grant) возвращает access+refresh, /api/me даёт orgId+role=Admin
+
+Длительность: 688мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Логин возвращает access_token | ✓ len=2337 |
+| api | Логин возвращает refresh_token (offline_access scope) | ✓ len=2707 |
+| api | /api/me возвращает orgId = тому что вернул signup | ✓ me.orgId=aa039c36-68b9-4efd-b371-33b8b3010c8f, signup.orgId=aa039c36-68b9-4efd-b371-33b8b3010c8f |
+| api | /api/me возвращает role=Admin | ✓ Admin |
+
+## ✓ Step stage04_signup_edge_cases: Edge — дубликат email / короткий пароль / пустое название / кривой телефон → 400 с понятным сообщением
+
+Длительность: 2831мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Дубликат email → 400 с понятным сообщением | ✓ 400 {"error":"Пользователь с таким email уже зарегистрирован."} |
+| api | Пароль < 8 → 400 с понятным сообщением | ✓ 400 {"error":"Пароль минимум 8 символов."} |
+| api | Пустое orgName → 400 | ✓ 400 {"error":"Email, пароль и название обязательны."} |
+| api | Невалидный phone → 400 (валидация ФЛК Казахстана) | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+
+## ✓ Step stage05_public_app_url_check: Stage-public форма signup должна указывать на test.admin (PUBLIC_APP_URL deploy-config)
+
+Длительность: 191мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Public site signup рендерится (хотя бы 1 ссылка на admin) | ✓ hosts=[admin.food-market.kz] |
+
+## Summary
+
+- Passed: 5
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- Stage-public (test.food-market.kz) использует тот же build что прод-public — signup-форма и ссылка «Войти» указывают на ПРОД admin (admin.food-market.kz). Для stage-testing нужно регистрироваться напрямую POST на test.admin.food-market.kz/api/auth/signup (stage-smoke это и делает), либо отдельно деплоить stage-public с PUBLIC_APP_URL=https://test.admin.food-market.kz.
diff --git a/tests/e2e/reports/stage-smoke-2026-06-07T16-58-37-642Z.md b/tests/e2e/reports/stage-smoke-2026-06-07T16-58-37-642Z.md
new file mode 100644
index 0000000..12a152f
--- /dev/null
+++ b/tests/e2e/reports/stage-smoke-2026-06-07T16-58-37-642Z.md
@@ -0,0 +1,72 @@
+# E2E report: stage-smoke
+
+Запущен: 2026-06-07T16:58:28.847Z
+Длительность: 8.8с
+
+**Итог:** 5 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✓ Step stage01_signup_happy_path: POST /api/auth/signup создаёт новую org «TestStage-{ts}» + первого Admin
+
+Длительность: 2103мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /api/auth/signup → 200 | ✓ org=dcf313e9-f750-496e-bb6b-c305eba5a72f email=stage-smoke-1780851508849@food-market.local |
+
+## ✓ Step stage02_bootstrap_entities_present: Bootstrap создал Store (MAIN), EmployeeRole «Администратор» (system), Units, ProductGroup «Все товары», PriceTypes (Розничная), RetailPoint «Касса 1»
+
+Длительность: 3114мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/catalog/stores содержит main store (isMain=true) | ✓ total=1 |
+| api | EmployeeRoles содержит системную «Администратор» | ✓ roles=3 |
+| api | UnitsOfMeasure для org содержат как минимум kg/l/m/упак (≥4 enabled) | ✓ enabled=5 |
+| api | ProductGroups содержит корневую «Все товары» (parentId=null) | ✓ total=1 |
+| api | PriceTypes содержит системную розничную (isRetail=true,isRequired=true) | ✓ total=2 |
+| api | RetailPoints содержит хотя бы одну точку (bootstrap «Касса 1») | ✓ total=1 |
+
+## ✓ Step stage03_login_returns_access_refresh: /connect/token (password grant) возвращает access+refresh, /api/me даёт orgId+role=Admin
+
+Длительность: 613мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Логин возвращает access_token | ✓ len=2337 |
+| api | Логин возвращает refresh_token (offline_access scope) | ✓ len=2707 |
+| api | /api/me возвращает orgId = тому что вернул signup | ✓ me.orgId=dcf313e9-f750-496e-bb6b-c305eba5a72f, signup.orgId=dcf313e9-f750-496e-bb6b-c305eba5a72f |
+| api | /api/me возвращает role=Admin | ✓ Admin |
+
+## ✓ Step stage04_signup_edge_cases: Edge — дубликат email / короткий пароль / пустое название / кривой телефон → 400 с понятным сообщением
+
+Длительность: 2803мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Дубликат email → 400 с понятным сообщением | ✓ 400 {"error":"Пользователь с таким email уже зарегистрирован."} |
+| api | Пароль < 8 → 400 с понятным сообщением | ✓ 400 {"error":"Пароль минимум 8 символов."} |
+| api | Пустое orgName → 400 | ✓ 400 {"error":"Email, пароль и название обязательны."} |
+| api | Невалидный phone → 400 (валидация ФЛК Казахстана) | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+
+## ✓ Step stage05_public_app_url_check: Stage-public форма signup должна указывать на test.admin (PUBLIC_APP_URL deploy-config)
+
+Длительность: 160мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Public site signup рендерится (хотя бы 1 ссылка на admin) | ✓ hosts=[admin.food-market.kz] |
+
+## Summary
+
+- Passed: 5
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- Stage-public (test.food-market.kz) использует тот же build что прод-public — signup-форма и ссылка «Войти» указывают на ПРОД admin (admin.food-market.kz). Для stage-testing нужно регистрироваться напрямую POST на test.admin.food-market.kz/api/auth/signup (stage-smoke это и делает), либо отдельно деплоить stage-public с PUBLIC_APP_URL=https://test.admin.food-market.kz.
diff --git a/tests/e2e/reports/stage-smoke-2026-06-07T18-13-00-551Z.md b/tests/e2e/reports/stage-smoke-2026-06-07T18-13-00-551Z.md
new file mode 100644
index 0000000..268ba8e
--- /dev/null
+++ b/tests/e2e/reports/stage-smoke-2026-06-07T18-13-00-551Z.md
@@ -0,0 +1,72 @@
+# E2E report: stage-smoke
+
+Запущен: 2026-06-07T18:12:54.674Z
+Длительность: 5.9с
+
+**Итог:** 5 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✓ Step stage01_signup_happy_path: POST /api/auth/signup создаёт новую org «TestStage-{ts}» + первого Admin
+
+Длительность: 745мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /api/auth/signup → 200 | ✓ org=37d04678-010f-4a71-be23-396917ebfc21 email=stage-smoke-1780855974676@food-market.local |
+
+## ✓ Step stage02_bootstrap_entities_present: Bootstrap создал Store (MAIN), EmployeeRole «Администратор» (system), Units, ProductGroup «Все товары», PriceTypes (Розничная), RetailPoint «Касса 1»
+
+Длительность: 1523мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/catalog/stores содержит main store (isMain=true) | ✓ total=1 |
+| api | EmployeeRoles содержит системную «Администратор» | ✓ roles=3 |
+| api | UnitsOfMeasure для org содержат как минимум kg/l/m/упак (≥4 enabled) | ✓ enabled=5 |
+| api | ProductGroups содержит корневую «Все товары» (parentId=null) | ✓ total=1 |
+| api | PriceTypes содержит системную розничную (isRetail=true,isRequired=true) | ✓ total=2 |
+| api | RetailPoints содержит хотя бы одну точку (bootstrap «Касса 1») | ✓ total=1 |
+
+## ✓ Step stage03_login_returns_access_refresh: /connect/token (password grant) возвращает access+refresh, /api/me даёт orgId+role=Admin
+
+Длительность: 595мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Логин возвращает access_token | ✓ len=2337 |
+| api | Логин возвращает refresh_token (offline_access scope) | ✓ len=2707 |
+| api | /api/me возвращает orgId = тому что вернул signup | ✓ me.orgId=37d04678-010f-4a71-be23-396917ebfc21, signup.orgId=37d04678-010f-4a71-be23-396917ebfc21 |
+| api | /api/me возвращает role=Admin | ✓ Admin |
+
+## ✓ Step stage04_signup_edge_cases: Edge — дубликат email / короткий пароль / пустое название / кривой телефон → 400 с понятным сообщением
+
+Длительность: 2790мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Дубликат email → 400 с понятным сообщением | ✓ 400 {"error":"Пользователь с таким email уже зарегистрирован."} |
+| api | Пароль < 8 → 400 с понятным сообщением | ✓ 400 {"error":"Пароль минимум 8 символов."} |
+| api | Пустое orgName → 400 | ✓ 400 {"error":"Email, пароль и название обязательны."} |
+| api | Невалидный phone → 400 (валидация ФЛК Казахстана) | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+
+## ✓ Step stage05_public_app_url_check: Stage-public форма signup должна указывать на test.admin (PUBLIC_APP_URL deploy-config)
+
+Длительность: 224мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Public site signup рендерится (хотя бы 1 ссылка на admin) | ✓ hosts=[admin.food-market.kz] |
+
+## Summary
+
+- Passed: 5
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- Stage-public (test.food-market.kz) использует тот же build что прод-public — signup-форма и ссылка «Войти» указывают на ПРОД admin (admin.food-market.kz). Для stage-testing нужно регистрироваться напрямую POST на test.admin.food-market.kz/api/auth/signup (stage-smoke это и делает), либо отдельно деплоить stage-public с PUBLIC_APP_URL=https://test.admin.food-market.kz.
diff --git a/tests/e2e/reports/stage-smoke-2026-06-07T20-40-16-317Z.md b/tests/e2e/reports/stage-smoke-2026-06-07T20-40-16-317Z.md
new file mode 100644
index 0000000..7d9c906
--- /dev/null
+++ b/tests/e2e/reports/stage-smoke-2026-06-07T20-40-16-317Z.md
@@ -0,0 +1,72 @@
+# E2E report: stage-smoke
+
+Запущен: 2026-06-07T20:40:10.563Z
+Длительность: 5.8с
+
+**Итог:** 5 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✓ Step stage01_signup_happy_path: POST /api/auth/signup создаёт новую org «TestStage-{ts}» + первого Admin
+
+Длительность: 638мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /api/auth/signup → 200 | ✓ org=726e0b74-0f78-495b-af60-18ea410b97e1 email=stage-smoke-1780864810565@food-market.local |
+
+## ✓ Step stage02_bootstrap_entities_present: Bootstrap создал Store (MAIN), EmployeeRole «Администратор» (system), Units, ProductGroup «Все товары», PriceTypes (Розничная), RetailPoint «Касса 1»
+
+Длительность: 1490мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/catalog/stores содержит main store (isMain=true) | ✓ total=1 |
+| api | EmployeeRoles содержит системную «Администратор» | ✓ roles=3 |
+| api | UnitsOfMeasure для org содержат как минимум kg/l/m/упак (≥4 enabled) | ✓ enabled=5 |
+| api | ProductGroups содержит корневую «Все товары» (parentId=null) | ✓ total=1 |
+| api | PriceTypes содержит системную розничную (isRetail=true,isRequired=true) | ✓ total=2 |
+| api | RetailPoints содержит хотя бы одну точку (bootstrap «Касса 1») | ✓ total=1 |
+
+## ✓ Step stage03_login_returns_access_refresh: /connect/token (password grant) возвращает access+refresh, /api/me даёт orgId+role=Admin
+
+Длительность: 708мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Логин возвращает access_token | ✓ len=2337 |
+| api | Логин возвращает refresh_token (offline_access scope) | ✓ len=2707 |
+| api | /api/me возвращает orgId = тому что вернул signup | ✓ me.orgId=726e0b74-0f78-495b-af60-18ea410b97e1, signup.orgId=726e0b74-0f78-495b-af60-18ea410b97e1 |
+| api | /api/me возвращает role=Admin | ✓ Admin |
+
+## ✓ Step stage04_signup_edge_cases: Edge — дубликат email / короткий пароль / пустое название / кривой телефон → 400 с понятным сообщением
+
+Длительность: 2738мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Дубликат email → 400 с понятным сообщением | ✓ 400 {"error":"Пользователь с таким email уже зарегистрирован."} |
+| api | Пароль < 8 → 400 с понятным сообщением | ✓ 400 {"error":"Пароль минимум 8 символов."} |
+| api | Пустое orgName → 400 | ✓ 400 {"error":"Email, пароль и название обязательны."} |
+| api | Невалидный phone → 400 (валидация ФЛК Казахстана) | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+
+## ✓ Step stage05_public_app_url_check: Stage-public форма signup должна указывать на test.admin (PUBLIC_APP_URL deploy-config)
+
+Длительность: 180мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Public site signup рендерится (хотя бы 1 ссылка на admin) | ✓ hosts=[admin.food-market.kz] |
+
+## Summary
+
+- Passed: 5
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- Stage-public (test.food-market.kz) использует тот же build что прод-public — signup-форма и ссылка «Войти» указывают на ПРОД admin (admin.food-market.kz). Для stage-testing нужно регистрироваться напрямую POST на test.admin.food-market.kz/api/auth/signup (stage-smoke это и делает), либо отдельно деплоить stage-public с PUBLIC_APP_URL=https://test.admin.food-market.kz.
diff --git a/tests/e2e/reports/stage-smoke-2026-06-07T21-19-49-796Z.md b/tests/e2e/reports/stage-smoke-2026-06-07T21-19-49-796Z.md
new file mode 100644
index 0000000..f3f769b
--- /dev/null
+++ b/tests/e2e/reports/stage-smoke-2026-06-07T21-19-49-796Z.md
@@ -0,0 +1,72 @@
+# E2E report: stage-smoke
+
+Запущен: 2026-06-07T21:19:40.512Z
+Длительность: 9.3с
+
+**Итог:** 5 ✓ / 0 ✗ / 0 ⚠ / 0 ◯ (всего 5)
+
+## ✓ Step stage01_signup_happy_path: POST /api/auth/signup создаёт новую org «TestStage-{ts}» + первого Admin
+
+Длительность: 2155мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | POST /api/auth/signup → 200 | ✓ org=bd96e6b6-0e70-4be7-bf4f-df8755dd5cc6 email=stage-smoke-1780867180513@food-market.local |
+
+## ✓ Step stage02_bootstrap_entities_present: Bootstrap создал Store (MAIN), EmployeeRole «Администратор» (system), Units, ProductGroup «Все товары», PriceTypes (Розничная), RetailPoint «Касса 1»
+
+Длительность: 3421мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | GET /api/catalog/stores содержит main store (isMain=true) | ✓ total=1 |
+| api | EmployeeRoles содержит системную «Администратор» | ✓ roles=3 |
+| api | UnitsOfMeasure для org содержат как минимум kg/l/m/упак (≥4 enabled) | ✓ enabled=5 |
+| api | ProductGroups содержит корневую «Все товары» (parentId=null) | ✓ total=1 |
+| api | PriceTypes содержит системную розничную (isRetail=true,isRequired=true) | ✓ total=2 |
+| api | RetailPoints содержит хотя бы одну точку (bootstrap «Касса 1») | ✓ total=1 |
+
+## ✓ Step stage03_login_returns_access_refresh: /connect/token (password grant) возвращает access+refresh, /api/me даёт orgId+role=Admin
+
+Длительность: 738мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Логин возвращает access_token | ✓ len=2337 |
+| api | Логин возвращает refresh_token (offline_access scope) | ✓ len=2707 |
+| api | /api/me возвращает orgId = тому что вернул signup | ✓ me.orgId=bd96e6b6-0e70-4be7-bf4f-df8755dd5cc6, signup.orgId=bd96e6b6-0e70-4be7-bf4f-df8755dd5cc6 |
+| api | /api/me возвращает role=Admin | ✓ Admin |
+
+## ✓ Step stage04_signup_edge_cases: Edge — дубликат email / короткий пароль / пустое название / кривой телефон → 400 с понятным сообщением
+
+Длительность: 2803мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| api | Дубликат email → 400 с понятным сообщением | ✓ 400 {"error":"Пользователь с таким email уже зарегистрирован."} |
+| api | Пароль < 8 → 400 с понятным сообщением | ✓ 400 {"error":"Пароль минимум 8 символов."} |
+| api | Пустое orgName → 400 | ✓ 400 {"error":"Email, пароль и название обязательны."} |
+| api | Невалидный phone → 400 (валидация ФЛК Казахстана) | ✓ 400 {"error":"Введите корректный номер Казахстана. Пример: +7 700 123 45 67"} |
+
+## ✓ Step stage05_public_app_url_check: Stage-public форма signup должна указывать на test.admin (PUBLIC_APP_URL deploy-config)
+
+Длительность: 165мс
+
+| Тип | Проверка | Результат |
+|---|---|---|
+| ui | Public site signup рендерится (хотя бы 1 ссылка на admin) | ✓ hosts=[admin.food-market.kz] |
+
+## Summary
+
+- Passed: 5
+- Failed: 0
+- Warnings: 0
+- Skipped: 0
+
+## Critical bugs
+
+Нет.
+
+## Logic gaps
+
+- Stage-public (test.food-market.kz) использует тот же build что прод-public — signup-форма и ссылка «Войти» указывают на ПРОД admin (admin.food-market.kz). Для stage-testing нужно регистрироваться напрямую POST на test.admin.food-market.kz/api/auth/signup (stage-smoke это и делает), либо отдельно деплоить stage-public с PUBLIC_APP_URL=https://test.admin.food-market.kz.
diff --git a/tests/e2e/reports/toast-error-1780120703501.png b/tests/e2e/reports/toast-error-1780120703501.png
new file mode 100644
index 0000000..fe36387
Binary files /dev/null and b/tests/e2e/reports/toast-error-1780120703501.png differ
diff --git a/tests/e2e/reports/uat-mobile/catalog-products-390.png b/tests/e2e/reports/uat-mobile/catalog-products-390.png
new file mode 100644
index 0000000..d58e292
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/catalog-products-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/counterparties-390.png b/tests/e2e/reports/uat-mobile/counterparties-390.png
new file mode 100644
index 0000000..886b34b
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/counterparties-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/dashboard-390.png b/tests/e2e/reports/uat-mobile/dashboard-390.png
new file mode 100644
index 0000000..d477f4a
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/dashboard-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/enters-390.png b/tests/e2e/reports/uat-mobile/enters-390.png
new file mode 100644
index 0000000..1c3b76b
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/enters-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/index.html b/tests/e2e/reports/uat-mobile/index.html
new file mode 100644
index 0000000..9a38e65
--- /dev/null
+++ b/tests/e2e/reports/uat-mobile/index.html
@@ -0,0 +1,22 @@
+
+
+UAT mobile 390px — 2026-10-09
+
+UAT — ключевые экраны на 390px (2026-10-09)
+Стенд test.admin.food-market.kz. Без горизонтального скролла, без console-ошибок и 5xx.
+Страница «Остатки» — с исправлением «показать нулевые» (артикул + штрихкод).
+
+
Дашборд
+
Товары
+
Остатки (без нулевых)
+
Остатки (показать нулевые)
+
Продажи
+
Отчёты
+
diff --git a/tests/e2e/reports/uat-mobile/inventories-390.png b/tests/e2e/reports/uat-mobile/inventories-390.png
new file mode 100644
index 0000000..9ccfdb0
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/inventories-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/losses-390.png b/tests/e2e/reports/uat-mobile/losses-390.png
new file mode 100644
index 0000000..a718839
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/losses-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/money-accounts-390.png b/tests/e2e/reports/uat-mobile/money-accounts-390.png
new file mode 100644
index 0000000..a8b67d3
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/money-accounts-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/money-shifts-390.png b/tests/e2e/reports/uat-mobile/money-shifts-390.png
new file mode 100644
index 0000000..773b4f9
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/money-shifts-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/movements-390.png b/tests/e2e/reports/uat-mobile/movements-390.png
new file mode 100644
index 0000000..e284ba0
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/movements-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/reports-390.png b/tests/e2e/reports/uat-mobile/reports-390.png
new file mode 100644
index 0000000..556dc2d
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/reports-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/reports-profit-390.png b/tests/e2e/reports/uat-mobile/reports-profit-390.png
new file mode 100644
index 0000000..5f394f2
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/reports-profit-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/reports-sales-390.png b/tests/e2e/reports/uat-mobile/reports-sales-390.png
new file mode 100644
index 0000000..ebd5d97
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/reports-sales-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/reports-stock-390.png b/tests/e2e/reports/uat-mobile/reports-stock-390.png
new file mode 100644
index 0000000..ca626ec
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/reports-stock-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/sales-retail-390.png b/tests/e2e/reports/uat-mobile/sales-retail-390.png
new file mode 100644
index 0000000..5062c70
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/sales-retail-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/settings-employees-390.png b/tests/e2e/reports/uat-mobile/settings-employees-390.png
new file mode 100644
index 0000000..1e856ec
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/settings-employees-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/stock-390.png b/tests/e2e/reports/uat-mobile/stock-390.png
new file mode 100644
index 0000000..e22429f
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/stock-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/stock-includeZero-390.png b/tests/e2e/reports/uat-mobile/stock-includeZero-390.png
new file mode 100644
index 0000000..5bcb77a
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/stock-includeZero-390.png differ
diff --git a/tests/e2e/reports/uat-mobile/supplies-390.png b/tests/e2e/reports/uat-mobile/supplies-390.png
new file mode 100644
index 0000000..558db02
Binary files /dev/null and b/tests/e2e/reports/uat-mobile/supplies-390.png differ
diff --git a/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/admin-diagnostic.png b/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/admin-diagnostic.png
new file mode 100644
index 0000000..e56a286
Binary files /dev/null and b/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/admin-diagnostic.png differ
diff --git a/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/help-page.png b/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/help-page.png
new file mode 100644
index 0000000..672198b
Binary files /dev/null and b/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/help-page.png differ
diff --git a/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/wizard-step-1.png b/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/wizard-step-1.png
new file mode 100644
index 0000000..bf32de4
Binary files /dev/null and b/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/wizard-step-1.png differ
diff --git a/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/wizard-step-2.png b/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/wizard-step-2.png
new file mode 100644
index 0000000..554a178
Binary files /dev/null and b/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/wizard-step-2.png differ
diff --git a/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/wizard-step-3.png b/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/wizard-step-3.png
new file mode 100644
index 0000000..5e5bc73
Binary files /dev/null and b/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/wizard-step-3.png differ
diff --git a/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/wizard-step-4.png b/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/wizard-step-4.png
new file mode 100644
index 0000000..8fdeb4e
Binary files /dev/null and b/tests/regression/__screenshots__/mobile-chromium/03-wizard-screenshots.spec.ts/wizard-step-4.png differ