feat: limit source exports to current year
All checks were successful
All checks were successful
This commit is contained in:
@@ -9,6 +9,11 @@
|
||||
теле обычной HTML-формы на
|
||||
`POST /api/v2/organization-source-records/export-download/`.
|
||||
|
||||
Имя скачиваемого архива формируется по выбранным источникам и времени создания
|
||||
запроса: `<source-stem>_YYYYMMDD_HHMMSS.zip`, а для нескольких источников их
|
||||
имена соединяются через `__`. Значение `file_name` из ticket и итоговый
|
||||
`Content-Disposition` совпадают.
|
||||
|
||||
Браузер получает потоковый ZIP напрямую, без многогигабайтного `Blob` в
|
||||
JavaScript. Ticket не попадает в URL и после первого запроса становится
|
||||
недействительным. Совместимый администраторский endpoint
|
||||
@@ -19,6 +24,13 @@ JavaScript. Ticket не попадает в URL и после первого з
|
||||
готовые файлы последнего ночного поколения. При отсутствии поколения API
|
||||
возвращает `503` с кодом `source_export_not_ready`.
|
||||
|
||||
Каждое поколение содержит только текущий календарный год в timezone сервиса.
|
||||
Для моделей с предметной датой год определяется по ней, для моделей без такой
|
||||
даты — по `created_at`, для финансовых отчётов — по году строк отчёта. Строки
|
||||
других лет из финансового отчёта не выгружаются. После смены года старое
|
||||
поколение не раздаётся: до успешной сборки нового года API отвечает
|
||||
`503 source_export_not_ready`.
|
||||
|
||||
## Матрица
|
||||
|
||||
| Группа API | Таблицы State Corp | Файл | CSV | XLSX | JSON |
|
||||
@@ -39,9 +51,9 @@ JavaScript. Ticket не попадает в URL и после первого з
|
||||
используют тот же контракт, что и Mostovik: реквизиты организации, включая ОКПО,
|
||||
общие поля записи источника и специфичные поля в `payload.*`.
|
||||
|
||||
Все записи включаются в публичные файлы, а техническое наименование внешнего
|
||||
поставщика нейтрализуется. Исходные значения в БД сохраняются для работы
|
||||
интеграции и дедупликации.
|
||||
Все записи текущего года включаются в публичные файлы, а техническое
|
||||
наименование внешнего поставщика нейтрализуется. Исходные значения в БД
|
||||
сохраняются для работы интеграции и дедупликации.
|
||||
|
||||
Физических XLSX-файлов может быть больше: по умолчанию один файл содержит не
|
||||
более 100 000 строк данных и получает суффикс `-part-001`, `-part-002` и далее.
|
||||
@@ -55,11 +67,13 @@ Celery Beat запускает
|
||||
Генератор:
|
||||
|
||||
1. читает каждую нормализованную таблицу один раз без model-level сортировки;
|
||||
предметные даты и fallback по `created_at` индексированы;
|
||||
2. создаёт компактный JSON-массив и переиспользует его как готовый JSON;
|
||||
3. потоково формирует CSV и write-only XLSX;
|
||||
4. атомарно публикует `current.json` только после готовности всей матрицы;
|
||||
5. при ошибке удаляет staging и продолжает отдавать предыдущее поколение;
|
||||
6. сохраняет текущее и предыдущее поколения по умолчанию.
|
||||
4. записывает календарный `export_year` в manifest;
|
||||
5. атомарно публикует `current.json` только после готовности всей матрицы;
|
||||
6. при ошибке удаляет staging и продолжает отдавать предыдущее поколение того же года;
|
||||
7. сохраняет текущее и предыдущее поколения по умолчанию.
|
||||
|
||||
Web и Celery worker должны использовать общий read-write volume `/app/media`.
|
||||
|
||||
@@ -81,3 +95,8 @@ PYTHONPATH=src uv run python src/manage.py build_source_record_exports
|
||||
|
||||
Для атомарной генерации требуется свободное место не меньше
|
||||
`(GENERATIONS_TO_KEEP + 1) * размер поколения` плюс запас файловой системы.
|
||||
|
||||
На локальном снимке от 2026-08-04 поколение за 2026 год содержит 1 962 записи
|
||||
и занимает 4 738 872 байта (4,52 MiB) для всей матрицы. Архив со всеми
|
||||
источниками оценивается в 2,49 MiB для JSON, 1,59 MiB для CSV и 0,44 MiB для
|
||||
XLSX; к сумме добавляется небольшой служебный overhead ZIP.
|
||||
|
||||
Reference in New Issue
Block a user