mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
Merge pull request #304 from Hestia-Homes/feature/pashub-fetcher-migration
Migration for changes to EpcProperty, new property baseline table, and additional file type
This commit is contained in:
commit
41c5b127c1
7 changed files with 11293 additions and 26 deletions
14
CONTEXT.md
14
CONTEXT.md
|
|
@ -74,6 +74,20 @@ See [ADR-0001](./docs/adr/0001-bulk-upload-state-machine.md) for the deliberate
|
|||
- A **BulkUpload** has at most one **Task** (the orchestration handle for the FastAPI pipeline run); a Task has many **SubTasks** (one per pipeline stage: address matching, combiner).
|
||||
- A **Portfolio** has many **VocabularyMappings** — one row per `(category, description)` it has ever encountered across all its BulkUploads. See [ADR-0002](./docs/adr/0002-landlord-override-vocabulary.md).
|
||||
|
||||
### Baseline performance
|
||||
|
||||
**Lodged performance**:
|
||||
The SAP score, EPC band, CO₂ emissions, and primary energy intensity as submitted to the government EPC register. Ground truth from the register; never modified.
|
||||
_Avoid_: original performance, registered performance
|
||||
|
||||
**Effective performance**:
|
||||
The SAP score (and associated metrics) that the modelling engine actually uses as its baseline. Usually equals Lodged performance, but differs when a Landlord override or data-quality issue makes the lodged certificate unreliable — triggering a Rebaseline.
|
||||
_Avoid_: current performance, adjusted performance
|
||||
|
||||
**Rebaseline**:
|
||||
The act of substituting a corrected set of performance metrics in place of the Lodged values. Recorded on `property_baseline_performance` with a `rebaseline_reason` enum value: `none`, `pre_sap10`, `physical_state_changed`, or `both`.
|
||||
_Avoid_: override, adjustment, correction
|
||||
|
||||
## Example dialogue
|
||||
|
||||
> **Dev:** "If the **Combiner** finishes but the user hasn't clicked Finalise, what does the user see?"
|
||||
|
|
|
|||
291
backlog/drizzle-schema-handoff.md
Normal file
291
backlog/drizzle-schema-handoff.md
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
# Drizzle schema handoff — pending EPC migrations
|
||||
|
||||
**Task:** Update Drizzle table definitions in `src/app/db/schema/property.ts` to match the
|
||||
Python SQLModel definitions. Do **not** run `drizzle-kit generate` or any migration
|
||||
commands — the developer will run generation manually after your changes.
|
||||
|
||||
Two sets of changes are covered here:
|
||||
|
||||
1. EPC property round-trip fidelity gaps (fixes an active production error)
|
||||
2. New `property_baseline_performance` table
|
||||
|
||||
### Before starting: update the import line
|
||||
|
||||
`jsonb` is not currently imported. Add it (and `pgEnum` is already present):
|
||||
|
||||
```typescript
|
||||
import {
|
||||
bigserial,
|
||||
text,
|
||||
timestamp,
|
||||
pgTable,
|
||||
real,
|
||||
pgEnum,
|
||||
integer,
|
||||
boolean,
|
||||
smallint,
|
||||
bigint,
|
||||
uniqueIndex,
|
||||
jsonb, // ← add this
|
||||
} from "drizzle-orm/pg-core";
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. `epc_property` — new columns
|
||||
|
||||
Add these columns to the `epcProperty` table. All are nullable (no `.notNull()`).
|
||||
|
||||
```typescript
|
||||
// Mechanical ventilation
|
||||
mechanicalVentDuctInsulationLevel: integer("mechanical_vent_duct_insulation_level"),
|
||||
|
||||
// Addendum flags
|
||||
addendumStoneWalls: boolean("addendum_stone_walls"),
|
||||
addendumSystemBuild: boolean("addendum_system_build"),
|
||||
addendumNumbers: jsonb("addendum_numbers"),
|
||||
|
||||
// Heating counts
|
||||
heatingNumberBaths: integer("heating_number_baths"),
|
||||
heatingNumberBathsWwhrs: integer("heating_number_baths_wwhrs"),
|
||||
heatingElectricShowerCount: integer("heating_electric_shower_count"),
|
||||
heatingMixerShowerCount: integer("heating_mixer_shower_count"),
|
||||
|
||||
// Ventilation detail
|
||||
ventilationPresent: boolean("ventilation_present").notNull().default(false),
|
||||
ventilationShelteredSides: integer("ventilation_sheltered_sides"),
|
||||
ventilationHasSuspendedTimberFloor: boolean("ventilation_has_suspended_timber_floor"),
|
||||
ventilationSuspendedTimberFloorSealed: boolean("ventilation_suspended_timber_floor_sealed"),
|
||||
ventilationHasDraughtLobby: boolean("ventilation_has_draught_lobby"),
|
||||
ventilationAirPermeabilityAp4M3HM2: real("ventilation_air_permeability_ap4_m3_h_m2"),
|
||||
ventilationMechanicalVentilationKind: text("ventilation_mechanical_ventilation_kind"),
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. `epc_property` — type changes: `text` → `jsonb`
|
||||
|
||||
Change the following existing columns from `text(...)` to `jsonb(...)`. Preserve any
|
||||
`.notNull()` that is currently present (none of these have it, but double-check).
|
||||
|
||||
| Property name | Column name |
|
||||
| ------------------------------- | ---------------------------------- |
|
||||
| `energyPvConnection` | `energy_pv_connection` |
|
||||
| `heatingCylinderSize` | `heating_cylinder_size` |
|
||||
| `heatingImmersionHeatingType` | `heating_immersion_heating_type` |
|
||||
| `heatingCylinderInsulationType` | `heating_cylinder_insulation_type` |
|
||||
| `heatingSecondaryHeatingType` | `heating_secondary_heating_type` |
|
||||
| `heatingShowerOutletType` | `heating_shower_outlet_type` |
|
||||
|
||||
Example — before:
|
||||
|
||||
```typescript
|
||||
heatingCylinderSize: text("heating_cylinder_size"),
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```typescript
|
||||
heatingCylinderSize: jsonb("heating_cylinder_size"),
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. `epc_main_heating_detail` — type changes: `text` → `jsonb`
|
||||
|
||||
These four columns are currently `text(...).notNull()`. Change to `jsonb(...).notNull()`.
|
||||
|
||||
| Property name | Column name |
|
||||
| -------------------- | ---------------------- |
|
||||
| `mainFuelType` | `main_fuel_type` |
|
||||
| `heatEmitterType` | `heat_emitter_type` |
|
||||
| `emitterTemperature` | `emitter_temperature` |
|
||||
| `mainHeatingControl` | `main_heating_control` |
|
||||
|
||||
---
|
||||
|
||||
## 4. `epc_building_part` — type changes and new columns
|
||||
|
||||
### 4a. Type changes: `text` → `jsonb`
|
||||
|
||||
| Property name | Column name | Currently nullable? |
|
||||
| ----------------------------- | -------------------------------- | ----------------------------------------------------------------------------------------- |
|
||||
| `wallConstruction` | `wall_construction` | no (`.notNull()`) |
|
||||
| `wallInsulationType` | `wall_insulation_type` | no (`.notNull()`) |
|
||||
| `partyWallConstruction` | `party_wall_construction` | **drop `.notNull()`** — Python has this as nullable; the TypeScript `.notNull()` is wrong |
|
||||
| `flatRoofInsulationThickness` | `flat_roof_insulation_thickness` | yes |
|
||||
| `roofInsulationLocation` | `roof_insulation_location` | yes |
|
||||
| `roofInsulationThickness` | `roof_insulation_thickness` | yes |
|
||||
|
||||
### 4b. New columns (add, nullable)
|
||||
|
||||
```typescript
|
||||
roofConstructionType: text("roof_construction_type"),
|
||||
curtainWallAge: text("curtain_wall_age"),
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. `epc_window` — type changes: `text` → `jsonb`
|
||||
|
||||
| Property name | Column name | Currently nullable? |
|
||||
| -------------------------- | ---------------------------- | ---------------------------------------------------------- |
|
||||
| `glazingGap` | `glazing_gap` | no (`.notNull()`) |
|
||||
| `orientation` | `orientation` | no (`.notNull()`) |
|
||||
| `windowType` | `window_type` | no (`.notNull()`) |
|
||||
| `glazingType` | `glazing_type` | no (`.notNull()`) |
|
||||
| `windowLocation` | `window_location` | no (`.notNull()`) |
|
||||
| `windowWallType` | `window_wall_type` | no (`.notNull()`) |
|
||||
| `draughtProofed` | `draught_proofed` | no (`.notNull()`) — currently `boolean`, change to `jsonb` |
|
||||
| `permanentShuttersPresent` | `permanent_shutters_present` | no (`.notNull()`) — currently `boolean`, change to `jsonb` |
|
||||
| `transmissionDataSource` | `transmission_data_source` | yes |
|
||||
|
||||
> **Note on `draughtProofed` and `permanentShuttersPresent`:** these are `boolean` in the
|
||||
> current TypeScript schema but `Union[bool, str]` JSONB in the Python model. Change them
|
||||
> to `jsonb(...).notNull()` — the TypeScript boolean type was incorrect.
|
||||
>
|
||||
> These two columns also require **boolean-specific** USING clauses in the generated migration
|
||||
> (PostgreSQL will not implicitly cast `boolean` to `jsonb`):
|
||||
>
|
||||
> ```sql
|
||||
> ALTER TABLE "epc_window" ALTER COLUMN "draught_proofed"
|
||||
> SET DATA TYPE jsonb
|
||||
> USING to_json("draught_proofed")::jsonb;
|
||||
>
|
||||
> ALTER TABLE "epc_window" ALTER COLUMN "permanent_shutters_present"
|
||||
> SET DATA TYPE jsonb
|
||||
> USING to_json("permanent_shutters_present")::jsonb;
|
||||
> ```
|
||||
>
|
||||
> `to_json` converts `true`/`false` to JSON booleans (not quoted strings), which is correct
|
||||
> for the `Union[bool, str]` Python type.
|
||||
|
||||
---
|
||||
|
||||
## 6. New table: `epc_renewable_heat_incentive`
|
||||
|
||||
Add this table to `src/app/db/schema/property.ts`:
|
||||
|
||||
```typescript
|
||||
export const epcRenewableHeatIncentive = pgTable(
|
||||
"epc_renewable_heat_incentive",
|
||||
{
|
||||
id: bigserial("id", { mode: "bigint" }).primaryKey(),
|
||||
epcPropertyId: bigint("epc_property_id", { mode: "bigint" })
|
||||
.notNull()
|
||||
.unique()
|
||||
.references(() => epcProperty.id),
|
||||
spaceHeatingKwh: real("space_heating_kwh").notNull(),
|
||||
waterHeatingKwh: real("water_heating_kwh").notNull(),
|
||||
impactOfLoftInsulationKwh: real("impact_of_loft_insulation_kwh"),
|
||||
impactOfCavityInsulationKwh: real("impact_of_cavity_insulation_kwh"),
|
||||
impactOfSolidWallInsulationKwh: real("impact_of_solid_wall_insulation_kwh"),
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. New table: `property_baseline_performance`
|
||||
|
||||
First, add the enum (before the table definition):
|
||||
|
||||
```typescript
|
||||
export const rebaselineReasonEnum = pgEnum("rebaseline_reason", [
|
||||
"none",
|
||||
"pre_sap10",
|
||||
"physical_state_changed",
|
||||
"both",
|
||||
]);
|
||||
```
|
||||
|
||||
Then add the table to `src/app/db/schema/property.ts`:
|
||||
|
||||
```typescript
|
||||
export const propertyBaselinePerformance = pgTable(
|
||||
"property_baseline_performance",
|
||||
{
|
||||
id: bigserial("id", { mode: "bigint" }).primaryKey(),
|
||||
propertyId: bigint("property_id", { mode: "bigint" })
|
||||
.notNull()
|
||||
.unique()
|
||||
.references(() => property.id),
|
||||
|
||||
// Lodged performance (from gov EPC register)
|
||||
lodgedSapScore: integer("lodged_sap_score").notNull(),
|
||||
lodgedEpcBand: epcEnum("lodged_epc_band").notNull(),
|
||||
lodgedCo2EmissionsTPerYr: real("lodged_co2_emissions_t_per_yr").notNull(),
|
||||
lodgedPrimaryEnergyIntensityKwhPerM2Yr: integer(
|
||||
"lodged_primary_energy_intensity_kwh_per_m2_yr",
|
||||
).notNull(),
|
||||
|
||||
// Effective performance (what modelling scored against)
|
||||
effectiveSapScore: integer("effective_sap_score").notNull(),
|
||||
effectiveEpcBand: epcEnum("effective_epc_band").notNull(),
|
||||
effectiveCo2EmissionsTPerYr: real(
|
||||
"effective_co2_emissions_t_per_yr",
|
||||
).notNull(),
|
||||
effectivePrimaryEnergyIntensityKwhPerM2Yr: integer(
|
||||
"effective_primary_energy_intensity_kwh_per_m2_yr",
|
||||
).notNull(),
|
||||
|
||||
rebaselineReason: rebaselineReasonEnum("rebaseline_reason").notNull(),
|
||||
|
||||
// Interim energy demand (from EPC RHI data; superseded by bill block below once populated)
|
||||
spaceHeatingKwh: real("space_heating_kwh").notNull(),
|
||||
waterHeatingKwh: real("water_heating_kwh").notNull(),
|
||||
|
||||
// Bill block — nullable until BillDerivation wiring lands
|
||||
fuelRatesPeriod: text("fuel_rates_period"),
|
||||
heatingKwh: real("heating_kwh"),
|
||||
heatingCostGbp: real("heating_cost_gbp"),
|
||||
hotWaterKwh: real("hot_water_kwh"),
|
||||
hotWaterCostGbp: real("hot_water_cost_gbp"),
|
||||
lightingKwh: real("lighting_kwh"),
|
||||
lightingCostGbp: real("lighting_cost_gbp"),
|
||||
appliancesKwh: real("appliances_kwh"),
|
||||
appliancesCostGbp: real("appliances_cost_gbp"),
|
||||
cookingKwh: real("cooking_kwh"),
|
||||
cookingCostGbp: real("cooking_cost_gbp"),
|
||||
pumpsFansKwh: real("pumps_fans_kwh"),
|
||||
pumpsFansCostGbp: real("pumps_fans_cost_gbp"),
|
||||
coolingKwh: real("cooling_kwh"),
|
||||
coolingCostGbp: real("cooling_cost_gbp"),
|
||||
standingChargesGbp: real("standing_charges_gbp"),
|
||||
segCreditGbp: real("seg_credit_gbp"),
|
||||
totalAnnualBillGbp: real("total_annual_bill_gbp"),
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Post-generation checklist (developer action, not Claude)
|
||||
|
||||
After running `drizzle-kit generate`, **manually edit the generated `.sql` file** before
|
||||
applying it. For every `ALTER COLUMN ... SET DATA TYPE jsonb` statement, add a `USING`
|
||||
expression to handle existing rows safely. Without it, any row with a bare unquoted
|
||||
string (e.g. `Electric Shower`) will cause the migration to fail.
|
||||
|
||||
Replace the generated form:
|
||||
|
||||
```sql
|
||||
ALTER TABLE "epc_property" ALTER COLUMN "heating_shower_outlet_type" SET DATA TYPE jsonb;
|
||||
```
|
||||
|
||||
With:
|
||||
|
||||
```sql
|
||||
ALTER TABLE "epc_property" ALTER COLUMN "heating_shower_outlet_type"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "heating_shower_outlet_type" IS NULL THEN NULL
|
||||
WHEN "heating_shower_outlet_type" ~ '^-?[0-9]+$' THEN "heating_shower_outlet_type"::jsonb
|
||||
ELSE to_json("heating_shower_outlet_type")::jsonb
|
||||
END
|
||||
);
|
||||
```
|
||||
|
||||
Apply this pattern to **every** `text → jsonb` column across all four tables
|
||||
(`epc_property`, `epc_main_heating_detail`, `epc_building_part`, `epc_window`).
|
||||
281
src/app/db/migrations/0220_glamorous_phantom_reporter.sql
Normal file
281
src/app/db/migrations/0220_glamorous_phantom_reporter.sql
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
CREATE TYPE "public"."rebaseline_reason" AS ENUM('none', 'pre_sap10', 'physical_state_changed', 'both');--> statement-breakpoint
|
||||
ALTER TYPE "public"."file_type" ADD VALUE 'other';--> statement-breakpoint
|
||||
CREATE TABLE "epc_renewable_heat_incentive" (
|
||||
"id" bigserial PRIMARY KEY NOT NULL,
|
||||
"epc_property_id" bigint NOT NULL,
|
||||
"space_heating_kwh" real NOT NULL,
|
||||
"water_heating_kwh" real NOT NULL,
|
||||
"impact_of_loft_insulation_kwh" real,
|
||||
"impact_of_cavity_insulation_kwh" real,
|
||||
"impact_of_solid_wall_insulation_kwh" real,
|
||||
CONSTRAINT "epc_renewable_heat_incentive_epc_property_id_unique" UNIQUE("epc_property_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "property_baseline_performance" (
|
||||
"id" bigserial PRIMARY KEY NOT NULL,
|
||||
"property_id" bigint NOT NULL,
|
||||
"lodged_sap_score" integer NOT NULL,
|
||||
"lodged_epc_band" "epc" NOT NULL,
|
||||
"lodged_co2_emissions_t_per_yr" real NOT NULL,
|
||||
"lodged_primary_energy_intensity_kwh_per_m2_yr" integer NOT NULL,
|
||||
"effective_sap_score" integer NOT NULL,
|
||||
"effective_epc_band" "epc" NOT NULL,
|
||||
"effective_co2_emissions_t_per_yr" real NOT NULL,
|
||||
"effective_primary_energy_intensity_kwh_per_m2_yr" integer NOT NULL,
|
||||
"rebaseline_reason" "rebaseline_reason" NOT NULL,
|
||||
"space_heating_kwh" real NOT NULL,
|
||||
"water_heating_kwh" real NOT NULL,
|
||||
"fuel_rates_period" text,
|
||||
"heating_kwh" real,
|
||||
"heating_cost_gbp" real,
|
||||
"hot_water_kwh" real,
|
||||
"hot_water_cost_gbp" real,
|
||||
"lighting_kwh" real,
|
||||
"lighting_cost_gbp" real,
|
||||
"appliances_kwh" real,
|
||||
"appliances_cost_gbp" real,
|
||||
"cooking_kwh" real,
|
||||
"cooking_cost_gbp" real,
|
||||
"pumps_fans_kwh" real,
|
||||
"pumps_fans_cost_gbp" real,
|
||||
"cooling_kwh" real,
|
||||
"cooling_cost_gbp" real,
|
||||
"standing_charges_gbp" real,
|
||||
"seg_credit_gbp" real,
|
||||
"total_annual_bill_gbp" real,
|
||||
CONSTRAINT "property_baseline_performance_property_id_unique" UNIQUE("property_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "epc_building_part" ALTER COLUMN "wall_construction"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "wall_construction" IS NULL THEN NULL
|
||||
WHEN "wall_construction" ~ '^-?[0-9]+$' THEN "wall_construction"::jsonb
|
||||
ELSE to_json("wall_construction")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_building_part" ALTER COLUMN "wall_insulation_type"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "wall_insulation_type" IS NULL THEN NULL
|
||||
WHEN "wall_insulation_type" ~ '^-?[0-9]+$' THEN "wall_insulation_type"::jsonb
|
||||
ELSE to_json("wall_insulation_type")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_building_part" ALTER COLUMN "party_wall_construction"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "party_wall_construction" IS NULL THEN NULL
|
||||
WHEN "party_wall_construction" ~ '^-?[0-9]+$' THEN "party_wall_construction"::jsonb
|
||||
ELSE to_json("party_wall_construction")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_building_part" ALTER COLUMN "party_wall_construction" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "epc_building_part" ALTER COLUMN "flat_roof_insulation_thickness"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "flat_roof_insulation_thickness" IS NULL THEN NULL
|
||||
WHEN "flat_roof_insulation_thickness" ~ '^-?[0-9]+$' THEN "flat_roof_insulation_thickness"::jsonb
|
||||
ELSE to_json("flat_roof_insulation_thickness")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_building_part" ALTER COLUMN "roof_insulation_location"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "roof_insulation_location" IS NULL THEN NULL
|
||||
WHEN "roof_insulation_location" ~ '^-?[0-9]+$' THEN "roof_insulation_location"::jsonb
|
||||
ELSE to_json("roof_insulation_location")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_building_part" ALTER COLUMN "roof_insulation_thickness"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "roof_insulation_thickness" IS NULL THEN NULL
|
||||
WHEN "roof_insulation_thickness" ~ '^-?[0-9]+$' THEN "roof_insulation_thickness"::jsonb
|
||||
ELSE to_json("roof_insulation_thickness")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_main_heating_detail" ALTER COLUMN "main_fuel_type"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "main_fuel_type" IS NULL THEN NULL
|
||||
WHEN "main_fuel_type" ~ '^-?[0-9]+$' THEN "main_fuel_type"::jsonb
|
||||
ELSE to_json("main_fuel_type")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_main_heating_detail" ALTER COLUMN "heat_emitter_type"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "heat_emitter_type" IS NULL THEN NULL
|
||||
WHEN "heat_emitter_type" ~ '^-?[0-9]+$' THEN "heat_emitter_type"::jsonb
|
||||
ELSE to_json("heat_emitter_type")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_main_heating_detail" ALTER COLUMN "emitter_temperature"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "emitter_temperature" IS NULL THEN NULL
|
||||
WHEN "emitter_temperature" ~ '^-?[0-9]+$' THEN "emitter_temperature"::jsonb
|
||||
ELSE to_json("emitter_temperature")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_main_heating_detail" ALTER COLUMN "main_heating_control"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "main_heating_control" IS NULL THEN NULL
|
||||
WHEN "main_heating_control" ~ '^-?[0-9]+$' THEN "main_heating_control"::jsonb
|
||||
ELSE to_json("main_heating_control")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ALTER COLUMN "energy_pv_connection"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "energy_pv_connection" IS NULL THEN NULL
|
||||
WHEN "energy_pv_connection" ~ '^-?[0-9]+$' THEN "energy_pv_connection"::jsonb
|
||||
ELSE to_json("energy_pv_connection")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ALTER COLUMN "heating_cylinder_size"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "heating_cylinder_size" IS NULL THEN NULL
|
||||
WHEN "heating_cylinder_size" ~ '^-?[0-9]+$' THEN "heating_cylinder_size"::jsonb
|
||||
ELSE to_json("heating_cylinder_size")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ALTER COLUMN "heating_immersion_heating_type"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "heating_immersion_heating_type" IS NULL THEN NULL
|
||||
WHEN "heating_immersion_heating_type" ~ '^-?[0-9]+$' THEN "heating_immersion_heating_type"::jsonb
|
||||
ELSE to_json("heating_immersion_heating_type")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ALTER COLUMN "heating_cylinder_insulation_type"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "heating_cylinder_insulation_type" IS NULL THEN NULL
|
||||
WHEN "heating_cylinder_insulation_type" ~ '^-?[0-9]+$' THEN "heating_cylinder_insulation_type"::jsonb
|
||||
ELSE to_json("heating_cylinder_insulation_type")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ALTER COLUMN "heating_secondary_heating_type"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "heating_secondary_heating_type" IS NULL THEN NULL
|
||||
WHEN "heating_secondary_heating_type" ~ '^-?[0-9]+$' THEN "heating_secondary_heating_type"::jsonb
|
||||
ELSE to_json("heating_secondary_heating_type")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ALTER COLUMN "heating_shower_outlet_type"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "heating_shower_outlet_type" IS NULL THEN NULL
|
||||
WHEN "heating_shower_outlet_type" ~ '^-?[0-9]+$' THEN "heating_shower_outlet_type"::jsonb
|
||||
ELSE to_json("heating_shower_outlet_type")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_window" ALTER COLUMN "glazing_gap"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "glazing_gap" IS NULL THEN NULL
|
||||
WHEN "glazing_gap" ~ '^-?[0-9]+$' THEN "glazing_gap"::jsonb
|
||||
ELSE to_json("glazing_gap")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_window" ALTER COLUMN "orientation"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "orientation" IS NULL THEN NULL
|
||||
WHEN "orientation" ~ '^-?[0-9]+$' THEN "orientation"::jsonb
|
||||
ELSE to_json("orientation")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_window" ALTER COLUMN "window_type"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "window_type" IS NULL THEN NULL
|
||||
WHEN "window_type" ~ '^-?[0-9]+$' THEN "window_type"::jsonb
|
||||
ELSE to_json("window_type")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_window" ALTER COLUMN "glazing_type"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "glazing_type" IS NULL THEN NULL
|
||||
WHEN "glazing_type" ~ '^-?[0-9]+$' THEN "glazing_type"::jsonb
|
||||
ELSE to_json("glazing_type")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_window" ALTER COLUMN "draught_proofed"
|
||||
SET DATA TYPE jsonb
|
||||
USING to_json("draught_proofed")::jsonb;--> statement-breakpoint
|
||||
ALTER TABLE "epc_window" ALTER COLUMN "window_location"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "window_location" IS NULL THEN NULL
|
||||
WHEN "window_location" ~ '^-?[0-9]+$' THEN "window_location"::jsonb
|
||||
ELSE to_json("window_location")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_window" ALTER COLUMN "window_wall_type"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "window_wall_type" IS NULL THEN NULL
|
||||
WHEN "window_wall_type" ~ '^-?[0-9]+$' THEN "window_wall_type"::jsonb
|
||||
ELSE to_json("window_wall_type")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_window" ALTER COLUMN "permanent_shutters_present"
|
||||
SET DATA TYPE jsonb
|
||||
USING to_json("permanent_shutters_present")::jsonb;--> statement-breakpoint
|
||||
ALTER TABLE "epc_window" ALTER COLUMN "transmission_data_source"
|
||||
SET DATA TYPE jsonb
|
||||
USING (
|
||||
CASE
|
||||
WHEN "transmission_data_source" IS NULL THEN NULL
|
||||
WHEN "transmission_data_source" ~ '^-?[0-9]+$' THEN "transmission_data_source"::jsonb
|
||||
ELSE to_json("transmission_data_source")::jsonb
|
||||
END
|
||||
);--> statement-breakpoint
|
||||
ALTER TABLE "epc_building_part" ADD COLUMN "roof_construction_type" text;--> statement-breakpoint
|
||||
ALTER TABLE "epc_building_part" ADD COLUMN "curtain_wall_age" text;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "mechanical_vent_duct_insulation_level" integer;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "addendum_stone_walls" boolean;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "addendum_system_build" boolean;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "addendum_numbers" jsonb;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "heating_number_baths" integer;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "heating_number_baths_wwhrs" integer;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "heating_electric_shower_count" integer;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "heating_mixer_shower_count" integer;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "ventilation_present" boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "ventilation_sheltered_sides" integer;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "ventilation_has_suspended_timber_floor" boolean;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "ventilation_suspended_timber_floor_sealed" boolean;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "ventilation_has_draught_lobby" boolean;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "ventilation_air_permeability_ap4_m3_h_m2" real;--> statement-breakpoint
|
||||
ALTER TABLE "epc_property" ADD COLUMN "ventilation_mechanical_ventilation_kind" text;--> statement-breakpoint
|
||||
ALTER TABLE "epc_renewable_heat_incentive" ADD CONSTRAINT "epc_renewable_heat_incentive_epc_property_id_epc_property_id_fk" FOREIGN KEY ("epc_property_id") REFERENCES "public"."epc_property"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "property_baseline_performance" ADD CONSTRAINT "property_baseline_performance_property_id_property_id_fk" FOREIGN KEY ("property_id") REFERENCES "public"."property"("id") ON DELETE no action ON UPDATE no action;
|
||||
10565
src/app/db/migrations/meta/0220_snapshot.json
Normal file
10565
src/app/db/migrations/meta/0220_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1541,6 +1541,13 @@
|
|||
"when": 1780419959831,
|
||||
"tag": "0219_add_verify_ack",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 220,
|
||||
"version": "7",
|
||||
"when": 1780483404142,
|
||||
"tag": "0220_glamorous_phantom_reporter",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import {
|
|||
smallint,
|
||||
bigint,
|
||||
uniqueIndex,
|
||||
jsonb,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { portfolio, PortfolioStatus } from "./portfolio";
|
||||
import { InferModel } from "drizzle-orm";
|
||||
|
|
@ -514,25 +515,25 @@ export const epcProperty = pgTable(
|
|||
energyIsDwellingExportCapable: boolean("energy_is_dwelling_export_capable").notNull(),
|
||||
energyWindTurbinesTerrainType: text("energy_wind_turbines_terrain_type").notNull(),
|
||||
energyElectricitySmartMeterPresent: boolean("energy_electricity_smart_meter_present").notNull(),
|
||||
energyPvConnection: text("energy_pv_connection"),
|
||||
energyPvConnection: jsonb("energy_pv_connection"),
|
||||
energyPvPercentRoofArea: integer("energy_pv_percent_roof_area"),
|
||||
energyPvBatteryCapacity: real("energy_pv_battery_capacity"),
|
||||
energyWindTurbineHubHeight: real("energy_wind_turbine_hub_height"),
|
||||
energyWindTurbineRotorDiameter: real("energy_wind_turbine_rotor_diameter"),
|
||||
|
||||
// Heating config
|
||||
heatingCylinderSize: text("heating_cylinder_size"),
|
||||
heatingCylinderSize: jsonb("heating_cylinder_size"),
|
||||
heatingWaterHeatingCode: integer("heating_water_heating_code"),
|
||||
heatingWaterHeatingFuel: integer("heating_water_heating_fuel"),
|
||||
heatingImmersionHeatingType: text("heating_immersion_heating_type"),
|
||||
heatingCylinderInsulationType: text("heating_cylinder_insulation_type"),
|
||||
heatingImmersionHeatingType: jsonb("heating_immersion_heating_type"),
|
||||
heatingCylinderInsulationType: jsonb("heating_cylinder_insulation_type"),
|
||||
heatingCylinderThermostat: text("heating_cylinder_thermostat"),
|
||||
heatingSecondaryFuelType: integer("heating_secondary_fuel_type"),
|
||||
heatingSecondaryHeatingType: text("heating_secondary_heating_type"),
|
||||
heatingSecondaryHeatingType: jsonb("heating_secondary_heating_type"),
|
||||
heatingCylinderInsulationThicknessMm: integer("heating_cylinder_insulation_thickness_mm"),
|
||||
heatingWwhrsIndexNumber1: integer("heating_wwhrs_index_number_1"),
|
||||
heatingWwhrsIndexNumber2: integer("heating_wwhrs_index_number_2"),
|
||||
heatingShowerOutletType: text("heating_shower_outlet_type"),
|
||||
heatingShowerOutletType: jsonb("heating_shower_outlet_type"),
|
||||
heatingShowerWwhrs: integer("heating_shower_wwhrs"),
|
||||
|
||||
// Ventilation
|
||||
|
|
@ -553,6 +554,27 @@ export const epcProperty = pgTable(
|
|||
mechanicalVentDuctInsulation: integer("mechanical_vent_duct_insulation"),
|
||||
mechanicalVentilationIndexNumber: integer("mechanical_ventilation_index_number"),
|
||||
mechanicalVentMeasuredInstallation: text("mechanical_vent_measured_installation"),
|
||||
mechanicalVentDuctInsulationLevel: integer("mechanical_vent_duct_insulation_level"),
|
||||
|
||||
// Addendum flags
|
||||
addendumStoneWalls: boolean("addendum_stone_walls"),
|
||||
addendumSystemBuild: boolean("addendum_system_build"),
|
||||
addendumNumbers: jsonb("addendum_numbers"),
|
||||
|
||||
// Heating counts
|
||||
heatingNumberBaths: integer("heating_number_baths"),
|
||||
heatingNumberBathsWwhrs: integer("heating_number_baths_wwhrs"),
|
||||
heatingElectricShowerCount: integer("heating_electric_shower_count"),
|
||||
heatingMixerShowerCount: integer("heating_mixer_shower_count"),
|
||||
|
||||
// Ventilation detail
|
||||
ventilationPresent: boolean("ventilation_present").notNull().default(false),
|
||||
ventilationShelteredSides: integer("ventilation_sheltered_sides"),
|
||||
ventilationHasSuspendedTimberFloor: boolean("ventilation_has_suspended_timber_floor"),
|
||||
ventilationSuspendedTimberFloorSealed: boolean("ventilation_suspended_timber_floor_sealed"),
|
||||
ventilationHasDraughtLobby: boolean("ventilation_has_draught_lobby"),
|
||||
ventilationAirPermeabilityAp4M3HM2: real("ventilation_air_permeability_ap4_m3_h_m2"),
|
||||
ventilationMechanicalVentilationKind: text("ventilation_mechanical_ventilation_kind"),
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex("uq_epc_property_property_portfolio").on(
|
||||
|
|
@ -627,10 +649,10 @@ export const epcMainHeatingDetail = pgTable(
|
|||
.references(() => epcProperty.id),
|
||||
|
||||
hasFghrs: boolean("has_fghrs").notNull(),
|
||||
mainFuelType: text("main_fuel_type").notNull(),
|
||||
heatEmitterType: text("heat_emitter_type").notNull(),
|
||||
emitterTemperature: text("emitter_temperature").notNull(),
|
||||
mainHeatingControl: text("main_heating_control").notNull(),
|
||||
mainFuelType: jsonb("main_fuel_type").notNull(),
|
||||
heatEmitterType: jsonb("heat_emitter_type").notNull(),
|
||||
emitterTemperature: jsonb("emitter_temperature").notNull(),
|
||||
mainHeatingControl: jsonb("main_heating_control").notNull(),
|
||||
fanFluePresent: boolean("fan_flue_present"),
|
||||
boilerFlueType: integer("boiler_flue_type"),
|
||||
boilerIgnitionType: integer("boiler_ignition_type"),
|
||||
|
|
@ -661,10 +683,10 @@ export const epcBuildingPart = pgTable(
|
|||
constructionAgeBand: text("construction_age_band").notNull(),
|
||||
|
||||
// Wall
|
||||
wallConstruction: text("wall_construction").notNull(),
|
||||
wallInsulationType: text("wall_insulation_type").notNull(),
|
||||
wallConstruction: jsonb("wall_construction").notNull(),
|
||||
wallInsulationType: jsonb("wall_insulation_type").notNull(),
|
||||
wallThicknessMeasured: boolean("wall_thickness_measured").notNull(),
|
||||
partyWallConstruction: text("party_wall_construction").notNull(),
|
||||
partyWallConstruction: jsonb("party_wall_construction"),
|
||||
buildingPartNumber: integer("building_part_number"),
|
||||
wallDryLined: boolean("wall_dry_lined"),
|
||||
wallThicknessMm: integer("wall_thickness_mm"),
|
||||
|
|
@ -674,7 +696,7 @@ export const epcBuildingPart = pgTable(
|
|||
// Floor
|
||||
floorHeatLoss: integer("floor_heat_loss"),
|
||||
floorInsulationThickness: text("floor_insulation_thickness"),
|
||||
flatRoofInsulationThickness: text("flat_roof_insulation_thickness"),
|
||||
flatRoofInsulationThickness: jsonb("flat_roof_insulation_thickness"),
|
||||
floorType: text("floor_type"),
|
||||
floorConstructionType: text("floor_construction_type"),
|
||||
floorInsulationTypeStr: text("floor_insulation_type_str"),
|
||||
|
|
@ -682,8 +704,11 @@ export const epcBuildingPart = pgTable(
|
|||
|
||||
// Roof
|
||||
roofConstruction: integer("roof_construction"),
|
||||
roofInsulationLocation: text("roof_insulation_location"),
|
||||
roofInsulationThickness: text("roof_insulation_thickness"),
|
||||
roofInsulationLocation: jsonb("roof_insulation_location"),
|
||||
roofInsulationThickness: jsonb("roof_insulation_thickness"),
|
||||
|
||||
roofConstructionType: text("roof_construction_type"),
|
||||
curtainWallAge: text("curtain_wall_age"),
|
||||
|
||||
// Room in roof (inlined)
|
||||
roomInRoofFloorArea: real("room_in_roof_floor_area"),
|
||||
|
|
@ -737,23 +762,23 @@ export const epcWindow = pgTable(
|
|||
.notNull()
|
||||
.references(() => epcProperty.id),
|
||||
|
||||
glazingGap: text("glazing_gap").notNull(),
|
||||
orientation: text("orientation").notNull(),
|
||||
windowType: text("window_type").notNull(),
|
||||
glazingType: text("glazing_type").notNull(),
|
||||
glazingGap: jsonb("glazing_gap").notNull(),
|
||||
orientation: jsonb("orientation").notNull(),
|
||||
windowType: jsonb("window_type").notNull(),
|
||||
glazingType: jsonb("glazing_type").notNull(),
|
||||
windowWidth: real("window_width").notNull(), // add unit?
|
||||
windowHeight: real("window_height").notNull(), // add unit?
|
||||
draughtProofed: boolean("draught_proofed").notNull(),
|
||||
windowLocation: text("window_location").notNull(),
|
||||
windowWallType: text("window_wall_type").notNull(),
|
||||
permanentShuttersPresent: boolean("permanent_shutters_present").notNull(),
|
||||
draughtProofed: jsonb("draught_proofed").notNull(),
|
||||
windowLocation: jsonb("window_location").notNull(),
|
||||
windowWallType: jsonb("window_wall_type").notNull(),
|
||||
permanentShuttersPresent: jsonb("permanent_shutters_present").notNull(),
|
||||
frameMaterial: text("frame_material"),
|
||||
frameFactor: real("frame_factor"),
|
||||
permanentShuttersInsulated: text("permanent_shutters_insulated"),
|
||||
|
||||
// Transmission details (inlined)
|
||||
transmissionUValue: real("transmission_u_value"),
|
||||
transmissionDataSource: text("transmission_data_source"),
|
||||
transmissionDataSource: jsonb("transmission_data_source"),
|
||||
transmissionSolarTransmittance: real("transmission_solar_transmittance"),
|
||||
},
|
||||
);
|
||||
|
|
@ -773,4 +798,86 @@ export const epcEnergyElement = pgTable(
|
|||
energyEfficiencyRating: integer("energy_efficiency_rating").notNull(),
|
||||
environmentalEfficiencyRating: integer("environmental_efficiency_rating").notNull(),
|
||||
},
|
||||
);
|
||||
|
||||
// ─── epc_renewable_heat_incentive ─────────────────────────────────────────────
|
||||
|
||||
export const epcRenewableHeatIncentive = pgTable(
|
||||
"epc_renewable_heat_incentive",
|
||||
{
|
||||
id: bigserial("id", { mode: "bigint" }).primaryKey(),
|
||||
epcPropertyId: bigint("epc_property_id", { mode: "bigint" })
|
||||
.notNull()
|
||||
.unique()
|
||||
.references(() => epcProperty.id),
|
||||
spaceHeatingKwh: real("space_heating_kwh").notNull(),
|
||||
waterHeatingKwh: real("water_heating_kwh").notNull(),
|
||||
impactOfLoftInsulationKwh: real("impact_of_loft_insulation_kwh"),
|
||||
impactOfCavityInsulationKwh: real("impact_of_cavity_insulation_kwh"),
|
||||
impactOfSolidWallInsulationKwh: real("impact_of_solid_wall_insulation_kwh"),
|
||||
},
|
||||
);
|
||||
|
||||
// ─── property_baseline_performance ────────────────────────────────────────────
|
||||
|
||||
export const rebaselineReasonEnum = pgEnum("rebaseline_reason", [
|
||||
"none",
|
||||
"pre_sap10",
|
||||
"physical_state_changed",
|
||||
"both",
|
||||
]);
|
||||
|
||||
export const propertyBaselinePerformance = pgTable(
|
||||
"property_baseline_performance",
|
||||
{
|
||||
id: bigserial("id", { mode: "bigint" }).primaryKey(),
|
||||
propertyId: bigint("property_id", { mode: "bigint" })
|
||||
.notNull()
|
||||
.unique()
|
||||
.references(() => property.id),
|
||||
|
||||
// Lodged performance (from gov EPC register)
|
||||
lodgedSapScore: integer("lodged_sap_score").notNull(),
|
||||
lodgedEpcBand: epcEnum("lodged_epc_band").notNull(),
|
||||
lodgedCo2EmissionsTPerYr: real("lodged_co2_emissions_t_per_yr").notNull(),
|
||||
lodgedPrimaryEnergyIntensityKwhPerM2Yr: integer(
|
||||
"lodged_primary_energy_intensity_kwh_per_m2_yr",
|
||||
).notNull(),
|
||||
|
||||
// Effective performance (what modelling scored against)
|
||||
effectiveSapScore: integer("effective_sap_score").notNull(),
|
||||
effectiveEpcBand: epcEnum("effective_epc_band").notNull(),
|
||||
effectiveCo2EmissionsTPerYr: real(
|
||||
"effective_co2_emissions_t_per_yr",
|
||||
).notNull(),
|
||||
effectivePrimaryEnergyIntensityKwhPerM2Yr: integer(
|
||||
"effective_primary_energy_intensity_kwh_per_m2_yr",
|
||||
).notNull(),
|
||||
|
||||
rebaselineReason: rebaselineReasonEnum("rebaseline_reason").notNull(),
|
||||
|
||||
// Interim energy demand (from EPC RHI data; superseded by bill block below once populated)
|
||||
spaceHeatingKwh: real("space_heating_kwh").notNull(),
|
||||
waterHeatingKwh: real("water_heating_kwh").notNull(),
|
||||
|
||||
// Bill block — nullable until BillDerivation wiring lands
|
||||
fuelRatesPeriod: text("fuel_rates_period"),
|
||||
heatingKwh: real("heating_kwh"),
|
||||
heatingCostGbp: real("heating_cost_gbp"),
|
||||
hotWaterKwh: real("hot_water_kwh"),
|
||||
hotWaterCostGbp: real("hot_water_cost_gbp"),
|
||||
lightingKwh: real("lighting_kwh"),
|
||||
lightingCostGbp: real("lighting_cost_gbp"),
|
||||
appliancesKwh: real("appliances_kwh"),
|
||||
appliancesCostGbp: real("appliances_cost_gbp"),
|
||||
cookingKwh: real("cooking_kwh"),
|
||||
cookingCostGbp: real("cooking_cost_gbp"),
|
||||
pumpsFansKwh: real("pumps_fans_kwh"),
|
||||
pumpsFansCostGbp: real("pumps_fans_cost_gbp"),
|
||||
coolingKwh: real("cooling_kwh"),
|
||||
coolingCostGbp: real("cooling_cost_gbp"),
|
||||
standingChargesGbp: real("standing_charges_gbp"),
|
||||
segCreditGbp: real("seg_credit_gbp"),
|
||||
totalAnnualBillGbp: real("total_annual_bill_gbp"),
|
||||
},
|
||||
);
|
||||
|
|
@ -54,7 +54,9 @@ export const fileType = pgEnum("file_type", [
|
|||
"improvement_option_evaluation",
|
||||
"medium_term_improvement_plan",
|
||||
// Design
|
||||
"retrofit_design_doc"
|
||||
"retrofit_design_doc",
|
||||
// Other
|
||||
"other"
|
||||
]);
|
||||
|
||||
export const fileSource = pgEnum("file_source", [
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue