AURORA-1832: aware-даты этапов форм и проектов (часовой пояс) #228

Open
aep wants to merge 2 commits from feat/208-aurora-1832-phase-dates-tz into test
Owner

Closes #208

Jira: AURORA-1832

Что сделано

  • timezone_from_offset вынесен из роутера в api/src/core/timezones.py, добавлен to_org_local_naive(dt, utc_offset): naive без изменений, aware переводится в пояс оргединицы формы и теряет tzinfo (SQL приписывает тот же offset, момент времени сохраняется).
  • Нормализация в FormPhaseService и Form3PhaseService (create/update, в update только переданные поля). Роутер передаёт utc_offset; в update org_unit загружается до вызова сервиса.
  • Aware-дата при NULL utc_offset оргединицы даёт 422 с понятным текстом.
  • Охвачены /stages/form/... и /stages/project/.... Репозитории и SQL не менялись.

Тесты

  • unit: tests/unit/test_form_phase_service_tz.py (хелпер: Z, +03:00, naive, отрицательный offset, 422; сервисы с AsyncMock-репозиторием).
  • integration: POST с +03:00 (200, тот же момент) и GET -> PATCH тем же значением.
  • Полный прогон на PG16: 212 passed, 4 skipped, 3 failed (те же 3 исходных падения).

Проверить руками

  • POST /api/v1/stages/form/{id} с opens_at: 2026-10-26T10:00:00+03:00 -> 200, в ответе тот же момент.
  • GET этапа и PATCH его значением -> 200 без изменений.
  • Аналогично для /stages/project/....

Замер до/после

будет добавлен после ночного прогона на стенде perf/ (не перф-задача, замер не требуется).

Rulings I made

  • R-1: 422 при aware-дате и NULL utc_offset поднимается как HTTPException из общего хелпера (ValidationsError даёт 400). Цена ошибки: статус/формат тела ошибки.

🤖 Generated with Claude Code

Closes #208 Jira: AURORA-1832 ## Что сделано - `timezone_from_offset` вынесен из роутера в `api/src/core/timezones.py`, добавлен `to_org_local_naive(dt, utc_offset)`: naive без изменений, aware переводится в пояс оргединицы формы и теряет tzinfo (SQL приписывает тот же offset, момент времени сохраняется). - Нормализация в `FormPhaseService` и `Form3PhaseService` (create/update, в update только переданные поля). Роутер передаёт `utc_offset`; в update org_unit загружается до вызова сервиса. - Aware-дата при NULL utc_offset оргединицы даёт 422 с понятным текстом. - Охвачены `/stages/form/...` и `/stages/project/...`. Репозитории и SQL не менялись. ## Тесты - unit: `tests/unit/test_form_phase_service_tz.py` (хелпер: Z, +03:00, naive, отрицательный offset, 422; сервисы с AsyncMock-репозиторием). - integration: POST с `+03:00` (200, тот же момент) и GET -> PATCH тем же значением. - Полный прогон на PG16: 212 passed, 4 skipped, 3 failed (те же 3 исходных падения). ## Проверить руками - POST /api/v1/stages/form/{id} с `opens_at: 2026-10-26T10:00:00+03:00` -> 200, в ответе тот же момент. - GET этапа и PATCH его значением -> 200 без изменений. - Аналогично для /stages/project/.... ## Замер до/после будет добавлен после ночного прогона на стенде perf/ (не перф-задача, замер не требуется). ## Rulings I made - R-1: 422 при aware-дате и NULL utc_offset поднимается как HTTPException из общего хелпера (ValidationsError даёт 400). Цена ошибки: статус/формат тела ошибки. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 2 commits 2026-10-28 17:13:33 +03:00
asyncpg не принимает aware-datetime для CAST AS TIMESTAMP WITHOUT TIME ZONE (400).
Даты переводятся в пояс оргединицы и становятся naive, SQL приписывает тот же offset.
timezone_from_offset вынесен в src/core/timezones.py, добавлен to_org_local_naive.
Aware-дата при NULL utc_offset оргединицы даёт 422.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Owner

Проверка красной фазы (контроллер, 28.10): новые тесты запущены на коде origin/test без правки (PG16). test_form_phases_create_aware_dates_keep_instant падает с assert 400 == 200 — воспроизводит баг; unit-тесты на старом коде не собираются (нет src/core/timezones.py). После правки — зелёные (полный прогон в описании PR).

Проверка красной фазы (контроллер, 28.10): новые тесты запущены на коде origin/test без правки (PG16). test_form_phases_create_aware_dates_keep_instant падает с assert 400 == 200 — воспроизводит баг; unit-тесты на старом коде не собираются (нет src/core/timezones.py). После правки — зелёные (полный прогон в описании PR).
This pull request can be merged automatically.
You are not authorized to merge this pull request.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/208-aurora-1832-phase-dates-tz:feat/208-aurora-1832-phase-dates-tz
git checkout feat/208-aurora-1832-phase-dates-tz
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RSHB/DFiP_Budget_planing#228
No description provided.