fix(cian): persist detail rich fields (description/kitchen/ceiling) + stamp detail_enriched_at
This commit is contained in:
parent
57800b24e9
commit
fe805ea528
2 changed files with 70 additions and 1 deletions
|
|
@ -48,6 +48,7 @@ class DetailEnrichment:
|
|||
repair_type: str | None = None # 'cosmetic' / 'design' / 'no' — raw Cian value
|
||||
repair_state: str | None = None # enum: needs_repair/standard/good/excellent
|
||||
kitchen_area_m2: float | None = None # offer.kitchenArea (м²)
|
||||
description: str | None = None # offer.description (текст объявления)
|
||||
views_total: int | None = None # Cian stats.totalViewsFormattedString → int
|
||||
views_today: int | None = None
|
||||
|
||||
|
|
@ -144,6 +145,7 @@ async def fetch_detail(
|
|||
repair_type=_extract_repair_type(offer),
|
||||
repair_state=_extract_repair_state(offer),
|
||||
kitchen_area_m2=_parse_float(offer.get("kitchenArea")),
|
||||
description=offer.get("description") or None,
|
||||
raw_offer=offer,
|
||||
)
|
||||
|
||||
|
|
@ -302,8 +304,10 @@ def save_detail_enrichment(db: Session, listing_id: int, enrichment: DetailEnric
|
|||
repair_type = COALESCE(:rt, repair_type),
|
||||
repair_state = COALESCE(:rs, repair_state),
|
||||
kitchen_area_m2 = COALESCE(CAST(:ka AS double precision), kitchen_area_m2),
|
||||
description = COALESCE(:descr, description),
|
||||
views_total = COALESCE(:vt, views_total),
|
||||
views_today = COALESCE(:vd, views_today)
|
||||
views_today = COALESCE(:vd, views_today),
|
||||
detail_enriched_at = NOW()
|
||||
WHERE id = CAST(:lid AS bigint)
|
||||
"""),
|
||||
{
|
||||
|
|
@ -315,6 +319,7 @@ def save_detail_enrichment(db: Session, listing_id: int, enrichment: DetailEnric
|
|||
"rt": enrichment.repair_type,
|
||||
"rs": enrichment.repair_state,
|
||||
"ka": enrichment.kitchen_area_m2,
|
||||
"descr": enrichment.description,
|
||||
"vt": enrichment.views_total,
|
||||
"vd": enrichment.views_today,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -462,6 +462,40 @@ async def test_fetch_detail_kitchen_area_none_when_missing(monkeypatch):
|
|||
assert result.kitchen_area_m2 is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fetch_detail_extracts_description(monkeypatch):
|
||||
"""offer.description → DetailEnrichment.description (для persist в listings)."""
|
||||
fake_state = {
|
||||
"offerData": {
|
||||
"offer": {
|
||||
"cianId": 555555,
|
||||
"description": "Продаётся уютная квартира с видом на парк.",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
monkeypatch.setattr(
|
||||
"app.services.scrapers.cian_detail.extract_state",
|
||||
lambda html, mfe, key: fake_state if key == "defaultState" else None,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"app.services.scrapers.cian_detail.extract_all_states",
|
||||
lambda html: {},
|
||||
)
|
||||
|
||||
response = MagicMock()
|
||||
response.status_code = 200
|
||||
response.text = "<html></html>"
|
||||
|
||||
session = MagicMock()
|
||||
session.get = AsyncMock(return_value=response)
|
||||
session.close = AsyncMock()
|
||||
|
||||
result = await fetch_detail("https://ekb.cian.ru/sale/flat/555555/", session=session)
|
||||
assert result is not None
|
||||
assert result.description == "Продаётся уютная квартира с видом на парк."
|
||||
|
||||
|
||||
# ── save_detail_enrichment — kitchen_area_m2 persisted ───────────────────────
|
||||
|
||||
|
||||
|
|
@ -504,6 +538,36 @@ def test_save_detail_enrichment_kitchen_area_none_passthrough():
|
|||
assert update_call_params["ka"] is None
|
||||
|
||||
|
||||
# ── save_detail_enrichment — description + detail_enriched_at stamp ───────────
|
||||
|
||||
|
||||
def test_save_detail_enrichment_writes_description():
|
||||
"""save_detail_enrichment передаёт description в UPDATE listings."""
|
||||
db = MagicMock()
|
||||
db.execute.return_value.fetchone.return_value = None
|
||||
|
||||
enrichment = DetailEnrichment(description="Светлая квартира рядом с парком")
|
||||
|
||||
save_detail_enrichment(db, listing_id=1002, enrichment=enrichment)
|
||||
|
||||
update_call_params = db.execute.call_args_list[0][0][1]
|
||||
assert update_call_params["descr"] == "Светлая квартира рядом с парком"
|
||||
|
||||
|
||||
def test_save_detail_enrichment_stamps_detail_enriched_at():
|
||||
"""UPDATE listings содержит detail_enriched_at = NOW() — иначе строка
|
||||
переобогащается каждый run (detail_enriched_at IS NULL filter)."""
|
||||
db = MagicMock()
|
||||
db.execute.return_value.fetchone.return_value = None
|
||||
|
||||
enrichment = DetailEnrichment(kitchen_area_m2=8.3)
|
||||
|
||||
save_detail_enrichment(db, listing_id=1003, enrichment=enrichment)
|
||||
|
||||
update_sql = str(db.execute.call_args_list[0][0][0])
|
||||
assert "detail_enriched_at = NOW()" in update_sql
|
||||
|
||||
|
||||
# ── fetch_detail browser_fetcher param ───────────────────────────────────────
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue