feat(tradein/history): вернуть floor/total_floors/year_built/house_type/repair_state/has_balcony в GET /history
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 7s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 1m0s

/history отдавал только address/rooms/area_m2 — остальные введённые параметры уже
персистятся в trade_in_estimates, но не выбирались; расширяем SELECT для витрины
«Предыдущие оценки» (CacheView) на фронте (follow-up фронт-PR).
This commit is contained in:
bot-backend 2026-07-04 16:00:39 +03:00
parent 8030f8ecef
commit 5cce0baf10
2 changed files with 91 additions and 1 deletions

View file

@ -646,6 +646,11 @@ def estimate_history(
#2043 (BE-1): в проекцию добавлен sources_used (jsonb-массив источников) —
разлочивает колонку «ИСТОЧНИКОВ N/7» в CacheView (len(sources_used) на строку).
#2417: добавлены floor/total_floors/year_built/house_type/repair_state/
has_balcony уже персистятся в trade_in_estimates при создании оценки
(см. TradeInEstimateInput / AggregatedEstimate), но раньше не выбирались
здесь. Nullable legacy строки / незаполненные поля отдаются как None.
"""
if not x_authenticated_user:
raise HTTPException(
@ -682,7 +687,9 @@ def estimate_history(
f"""
SELECT id, address, rooms, area_m2, median_price,
confidence, n_analogs, created_at,
COALESCE(sources_used, '[]'::jsonb) AS sources_used
COALESCE(sources_used, '[]'::jsonb) AS sources_used,
floor, total_floors, year_built,
house_type, repair_state, has_balcony
FROM trade_in_estimates
{where}
ORDER BY created_at DESC

View file

@ -178,3 +178,86 @@ def test_admin_filters_by_account(trade_in_app: FastAPI) -> None:
assert "created_by = :account" in sql
assert params["account"] == "kopylov"
assert "owner" not in params
def test_history_returns_full_input_params(trade_in_app: FastAPI) -> None:
"""#2417: /history проецирует floor/total_floors/year_built/house_type/
repair_state/has_balcony в дополнение к базовому подмножеству, включая
NULL-passthrough для строк, где эти поля никогда не заполнялись.
"""
db_mock = _make_db_mock(
[
{
"id": "1",
"address": "A",
"rooms": 2,
"area_m2": 50,
"median_price": 5_000_000,
"confidence": "medium",
"n_analogs": 7,
"created_at": "2026-05-29T00:00:00",
"sources_used": ["avito", "cian"],
"floor": 3,
"total_floors": 9,
"year_built": 2005,
"house_type": "panel",
"repair_state": "good",
"has_balcony": True,
},
{
"id": "2",
"address": "B",
"rooms": 1,
"area_m2": 33,
"median_price": 3_000_000,
"confidence": "low",
"n_analogs": 2,
"created_at": "2026-05-28T00:00:00",
"sources_used": [],
# legacy row / поля никогда не заполнялись пользователем.
"floor": None,
"total_floors": None,
"year_built": None,
"house_type": None,
"repair_state": None,
"has_balcony": None,
},
]
)
client = _client_with(trade_in_app, db_mock, role="admin")
resp = client.get(
"/api/v1/trade-in/history",
headers={"X-Authenticated-User": "admin"},
)
assert resp.status_code == 200
sql, _params = _captured_sql_and_params(db_mock)
for col in (
"floor",
"total_floors",
"year_built",
"house_type",
"repair_state",
"has_balcony",
):
assert col in sql
body = resp.json()
assert len(body) == 2
filled, legacy = body[0], body[1]
assert filled["floor"] == 3
assert filled["total_floors"] == 9
assert filled["year_built"] == 2005
assert filled["house_type"] == "panel"
assert filled["repair_state"] == "good"
assert filled["has_balcony"] is True
# NULL passthrough — не должно рейзить/подменяться дефолтами.
assert legacy["floor"] is None
assert legacy["total_floors"] is None
assert legacy["year_built"] is None
assert legacy["house_type"] is None
assert legacy["repair_state"] is None
assert legacy["has_balcony"] is None