import os import time from epc_api.client import EpcClient from utils.logger import setup_logger from typing import List logger = setup_logger() class SearchEpc: """ Given address information about a home, this class is responsible for retrieving the EPC data associated to the property. For a home, we might have address lines 1, 2, 3 and 4, as well as a postcode. Often, simply searching the EPC database with address line 1 and postcode will be enough to find the property, but there are some cases where this is not true and we might need to utilise other combinations about the home to find the property """ MAX_RETRIES = 5 SUCCESS = { "status": 200, "message": "success", "error": None } NODATA = { "status": 201, "message": "No data", "error": None } def __init__( self, address1: str, postcode: str, address2: str = None, address3: str = None, address4: str = None, max_retries: int = None ): """ Address lines 1 and postcode are mandatory fields. The other address lines are optional but can be used to find the epc for the home, if address1 and postcode are insufficient :param address1: string, propery's address line 1 :param postcode: string, propery's postcode :param address2: string, optional, propery's address line 2 :param address3: string, optional, propery's address line 3 :param address4: string, optional, propery's address line 4 """ self.address1 = address1 self.postcode = postcode self.address2 = address2 self.address3 = address3 self.address4 = address4 self.max_retries = max_retries if max_retries is not None else self.MAX_RETRIES self.client = EpcClient(auth_token=os.getenv("EPC_AUTH_TOKEN")) self.data = None def search(self): # Get the EPC data with retries response = {} for retry in range(self.max_retries): try: response = self.client.domestic.search( params={"address": self.address1, "postcode": self.postcode} ) if response: self.data = response return self.SUCCESS if retry > 0: print("Failed previous attempt but retry successful") # If we got nothing, final try if not response: raise NotImplementedError("Implement me") # response = client.domestic.search( # params={"address": " ".join([home["Dwelling num"], home["Street"]]), # "postcode": home["Postcode"]} # ) # TODO: Eventually, if we have nothing, we should exit with a 201 or 202, saying that # there is not data for this property return { "status": 200, "message": "success", "error": None } except Exception as e: if retry < self.max_retries - 1: # If not the last retry, wait for 3 seconds before retrying time.sleep(3) else: # If it's the last retry, we continue return { "status": 500, "message": "Could not retrieve EPC data", "error": str(e) } def retrieve(self): """ Given a successful search, this method will format the data and return it :return: """ if self.data is None: raise ValueError("data is missing, run search first") rows = self.data["rows"] # We perform some checks on the rows # Firstly, we should only have 1 urpn so if we have multiple, we'll need to filter down the # property further uprns = {r["uprn"] for r in rows} if len(uprns) != 1: raise NotImplementedError("More than one unique UPRN, need to handle this case") # We now check for a full sap epc: full_sap_epc = [r for r in rows if r["transaction-type"] == "new dwelling"] full_sap_epc = full_sap_epc[0] if full_sap_epc else {} # Finally, we identify the newest epc and the rest, and then return newest_epc, older_epcs = self.filter_newest_epc(list_of_epcs=rows) return newest_epc, older_epcs, full_sap_epc @staticmethod def filter_newest_epc(list_of_epcs: List): newest_response = [ r for r in list_of_epcs if r["lodgement-datetime"] == max([x["lodgement-datetime"] for x in list_of_epcs]) ] if not newest_response: return {}, [] if len(newest_response) != 1: raise Exception("More than one result found for this address - investigate me") older_epcs = [epc for epc in list_of_epcs if epc["lmk-key"] != newest_response[0]["lmk-key"]] return newest_response[0], older_epcs