Appearance
Импорт Excel в UI: пошаговый flow
Обновлено: 17.05.2026 Статус: wave K-ADM1 A5 закрыт codex-ревью, доступен на dev-стенде. Покрывает реальный Кочарин-канонический файл по 7 организациям. Адресат: интегратор (Андрей или замещающий), который заливает Excel-данные предприятия в систему.
Страница описывает UI-обёртку над K-O2 split_kocharin_excel — пошаговый импорт реального Excel-файла через консоль, с preflight-проверкой, подтверждением и историей запусков. До K-ADM1 A5 импорт выполнялся командой на сервере; теперь — через раздел /v/admin/integrator-tools/imports/kocharin.
1. Что делает импорт
В одном Excel-файле Кочарина — 13 листов: Предприятия, Оборудование, Рабочие места, Персонал, Операции, Материалы, Поставщики, техкарты, Переделы, план, спецификации заказа, BOM сборочных узлов, Легенда. Все 7 организаций (5 юр.лиц + 2 ИП-кооператора) живут в одной общей таблице — данные предприятия идентифицируются по столбцу Предприятие.
Импорт делает три вещи:
- Split — разрезает один общий файл на 7 per-org файлов (каждый со своими листами и строками).
- Validate — preflight-проверка: подсчёт строк, обнаружение конфликтов, проверка соответствия эталонной схеме.
- Apply — DB import per-org с tenant isolation: каждая организация получает только свои данные, ссылки на внешние сущности (кооперация) идут через KOCH_* global namespace.
2. Перед запуском
| Что | Где взять |
|---|---|
| Excel-файл | Через раздел Excel-import UI ниже. Эталон лежит в antroute_backend/core/management/commands/data/kocharin_m7_canonical.xlsx |
| Доступ | Superuser-логин kocharin-integrator |
| Ограничение по размеру | ≤ 50 МБ (MAX_XLSX_BYTES в backend, frontend проверяет .size до отправки) |
| Расширение | строго .xlsx, другие отклоняются на frontend ещё до preflight |
Импорт идемпотентен. Повторный запуск на том же файле — Δ=0 по всем сущностям (B10 walkthrough evidence: idempotency_smoke_preflight.json).
3. Шаг 1. Загрузка файла
Открываем /v/admin/integrator-tools/imports/kocharin. Шаг 1 — Upload — пустая area для drag-and-drop или клика «Выбрать файл».

Что валидируется на этом шаге:
- расширение
.xlsx(другие отклоняются с конкретным сообщением); - размер ≤ 50 МБ;
- не блокирует параллельный
runningimport (singletonExcelImportLockчерезselect_for_update(nowait=True)— если другой импорт идёт, UI показывает ошибку «занят»).
Что пока не делается:
- preview содержимого без загрузки на сервер (drag-over toast пустой);
- история отклонённых файлов (если расширение не то, файл просто не уходит).
4. Шаг 2. Preflight — проверка структуры
После загрузки файла UI автоматически переходит к Preflight. Backend читает Excel в память (без записи в БД), парсит листы, проверяет:
- соответствие листов эталонной схеме (13 ожидаемых);
- соответствие столбцов в каждом листе;
- наличие всех 7 организаций в колонке
Предприятие; - отсутствие дублей по уникальным ключам.
Результат — summary с разрезом по orgs:

Что видно в summary:
preflight_content_sha— SHA-256 от scrubbed payload (без volatile путей). Идентичный файл даст идентичный SHA;preflight_id— UUID этого конкретного preflight'а (для split identity);- по каждой organization: счётчики строк / РМ / материалов / техопераций / спецификаций;
- target_org_codes — какие organizations будут обновлены.
Что preflight не делает:
- DB write — никаких изменений;
- semantic validation — только структура. Если в
Маршрутыесть ссылка на несуществующее РМ, это всплывёт на apply, не на preflight (мы fail-closed на unresolved-wp).
Preflight живёт 30 минут как ExcelImportPreflight(status='done'). Можно вернуться и применить позже — но если за это время кто-то опубликовал DSL-конфиг изменения, может появиться конфликт. UI это покажет через split identity (preflight_id ≠ актуальное состояние).
5. Шаг 3. Подтверждение
Перед apply нужно явно поставить галочку «Я понимаю что данные предприятия будут перезаписаны / дополнены». Это защита от случайного клика «Apply» — особенно если preflight summary показывает большое число изменений.

Кнопка Apply disabled пока галочка не стоит. После клика — POST запрос с body {preflight_id, preflight_content_sha} (split identity + fingerprint). Backend ещё раз сравнивает content_sha с актуальным состоянием файла — это защита от parallel re-upload.
6. Шаг 4. Apply — асинхронный запуск
Backend стартует thread runner с _run_apply_in_thread. UI показывает прогресс через polling каждые 2 секунды. После завершения — финальный экран с deep-link на audit log:

