fix(report): report_generated_at в POST-ответе на fast-path из кэша
All checks were successful
CI / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 8s
CI / frontend-tests (pull_request) Successful in 1m11s
CI / openapi-codegen-check (pull_request) Successful in 2m5s
CI / backend-tests (pull_request) Successful in 14m47s
All checks were successful
CI / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 8s
CI / frontend-tests (pull_request) Successful in 1m11s
CI / openapi-codegen-check (pull_request) Successful in 2m5s
CI / backend-tests (pull_request) Successful in 14m47s
Кэш-хит POST /{cad}/report возвращал status=ready без даты сборки —
кнопка «Скачать отчёт» показывала лейбл без даты до отдельного
GET /status. Заполняем report_generated_at из метадаты рана на
ready-ветке (тот же ключ generated_at, что у status — ответы согласованы),
building — None. Хук фолбэчит на enqueue-ответ. api-types +2.
Refs #2259
This commit is contained in:
parent
9289c3d69d
commit
cfa6309551
5 changed files with 22 additions and 5 deletions
|
|
@ -1626,10 +1626,15 @@ def build_parcel_report(
|
|||
analyze_at = _iso_or_none(getattr(analyze_run, "created_at", None))
|
||||
forecast_at = _iso_or_none(getattr(forecast_run, "created_at", None))
|
||||
|
||||
# Готовый кэш → 200 ready (не enqueue'им повторно).
|
||||
if _cached_report_result(db, cad_num) is not None:
|
||||
# Готовый кэш → 200 ready (не enqueue'им повторно). Отдаём и дату генерации PDF из
|
||||
# метадаты рана — чтобы fast-path кнопка показала дату без отдельного GET /status.
|
||||
cached = _cached_report_result(db, cad_num)
|
||||
if cached is not None:
|
||||
return ReportBuildResponse(
|
||||
status="ready", analyze_run_at=analyze_at, forecast_run_at=forecast_at
|
||||
status="ready",
|
||||
analyze_run_at=analyze_at,
|
||||
forecast_run_at=forecast_at,
|
||||
report_generated_at=cached.get("generated_at"),
|
||||
)
|
||||
|
||||
# Enqueue фоновой сборки. Lazy import таски (как forecast в analyze_parcel) — атрибут
|
||||
|
|
|
|||
|
|
@ -270,6 +270,9 @@ class ReportBuildResponse(BaseModel):
|
|||
# Даты базовых ранов (ISO) — контекст, по каким данным собирается/собран отчёт.
|
||||
analyze_run_at: str | None = None
|
||||
forecast_run_at: str | None = None
|
||||
# Дата генерации готового PDF (ISO) — только при status="ready" (кэш-хит); на
|
||||
# building-ветке None (файла ещё нет). Даёт fast-path кнопке дату без GET /status.
|
||||
report_generated_at: str | None = None
|
||||
|
||||
|
||||
class ReportStatusResponse(BaseModel):
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ def test_post_report_enqueues_and_returns_202() -> None:
|
|||
body = resp.json()
|
||||
assert body["status"] == "building"
|
||||
assert body["analyze_run_at"] is not None
|
||||
# Отчёт ещё не собран → даты генерации PDF нет.
|
||||
assert body["report_generated_at"] is None
|
||||
delay_mock.assert_called_once_with(_CAD)
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
|
@ -127,7 +129,10 @@ def test_post_report_cache_hit_returns_200_ready(tmp_path: Path) -> None:
|
|||
client = TestClient(app)
|
||||
resp = client.post(f"/api/v1/parcels/{_CAD}/report")
|
||||
assert resp.status_code == 200, resp.text
|
||||
assert resp.json()["status"] == "ready"
|
||||
body = resp.json()
|
||||
assert body["status"] == "ready"
|
||||
# Fast-path: POST-ответ несёт дату генерации PDF из метадаты рана (без GET /status).
|
||||
assert body["report_generated_at"] == "2026-07-03T09:00:00+00:00"
|
||||
delay_mock.assert_not_called() # кэш есть → не enqueue'им
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
|
|
|||
|
|
@ -294,7 +294,9 @@ export function useFullReport(cad: string): UseFullReportResult {
|
|||
}
|
||||
|
||||
const reportGeneratedAt =
|
||||
(uiState === "ready" ? statusData?.report_generated_at : null) ?? null;
|
||||
(uiState === "ready"
|
||||
? (statusData?.report_generated_at ?? enqueue.data?.report_generated_at)
|
||||
: null) ?? null;
|
||||
|
||||
return {
|
||||
uiState,
|
||||
|
|
|
|||
|
|
@ -5255,6 +5255,8 @@ export interface components {
|
|||
analyze_run_at?: string | null;
|
||||
/** Forecast Run At */
|
||||
forecast_run_at?: string | null;
|
||||
/** Report Generated At */
|
||||
report_generated_at?: string | null;
|
||||
};
|
||||
/**
|
||||
* ReportStatusResponse
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue