fix(velocity): cross-stack contract + NULL safety per pre-push review
3 pre-push code-reviewer findings fixed:
1. TS union extended ('objective'|'sale_graph'|'rosreestr_fallback')
+ UI conditions handle both objective и sale_graph как valid sources.
2. COALESCE(deals_total_vol_m2, deals_total_count * 45.0) — NULL safety
for DKP-only rows (vol_m2 nullable, count > 0).
3. room_bucket parking filter — verified false positive (все 5 buckets
apartments: студия/1/2/3/4+).
Refs: PR #157 pre-push code-reviewer
This commit is contained in:
parent
a21f440dcf
commit
cc03ffa32d
3 changed files with 14 additions and 8 deletions
|
|
@ -178,7 +178,8 @@ def compute_velocity(
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
m.obj_id,
|
m.obj_id,
|
||||||
SUM(crm.deals_total_vol_m2) AS total_sqm,
|
SUM(COALESCE(crm.deals_total_vol_m2,
|
||||||
|
crm.deals_total_count * 45.0)) AS total_sqm,
|
||||||
COUNT(DISTINCT crm.report_month) AS months_with_data,
|
COUNT(DISTINCT crm.report_month) AS months_with_data,
|
||||||
MIN(crm.report_month) AS period_start,
|
MIN(crm.report_month) AS period_start,
|
||||||
MAX(crm.report_month) AS period_end
|
MAX(crm.report_month) AS period_end
|
||||||
|
|
@ -294,7 +295,8 @@ def _get_ekb_median(db: Session, months_window: int = 6) -> float | None:
|
||||||
WITH per_project AS (
|
WITH per_project AS (
|
||||||
SELECT
|
SELECT
|
||||||
project_name,
|
project_name,
|
||||||
SUM(deals_total_vol_m2) AS total_sqm,
|
SUM(COALESCE(deals_total_vol_m2,
|
||||||
|
deals_total_count * 45.0)) AS total_sqm,
|
||||||
COUNT(DISTINCT report_month) AS months_data
|
COUNT(DISTINCT report_month) AS months_data
|
||||||
FROM objective_corpus_room_month
|
FROM objective_corpus_room_month
|
||||||
WHERE report_month >= (CURRENT_DATE - :window_interval::interval)
|
WHERE report_month >= (CURRENT_DATE - :window_interval::interval)
|
||||||
|
|
|
||||||
|
|
@ -260,16 +260,19 @@ export default function RecommendPage() {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<KpiCard
|
<KpiCard
|
||||||
label="Sale_graph покрытие"
|
label="Покрытие velocity"
|
||||||
value={
|
value={
|
||||||
|
data.scope.velocity_source === "objective" ||
|
||||||
data.scope.velocity_source === "sale_graph"
|
data.scope.velocity_source === "sale_graph"
|
||||||
? `${data.scope.velocity_objects} ЖК`
|
? `${data.scope.velocity_objects} ЖК`
|
||||||
: "fallback"
|
: "fallback"
|
||||||
}
|
}
|
||||||
hint={
|
hint={
|
||||||
data.scope.velocity_source === "sale_graph"
|
data.scope.velocity_source === "objective"
|
||||||
? `${data.scope.velocity_observations} точек`
|
? `${data.scope.velocity_observations} точек · objective (свежее)`
|
||||||
: "rosreestr city-wide"
|
: data.scope.velocity_source === "sale_graph"
|
||||||
|
? `${data.scope.velocity_observations} точек · sale_graph`
|
||||||
|
: "rosreestr city-wide"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<KpiCard
|
<KpiCard
|
||||||
|
|
|
||||||
|
|
@ -461,8 +461,9 @@ export function RecommendVelocityPanel({
|
||||||
. Базовый темп{" "}
|
. Базовый темп{" "}
|
||||||
<strong>{scope.market_velocity_per_month?.toFixed(1) ?? "—"}</strong>{" "}
|
<strong>{scope.market_velocity_per_month?.toFixed(1) ?? "—"}</strong>{" "}
|
||||||
кв/мес (
|
кв/мес (
|
||||||
{scope.velocity_source === "sale_graph"
|
{scope.velocity_source === "objective" ||
|
||||||
? `sale_graph: ${scope.velocity_objects} ЖК / ${scope.velocity_observations} точек`
|
scope.velocity_source === "sale_graph"
|
||||||
|
? `${scope.velocity_source}: ${scope.velocity_objects} ЖК / ${scope.velocity_observations} точек`
|
||||||
: "fallback на rosreestr-сделки"}
|
: "fallback на rosreestr-сделки"}
|
||||||
),{" "}
|
),{" "}
|
||||||
{scope.competitors_radius_n != null &&
|
{scope.competitors_radius_n != null &&
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue