multiple remote assessments

This commit is contained in:
Khalim Conn-Kowlessar 2025-09-18 16:23:18 +01:00
parent 78b4aeef63
commit 335164eaf1
7 changed files with 154 additions and 9 deletions

View file

@ -1783,9 +1783,16 @@ class AssetList:
)
)
not_a_flat = (
self.standardised_asset_list[self.STANDARD_PROPERTY_TYPE] != "flat"
)
# Determine if the client gave us property type in the first place
if all(self.standardised_asset_list[self.STANDARD_PROPERTY_TYPE] == "unknown"):
# Use EPC
not_a_flat = (
self.standardised_asset_list[self.EPC_API_DATA_NAMES["property-type"]] != "Flat"
)
else:
not_a_flat = (
self.standardised_asset_list[self.STANDARD_PROPERTY_TYPE] != "flat"
)
solar_roof_meets_criteria = (
self.standardised_asset_list["solar_epc_roof_insulated"] |
@ -3452,7 +3459,13 @@ class AssetList:
raise ValueError("No installer column found in master data")
measure_mix_col = "MEASURE COMBO"
town_colname = "TOWN" if "TOWN" in master_data.columns else 'Town/Area'
if "TOWN" in master_data.columns:
town_colname = "TOWN"
elif 'Town/Area' in master_data.columns:
town_colname = 'Town/Area'
else:
town_colname = "Town/City"
logger.info("Matching master data to asset list")
matched = []

View file

@ -59,6 +59,74 @@ def app():
Property UPRN
"""
# CDS - Sept 2025
data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/CDS/September 2025 Programme"
data_filename = "Founder Estates CDS.xlsx"
sheet_name = "Combined List"
postcode_column = 'Postcode'
address1_column = None # Is only patchily populated so we create it
address1_method = 'house_number_extraction'
fulladdress_column = "Address"
address_cols_to_concat = []
missing_postcodes_method = None
landlord_year_built = None
landlord_os_uprn = None
landlord_property_type = "Property Type"
landlord_built_form = None
landlord_wall_construction = None
landlord_roof_construction = None
landlord_heating_system = "Heating Type"
landlord_existing_pv = None
landlord_property_id = "(Do Not Modify) Property"
landlord_sap = None
outcomes_filename = None
outcomes_sheetname = None
outcomes_postcode = None
outcomes_houseno = None
outcomes_id = None
outcomes_address = None
master_filepaths = []
master_id_colnames = []
master_to_asset_list_filepath = None
phase = False
ecosurv_landlords = None
asset_list_header = 0
landlord_block_reference = None
# Project from Nick
data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/sfr/Sep2025 Project"
data_filename = "AL Test.xlsx"
sheet_name = "Sheet1"
postcode_column = 'postcode'
address1_column = None
address1_method = 'house_number_extraction'
fulladdress_column = "address"
address_cols_to_concat = []
missing_postcodes_method = None
landlord_year_built = None
landlord_os_uprn = None
landlord_property_type = None
landlord_built_form = None
landlord_wall_construction = None
landlord_roof_construction = None
landlord_heating_system = None
landlord_existing_pv = None
landlord_property_id = "row_id"
landlord_sap = None
outcomes_filename = None
outcomes_sheetname = None
outcomes_postcode = None
outcomes_houseno = None
outcomes_id = None
outcomes_address = None
master_filepaths = []
master_id_colnames = []
master_to_asset_list_filepath = None
phase = False
ecosurv_landlords = None
asset_list_header = 0
landlord_block_reference = None
# Lambeth
data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Lambeth"
data_filename = "LAMBETH Asset List ( Incomplete).xlsx"
@ -1307,6 +1375,26 @@ def app():
filename = os.path.join(data_folder, ".".join(data_filename.split(".")[:-1])) + " - Standardised.xlsx"
# Store the data in two tabs. One for the asset list with the EPC data and the second with the flat data
# Determine inspections priority
# solar_jobs = asset_list.standardised_asset_list[~pd.isnull(asset_list.standardised_asset_list["solar_reason"])][
# "domna_postcode"].unique()
# asset_list.standardised_asset_list["in_solar_area"] = asset_list.standardised_asset_list["domna_postcode"].isin(
# solar_jobs
# )
# # Same for cav
# cavity_jobs = asset_list.standardised_asset_list[
# ~pd.isnull(asset_list.standardised_asset_list["cavity_reason"])
# ]["domna_postcode"].unique()
# asset_list.standardised_asset_list["in_cavity_area"] = asset_list.standardised_asset_list["domna_postcode"].isin(
# cavity_jobs
# )
# # We prioritise properties that are in solar areas and cavity areas
# import numpy as np
# asset_list.standardised_asset_list["inspection_priority"] = np.where(
# asset_list.standardised_asset_list["in_solar_area"] | asset_list.standardised_asset_list["in_cavity_area"],
# 1, 2
# )
with pd.ExcelWriter(filename) as writer:
asset_list.standardised_asset_list.to_excel(writer, sheet_name="Standardised Asset List", index=False)
if asset_list.block_analysis_df is not None:

View file

@ -438,6 +438,6 @@ BUILT_FORM_MAPPINGS = {
'Maisonette - Mid Terrace': 'mid-terrace',
'Chalet - Wheelchair': 'unknown',
'Studio Flat': 'unknown',
'Bungalow - Attached': 'semi-detached'
'Bungalow - Attached': 'semi-detached',
'ND': 'unknown'
}

View file

@ -473,5 +473,10 @@ HEATING_MAPPINGS = {
'Boiler and radiators, oil': 'oil boiler',
'Boiler and radiators, electric': 'electric boiler',
'No system present: electric heaters assumed': 'electric radiators',
'Boiler and radiators, anthracite': 'solid fuel'
'Boiler and radiators, anthracite': 'solid fuel',
'Heat networks Heat networks (mains gas)': 'communal heating',
'ND Oil': 'oil fuel',
'Boiler Biofuel': 'boiler - other fuel'
}

View file

@ -246,4 +246,34 @@ ROOF_CONSTRUCTION_MAPPINGS = {
'Pitched, 150 mm loft insulation': 'pitched insulated',
'Flat, limited insulation (assumed)': 'flat uninsulated',
'Pitched (no access to loft) 350mm': 'pitched insulated',
'Pitched (no access to loft) 200mm': 'pitched insulated',
'Pitched (access to loft) 200mm': 'pitched insulated',
'Pitched (no access to loft) 250mm': 'pitched insulated',
'Pitched (access to loft) 100mm': 'pitched insulated',
'Another dwelling above ND (inferred)': 'another dwelling above',
'Pitched (no access to loft) N/A': 'pitched no access to loft',
'Pitched (no access to loft) ND (inferred)': 'pitched no access to loft',
'Pitched (no access to loft) 150mm': 'pitched insulated',
'Pitched (access to loft) 400mm+': 'pitched insulated',
'Pitched (no access to loft) 300mm': 'pitched insulated',
'Pitched (access to loft) <25mm': 'pitched less than 100mm insulation',
'Pitched (access to loft) None': 'pitched less than 100mm insulation',
'Pitched (access to loft) 300mm': 'pitched insulated',
'Pitched (access to loft) 50mm': 'pitched less than 100mm insulation',
'Pitched (access to loft) 270mm': 'pitched insulated',
'Pitched (access to loft) Non-joist': 'pitched access to loft',
'Pitched (access to loft) 250mm': 'pitched insulated',
'Another dwelling above N/A': 'another dwelling above',
'Pitched (access to loft) 150mm': 'pitched insulated',
'Pitched (access to loft) ND (inferred)': 'pitched access to loft',
'Pitched (access to loft) 350mm': 'pitched insulated',
'Pitched (access to loft) NR': 'pitched unknown insulation',
'Pitched (access to loft) 75mm': 'pitched less than 100mm insulation',
'Pitched (access to loft) N/A': 'pitched access to loft',
'ND (inferred) 250mm': 'unknown insulated',
'Pitched (vaulted ceiling) Non-joist': 'pitched unknown insulation',
'ND (inferred) ND (inferred)': 'unknown',
'Flat Non-joist': 'flat insulated',
'Same dwelling above N/A': 'another dwelling above'
}

View file

@ -342,5 +342,15 @@ WALL_CONSTRUCTION_MAPPINGS = {
'Solid brick, as built, partial insulation (assumed)': 'insulated solid brick',
'Sandstone, as built, no insulation (assumed)': 'uninsulated sandstone or limestone',
'System built, as built, partial insulation (assumed)': 'system built unknown insulation',
'Timber frame, with external insulation': 'insulated timber frame'
'Timber frame, with external insulation': 'insulated timber frame',
'Cob As-built': 'cob',
'System built Unknown insulation': 'system built unknown insulation',
'Solid brick Unknown insulation': 'solid brick unknown insulation',
'Timber frame Internal': 'insulated timber frame',
'System built External': 'insulated system built',
'Stone As-built': 'uninsulated sandstone or limestone',
'System built As-built': "uninsulated system built",
'System built Internal': 'insulated system built',
}

View file

@ -332,7 +332,6 @@ class GoogleSolarApi:
)
if solar_product is None:
logger.info("No suitable solar product found for the configuration with %d panels.", total_panels)
continue
total_cost = Costs.solar_pv(