Skip to content

Импорт 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 ИП-кооператора) живут в одной общей таблице — данные предприятия идентифицируются по столбцу Предприятие.

Импорт делает три вещи:

  1. Split — разрезает один общий файл на 7 per-org файлов (каждый со своими листами и строками).
  2. Validate — preflight-проверка: подсчёт строк, обнаружение конфликтов, проверка соответствия эталонной схеме.
  3. 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 или клика «Выбрать файл».

Upload step — idle

Что валидируется на этом шаге:

  • расширение .xlsx (другие отклоняются с конкретным сообщением);
  • размер ≤ 50 МБ;
  • не блокирует параллельный running import (singleton ExcelImportLock через select_for_update(nowait=True) — если другой импорт идёт, UI показывает ошибку «занят»).

Что пока не делается:

  • preview содержимого без загрузки на сервер (drag-over toast пустой);
  • история отклонённых файлов (если расширение не то, файл просто не уходит).

4. Шаг 2. Preflight — проверка структуры

После загрузки файла UI автоматически переходит к Preflight. Backend читает Excel в память (без записи в БД), парсит листы, проверяет:

  • соответствие листов эталонной схеме (13 ожидаемых);
  • соответствие столбцов в каждом листе;
  • наличие всех 7 организаций в колонке Предприятие;
  • отсутствие дублей по уникальным ключам.

Результат — summary с разрезом по orgs:

Preflight summary — by-org breakdown

Что видно в 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 показывает большое число изменений.

Confirm step — checkbox ticked, Apply enabled

Кнопка 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:

Apply done — final state

Что в финальном 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=True view-level транзакция отключена на этих endpoint'ах (декоратор @method_decorator(transaction.non_atomic_requests, name='dispatch')) — иначе preliminary ExcelImportPreflight(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:

History drawer — full list

Что в каждой строке:

  • 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 минут

  1. Логин kocharin-integrator, открой /v/admin/integrator-tools/imports/kocharin.
  2. Drag-drop файл kocharin_m7_canonical.xlsx (или клик «Выбрать»).
  3. Дождись preflight summary — должно показать 7 organizations с цифрами из §3 в integrator-console.md.
  4. Поставь галочку, нажми Apply — экран running → done за 6-15 сек.
  5. Открой Drawer History — увидишь новую apply строку со status='done' и 1 audit_log_id tag.
  6. Перезалей тот же файл повторно — apply summary должен быть {"mode": "skip-projection"} (идемпотентность).

9. Что в обратной связи

  1. UX preflight'а. Достаточно ли by-org разреза, или нужны разрезы по листам (детально по 13 листам)?
  2. Threshold confirmation. Достаточно ли одной галочки, или нужны 2-уровневые confirmation'ы (один для «новое предприятие», другой для «уже импортированное» — другой риск)?
  3. Истории глубина. 30 дней или нужно дольше? Нужен ли filter по org / kind / status?
  4. Apply summary. Сейчас skip-projection или counts — нужны ли human-readable деталь («Создано 24 изделия, обновлено 0, удалено 0»)?
  5. 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).

AntRoute MES — управление блуждающими узкими местами