feat(tradein/history): вернуть все параметры оценки в GET /history #2420
2 changed files with 91 additions and 1 deletions
|
|
@ -646,6 +646,11 @@ def estimate_history(
|
||||||
|
|
||||||
#2043 (BE-1): в проекцию добавлен sources_used (jsonb-массив источников) —
|
#2043 (BE-1): в проекцию добавлен sources_used (jsonb-массив источников) —
|
||||||
разлочивает колонку «ИСТОЧНИКОВ N/7» в CacheView (len(sources_used) на строку).
|
разлочивает колонку «ИСТОЧНИКОВ 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:
|
if not x_authenticated_user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
@ -682,7 +687,9 @@ def estimate_history(
|
||||||
f"""
|
f"""
|
||||||
SELECT id, address, rooms, area_m2, median_price,
|
SELECT id, address, rooms, area_m2, median_price,
|
||||||
confidence, n_analogs, created_at,
|
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
|
FROM trade_in_estimates
|
||||||
{where}
|
{where}
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
|
|
|
||||||
|
|
@ -178,3 +178,86 @@ def test_admin_filters_by_account(trade_in_app: FastAPI) -> None:
|
||||||
assert "created_by = :account" in sql
|
assert "created_by = :account" in sql
|
||||||
assert params["account"] == "kopylov"
|
assert params["account"] == "kopylov"
|
||||||
assert "owner" not in params
|
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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue