mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-30 12:55:02 +00:00
fix(reporting): read scenario measures via denormalised recommendation.plan_id
The scenario measures modal came up empty because both measures routes gated on EXISTS against plan_recommendations — a retired join table with no rows for new-approach plans (25.7M legacy rows, none for e.g. portfolio 812's plans), so the query returned zero measures. Read the denormalised model instead: drive from the latest plan per property (default or scenario) and JOIN recommendation by the indexed property_id, scoped to the plan via recommendation.plan_id. Portfolio 812 default now returns 5 measures (solar_pv 54 homes/£266k, …) where it returned 0. Also removes the stale commented query block that referenced the retired plan_recommendations / recommendation_materials tables. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
eef9fdc171
commit
2f0f937fb6
2 changed files with 34 additions and 88 deletions
|
|
@ -20,62 +20,11 @@ export async function GET(
|
|||
const pid = BigInt(portfolioId);
|
||||
const sid = BigInt(scenarioId);
|
||||
|
||||
// TEMP: Remove batteries as underspecified
|
||||
// const result = await db.execute(sql`
|
||||
// WITH latest_plans AS (
|
||||
// SELECT DISTINCT ON (property_id)
|
||||
// *
|
||||
// FROM plan
|
||||
// WHERE portfolio_id = ${pid}
|
||||
// AND scenario_id = ${sid}
|
||||
// ORDER BY property_id, created_at DESC
|
||||
// ),
|
||||
|
||||
// recommendation_flags AS (
|
||||
// SELECT
|
||||
// r.id AS recommendation_id,
|
||||
// r.measure_type AS measure_type,
|
||||
// r.property_id AS property_id,
|
||||
// r.estimated_cost AS estimated_cost,
|
||||
// BOOL_OR(m.includes_battery) AS includes_battery
|
||||
|
||||
// FROM latest_plans lp
|
||||
// JOIN plan_recommendations pr
|
||||
// ON pr.plan_id = lp.id
|
||||
// JOIN recommendation r
|
||||
// ON r.id = pr.recommendation_id
|
||||
|
||||
// LEFT JOIN recommendation_materials rm
|
||||
// ON rm.recommendation_id = r.id
|
||||
// LEFT JOIN material m
|
||||
// ON m.id = rm.material_id
|
||||
// AND m.is_active = true
|
||||
|
||||
// WHERE r.default = true
|
||||
// AND r.already_installed = false
|
||||
|
||||
// GROUP BY
|
||||
// r.id,
|
||||
// r.measure_type,
|
||||
// r.property_id,
|
||||
// r.estimated_cost
|
||||
// )
|
||||
|
||||
// SELECT
|
||||
// measure_type,
|
||||
// COALESCE(includes_battery, false) AS includes_battery,
|
||||
|
||||
// COUNT(DISTINCT property_id)::int AS homes_count,
|
||||
// SUM(estimated_cost)::float AS total_cost,
|
||||
// AVG(estimated_cost)::float AS average_cost
|
||||
|
||||
// FROM recommendation_flags
|
||||
// GROUP BY
|
||||
// measure_type,
|
||||
// includes_battery
|
||||
// ORDER BY total_cost DESC;
|
||||
// `);
|
||||
|
||||
// Latest plan per property for this scenario, then its recommendations read
|
||||
// through the DENORMALISED link: join by the indexed recommendation.property_id
|
||||
// and scope to the plan via recommendation.plan_id. The plan_recommendations
|
||||
// join table is retired (no rows for new-approach plans), so the old EXISTS
|
||||
// against it returned zero measures. See the handover / ADR notes.
|
||||
const result = await db.execute(sql`
|
||||
SELECT
|
||||
r.measure_type,
|
||||
|
|
@ -83,23 +32,19 @@ export async function GET(
|
|||
COUNT(DISTINCT r.property_id)::int AS homes_count,
|
||||
SUM(r.estimated_cost)::float AS total_cost,
|
||||
AVG(r.estimated_cost)::float AS average_cost
|
||||
FROM recommendation r
|
||||
WHERE r.default = true
|
||||
FROM (
|
||||
SELECT DISTINCT ON (property_id)
|
||||
id, property_id
|
||||
FROM plan
|
||||
WHERE portfolio_id = ${pid}
|
||||
AND scenario_id = ${sid}
|
||||
ORDER BY property_id, created_at DESC
|
||||
) lp
|
||||
JOIN recommendation r
|
||||
ON r.property_id = lp.property_id
|
||||
AND r.plan_id = lp.id
|
||||
AND r.default = true
|
||||
AND r.already_installed = false
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM (
|
||||
SELECT DISTINCT ON (p.property_id)
|
||||
p.id
|
||||
FROM plan p
|
||||
WHERE p.portfolio_id = ${pid}
|
||||
AND p.scenario_id = ${sid}
|
||||
ORDER BY p.property_id, p.created_at DESC
|
||||
) lp
|
||||
JOIN plan_recommendations pr
|
||||
ON pr.plan_id = lp.id
|
||||
WHERE pr.recommendation_id = r.id
|
||||
)
|
||||
GROUP BY
|
||||
r.measure_type,
|
||||
r.type
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ export async function GET(
|
|||
|
||||
const pid = BigInt(portfolioId);
|
||||
|
||||
// Latest default plan per property, then its recommendations read through the
|
||||
// DENORMALISED link: join by the indexed recommendation.property_id and scope
|
||||
// to the plan via recommendation.plan_id. The plan_recommendations join table
|
||||
// is retired (no rows for new-approach plans), so the old EXISTS against it
|
||||
// returned zero measures.
|
||||
const result = await db.execute(sql`
|
||||
SELECT
|
||||
r.measure_type,
|
||||
|
|
@ -26,23 +31,19 @@ export async function GET(
|
|||
COUNT(DISTINCT r.property_id)::int AS homes_count,
|
||||
SUM(r.estimated_cost)::float AS total_cost,
|
||||
AVG(r.estimated_cost)::float AS average_cost
|
||||
FROM recommendation r
|
||||
WHERE r.default = true
|
||||
FROM (
|
||||
SELECT DISTINCT ON (property_id)
|
||||
id, property_id
|
||||
FROM plan
|
||||
WHERE portfolio_id = ${pid}
|
||||
AND is_default = true
|
||||
ORDER BY property_id, created_at DESC
|
||||
) lp
|
||||
JOIN recommendation r
|
||||
ON r.property_id = lp.property_id
|
||||
AND r.plan_id = lp.id
|
||||
AND r.default = true
|
||||
AND r.already_installed = false
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM (
|
||||
SELECT DISTINCT ON (p.property_id)
|
||||
p.id
|
||||
FROM plan p
|
||||
WHERE p.portfolio_id = ${pid}
|
||||
AND p.is_default = true
|
||||
ORDER BY p.property_id, p.created_at DESC
|
||||
) lp
|
||||
JOIN plan_recommendations pr
|
||||
ON pr.plan_id = lp.id
|
||||
WHERE pr.recommendation_id = r.id
|
||||
)
|
||||
GROUP BY
|
||||
r.measure_type,
|
||||
r.type
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue