fix(reports): HEAD-поддержка на /report/download — qa поймал 405, DOCX не скачивался из UI (#2343)
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-frontend (push) Has been skipped
Deploy / build-backend (push) Successful in 2m0s
Deploy / build-worker (push) Successful in 2m53s
Deploy / deploy (push) Successful in 1m35s

This commit is contained in:
bot-backend 2026-07-03 23:13:23 +00:00
parent f872f5636b
commit 9289c3d69d
2 changed files with 57 additions and 0 deletions

View file

@ -1699,6 +1699,10 @@ def parcel_report_status(
_REPORT_DOCX_MEDIA_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
# HEAD нужен фронтовому preflight'у (#2338): FastAPI НЕ добавляет HEAD к @router.get
# автоматически (прод отдавал 405 → UI не скачивал DOCX вовсе). FileResponse при
# HEAD нативно отдаёт только заголовки (Starlette send_header_only).
@router.head("/{cad_num}/report/download", include_in_schema=False)
@router.get(
"/{cad_num}/report/download",
summary="Скачать готовый полный отчёт участка — PDF или DOCX (#2259 PR-D/PR-F)",

View file

@ -422,3 +422,56 @@ def test_download_invalid_format_returns_422() -> None:
assert resp.status_code == 422, resp.text
finally:
app.dependency_overrides.clear()
def test_download_head_returns_headers_only(tmp_path: Path) -> None:
"""HEAD на download — 200 с заголовками БЕЗ тела (preflight фронта, #2338).
FastAPI не добавляет HEAD к @router.get автоматически прод отдавал 405,
HEAD-preflight абортился и UI молча не скачивал DOCX. Явный @router.head чинит.
"""
from app.core.db import get_db
pdf = tmp_path / "report.pdf"
pdf.write_bytes(b"%PDF-1.7 payload")
docx = tmp_path / "report.docx"
docx.write_bytes(b"PK\x03\x04 fake-docx")
report_row = _run(
510,
{
"pdf_path": str(pdf),
"docx_path": str(docx),
"analyze_run_id": 101,
"forecast_run_id": 202,
"generated_at": "2026-07-01T09:00:00+00:00",
},
)
rows = {REPORT_SCHEMA_VERSION: report_row}
db = MagicMock()
app.dependency_overrides[get_db] = _override_db(db)
try:
with patch("app.api.v1.parcels.latest_run_for", side_effect=_lrf_router(rows)):
client = TestClient(app)
resp = client.head(f"/api/v1/parcels/{_CAD}/report/download?format=docx")
assert resp.status_code == 200, resp.text
assert resp.headers["content-type"] == (
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
)
assert resp.content == b""
finally:
app.dependency_overrides.clear()
def test_download_head_404_when_not_ready() -> None:
"""HEAD для участка без готового отчёта — 404 (симметрично GET)."""
from app.core.db import get_db
db = MagicMock()
app.dependency_overrides[get_db] = _override_db(db)
try:
with patch("app.api.v1.parcels.latest_run_for", side_effect=_lrf_router({})):
client = TestClient(app)
resp = client.head(f"/api/v1/parcels/{_CAD}/report/download")
assert resp.status_code == 404
finally:
app.dependency_overrides.clear()