Что в финальном state:
run_id— UUID этого apply (используется во всех audit-записях);audit_log_ids— UUID[] записей в AuditLog (одна по умолчанию —IMPORT_APPLIED);apply_summary— JSONB с разрезом «что произошло»: counts up-to-date, не diff. Для Kocharin canonical это{"mode": "skip-projection"}если все 7 organizations уже актуальны.
Что обрабатывается под капотом:
ATOMIC_REQUESTS=Trueview-level транзакция отключена на этих endpoint'ах (декоратор@method_decorator(transaction.non_atomic_requests, name='dispatch')) — иначе preliminaryExcelImportPreflight(status='running')row rollback-ается при view-exception;- thread runner rehydrate-by-id, не shared state с view;
close_old_connections()чтобы pgbouncer-style pool не задержался;- финальный AuditLog в одной атомарной транзакции вместе со status='done'.
Что не делается:
- streaming progress (60% / 70% / ...) — только бинарный running/done;
- автоматический rollback при partial-fail (если apply упал на 5-й organization из 7, первые 4 остаются. Это намеренно — следующий import может пере-применить только провалившиеся organizations).
7. Шаг 5. История запусков
Drawer History показывает все запуски preflight/apply последних 30 дней, с timestamp, status, run_id, audit_log_ids:

Что в каждой строке:
kind— preflight или apply;status— running / done / error;created_at/finished_at;audit_log_ids[]— UUID-tags, кликабельные для перехода в AuditLog detail.
Watchdog: Background команда cleanup_stale_excel_imports чистит зависшие записи:
- preflight
runningстарше 5 мин → status='error', message='stale'; - terminal-status старше 30 мин → soft-delete (artifact dirs cleanup);
- apply
runningстарше 30 мин → status='error' (защита от orphan threads).
8. Маршрут просмотра на 10 минут
- Логин
kocharin-integrator, открой/v/admin/integrator-tools/imports/kocharin. - Drag-drop файл
kocharin_m7_canonical.xlsx(или клик «Выбрать»). - Дождись preflight summary — должно показать 7 organizations с цифрами из §3 в integrator-console.md.
- Поставь галочку, нажми
Apply— экран running → done за 6-15 сек. - Открой Drawer History — увидишь новую apply строку со status='done' и 1 audit_log_id tag.
- Перезалей тот же файл повторно — apply summary должен быть
{"mode": "skip-projection"}(идемпотентность).
9. Что в обратной связи
- UX preflight'а. Достаточно ли by-org разреза, или нужны разрезы по листам (детально по 13 листам)?
- Threshold confirmation. Достаточно ли одной галочки, или нужны 2-уровневые confirmation'ы (один для «новое предприятие», другой для «уже импортированное» — другой риск)?
- Истории глубина. 30 дней или нужно дольше? Нужен ли filter по org / kind / status?
- Apply summary. Сейчас
skip-projectionили counts — нужны ли human-readable деталь («Создано 24 изделия, обновлено 0, удалено 0»)? - Error states. Не покрыто этой страницей — если apply провалился на 5-й org, как это видно интегратору? (Сейчас — status='error' + error_message в drawer; нужно проверить как читается).
10. Что отложено
- UI для других предприятий. Сейчас только Кочарин-канонический формат. Дженерик «загрузи свой Excel» — после пилота.
- Pre-import staging area. Возможность загрузить файл «черновиком» (можно посмотреть preflight под несколькими файлами и выбрать самый успешный). Сейчас preflight уникальный per upload.
- Email уведомления. Apply done / error не шлёт email админу. Только UI-индикатор.
- API endpoint для CI/CD. Через UI только сейчас; программный импорт пока —
python manage.py split_kocharin_excel.
Приложение. Evidence в репозитории
docs/sprint_2026_may/closed/2026-05/K-ADM1-evidence/05-imports/— 5 PNG +summary.json(overall_pass=true, apply_done_seen=true, audit_log_ids_count=1, history_apply_done_count=3).docs/sprint_2026_may/closed/2026-05/K-ADM1-integrator-console-methodology.md— §A5 ACCEPTED methodology с invariant'ами (ATOMIC_REQUESTS workaround, split identity, timeout overrides).docs/sprint_2026_may/closed/2026-05/K-O2-split/phaseB10/checks.json— машинно-проверяемый итог B10 walkthrough (counts up-to-date после реального apply).antroute_backend/screens/views_integrator_excel.py— 4 endpoint'а реализации.antroute_backend/screens/services/integrator_excel_import.py— pure helpers (scrub, sha, manifest, scope resolve).frontend/src/features/integrator/imports/— full UI tree (25 vitest tests).