from sqlalchemy.orm import sessionmaker from backend.app.db.connection import db_engine from backend.app.db.models.portfolio import PropertyModel, PropertyDetailsEpcModel from backend.app.db.models.recommendations import Recommendation, Plan, PlanRecommendations class Outputs: FORMATS = ["mds"] def __init__(self, format, portfolio_id): """ This class handles the creation of standard outputs for the backend. For example, creation of an excel output, to be used for the MDS data sheet, required by E.ON :param format: The format of the output, e.g. mds :param portfolio_id: The id of the portfolio for which the output is being created """ if format not in self.FORMATS: raise ValueError("Invalid format, should be one of {}".format(self.FORMATS)) self.format = format self.portfolio_id = portfolio_id # Connect to the database self.session = sessionmaker(bind=db_engine)() def get_properties_from_db(self): # Get properties and their details for a specific portfolio properties_query = self.session.query( PropertyModel, PropertyDetailsEpcModel ).join( PropertyDetailsEpcModel, PropertyModel.id == PropertyDetailsEpcModel.property_id ).filter( PropertyModel.portfolio_id == self.portfolio_id # Filter by portfolio ID ).all() # Transform properties data to include all fields dynamically properties_data = [ {**{col.name: getattr(prop.PropertyModel, col.name) for col in PropertyModel.__table__.columns}, **{col.name: getattr(prop.PropertyDetailsEpcModel, col.name) for col in PropertyDetailsEpcModel.__table__.columns}} for prop in properties_query ] return properties_data def get_plans_from_db(self): plans_query = self.session.query(Plan).all() # Transform plans data to include all fields dynamically plans_data = [ {col.name: getattr(plan, col.name) for col in Plan.__table__.columns} for plan in plans_query ] return plans_data def get_recommendations_from_db(self, plan_ids): # Get recommendations through PlanRecommendations for those plans and that are default recommendations_query = self.session.query( Recommendation, Plan.scenario_id ).join( PlanRecommendations, Recommendation.id == PlanRecommendations.recommendation_id ).join( Plan, Plan.id == PlanRecommendations.plan_id # Join with Plan to access scenario_id ).filter( PlanRecommendations.plan_id.in_(plan_ids), Recommendation.default == True # Filtering for default recommendations ).all() # Transform recommendations data to include all fields dynamically and include scenario_id recommendations_data = [ { **{ col.name: getattr(rec.Recommendation, col.name) if hasattr(rec, 'Recommendation') else getattr(rec, col.name) for col in Recommendation.__table__.columns }, "Scenario ID": rec.scenario_id } for rec in recommendations_query ] return recommendations_data def export_mds(self): """ This function will export the data in the MDS format Core data required: - Property address - Property postcode - uprn - recommended measures - pre-EPC - pre-SAP - pre Heat Demand - Property Type - Built form - Wall type - Tenure - Fuel type - Estimated bill - Recommended measures - Post EPC - Post heat demand - Bill savings - Kwh savings """ self.session.begin() properties_data = self.get_properties_from_db() plans_data = self.get_plans_from_db() plan_ids = [plan['id'] for plan in plans_data] recommendations_data = self.get_recommendations_from_db(plan_ids) self.session.close() def export(self): """ This function will export the data in the required format """ if self.format == "mds": self.export_mds()