diff --git a/bpeng/pna/discrete_bar_graph.py b/bpeng/pna/discrete_bar_graph.py index 3044e44a86408ef0ac582e4c5f15dd77b3aa489e..5264a401bebf2d2c1a2a687a8f10f27e57efae33 100644 --- a/bpeng/pna/discrete_bar_graph.py +++ b/bpeng/pna/discrete_bar_graph.py @@ -1,6 +1,6 @@ from pptx.dml.color import RGBColor -def create_graph_factory(name_in_ppt, num_colored, total=5, horizontal=True, blank_color=(255,255,255), fill_color=(26,174,85)): +def create_graph_factory(name_in_ppt, num_colored, total=5, horizontal=True): """ Search for a table containing a cell at (0,0) with text string name_in_ppt, and create a "graph" by coloring in a dynamic number of cells. @@ -23,9 +23,9 @@ def create_graph_factory(name_in_ppt, num_colored, total=5, horizontal=True, bla i = 0 for cell in row.cells: cell.text = '' - #cell.fill.solid() - cell.fill.fore_color.rgb = RGBColor(fill_color[0], fill_color[1], fill_color[2]) + cell.fill.solid() + cell.fill.fore_color.rgb = RGBColor(0xE7, 0x8C, 0x64) i += 1 if i > num_colored: - cell.fill.fore_color.rgb = RGBColor(blank_color[0], blank_color[1], blank_color[2]) + cell.fill.fore_color.rgb = RGBColor(0xFF, 0xFF, 0xFF) return graph_factory diff --git a/bpeng/pna/pna.py b/bpeng/pna/pna.py index c4742113d88200a2be86f5f1f89597210372f6d2..190b8eec7b574ef406d08536a82c1a17a8f6ee72 100644 --- a/bpeng/pna/pna.py +++ b/bpeng/pna/pna.py @@ -11,8 +11,7 @@ from .field_format import * from .discrete_bar_graph import create_graph_factory -def generate_ashp_pna(template_path, building_info, hvac, cost_estimates, scores, contact_info=None, - external=False): +def generate_ashp_pna(template_path, building_info, hvac, scores): """ Generate an ASHP PNA from dicts @@ -42,50 +41,68 @@ def generate_ashp_pna(template_path, building_info, hvac, cost_estimates, scores addr_sub = Substitution( 'ADDRESS', addr, - font_size=24, - align=PP_ALIGN.CENTER, - bold=True - ) - client_sub = Substitution( - 'CLIENT', - building_info['owner'], - font_size=18 + font_size=18, + font = 'Avenir', + align=PP_ALIGN.LEFT, + bold=False, + color=(173,216,216), ) + + # CLIENT NAME + # WE ARE NOT USING THIS FOR THIS VERSION OF PNA REPORT GENERATION + # client_sub = Substitution( + # 'CLIENT', + # building_info['owner'], + # font_size=18 + # ) + date_sub = Substitution( 'DATE', format_date(date.today()), - #formatter=format_date, - font_size=18 + font_size=9, + color=(173,216,216), ) + title_slide = pna_generator.templateSlideNumber(0) title_slide.add_substitutions([ date_sub, - client_sub, + # client_sub, addr_sub ]) # Fill in HVAC Fields addr_sub_2 = Substitution( 'ADDRESS', - addr + addr, + color=(255,255,255), + font_size=12, + font = 'Avenir', ) heating_system_sub = Substitution( 'HEATING_SYSTEM', - hvac['heating_system'] + hvac['heating_system'], + font_size=11, + font = 'Avenir', ) heating_system_age_sub = Substitution( 'HEATING_SYSTEM_AGE', - hvac['heating_age'] + hvac['heating_age'], + font_size=11, + font = 'Avenir', ) fuel_sub = Substitution( 'HEATING_FUEL_TYPE', - hvac['heating_fuel'] + hvac['heating_fuel'], + font_size=11, + font = 'Avenir', ) dhw_sub = Substitution( 'SAME_DHW_SYSTEM', - hvac['dhw_heat_same'] + hvac['dhw_heat_same'], + font_size=11, + font = 'Avenir', ) - hvac_slide = pna_generator.templateSlideNumber(3) + hvac_slide = pna_generator.templateSlideNumber(4) hvac_slide.add_substitutions([ addr_sub_2, heating_system_sub, @@ -100,11 +117,21 @@ def generate_ashp_pna(template_path, building_info, hvac, cost_estimates, scores new_crit_name = scores[i][0] + '*' # Put an asterisk/footnote on utility scores, for legal reasons scores[i] = (new_crit_name, scores[i][1]) - addr_sub_2a = Substitution('ADDRESS', addr) - criteria_name_sub1 = Substitution('CRITERIA_NAME_0', scores[0][0], font_size=18) - criteria_name_sub2 = Substitution('CRITERIA_NAME_1', scores[1][0], font_size=18) - criteria_name_sub3 = Substitution('CRITERIA_NAME_2', scores[2][0], font_size=18) - criteria_name_sub4 = Substitution('CRITERIA_NAME_3', scores[3][0], font_size=18) + addrQn = "Is " + addr +" a Good Candidate for an ASHP Project?" + addr_sub_2a = Substitution( + 'ADDRESS_QUESTION', + addrQn, + font_size=18, + font = 'Avenir', + color=(14,46,65) + ) + + # ADDING CRITERIAS + # WE ARE NOT USING THIS FOR THIS VERSION OF PNA REPORT GENERATION + # criteria_name_sub1 = Substitution('CRITERIA_NAME_0', scores[0][0], font_size=13) + # criteria_name_sub2 = Substitution('CRITERIA_NAME_1', scores[1][0], font_size=13) + # criteria_name_sub3 = Substitution('CRITERIA_NAME_2', scores[2][0], font_size=13) + # criteria_name_sub4 = Substitution('CRITERIA_NAME_3', scores[3][0], font_size=13) num_list = calculate_bar_color_number(scores) @@ -113,76 +140,77 @@ def generate_ashp_pna(template_path, building_info, hvac, cost_estimates, scores graph_factory3 = create_graph_factory('CSCORE2', num_list[2], total=5) graph_factory4 = create_graph_factory('CSCORE3', num_list[3], total=5) - graph_slide = pna_generator.templateSlideNumber(4) + graph_slide = pna_generator.templateSlideNumber(5) - graph_slide.add_substitutions([addr_sub_2a, criteria_name_sub1, criteria_name_sub2, criteria_name_sub3, criteria_name_sub4]) + # graph_slide.add_substitutions([addr_sub_2a, criteria_name_sub1, criteria_name_sub2, criteria_name_sub3, criteria_name_sub4]) + graph_slide.add_substitutions([addr_sub_2a]) graph_slide.add_function(graph_factory1) graph_slide.add_function(graph_factory2) graph_slide.add_function(graph_factory3) graph_slide.add_function(graph_factory4) # Populate cost estimates slide - cost_slide = pna_generator.templateSlideNumber(5) - addr_sub_3 = Substitution('ADDRESS', addr) - window_sub = Substitution( - 'COST_WINDOWS', - '${:,} - ${:,}'.format(cost_estimates['windows_low'], - cost_estimates['windows_high']), - bold=True, - align=PP_ALIGN.CENTER - ) - ashp_sub = Substitution( - 'COST_ASHP', - '${:,} - ${:,}'.format(cost_estimates['ashp_low'], cost_estimates['ashp_high']), - bold=True, - align=PP_ALIGN.CENTER - ) - cost_slide.add_substitutions([ - addr_sub_3, - window_sub, - ashp_sub - ]) + # WE ARE NOT USING THIS FOR THIS VERSION OF PNA REPORT GENERATION. + # cost_slide = pna_generator.templateSlideNumber(6) + # addr_sub_3 = Substitution('ADDRESS', addr) + # window_sub = Substitution( + # 'COST_WINDOWS', + # '${:,} - ${:,}'.format(cost_estimates['windows_low'], + # cost_estimates['windows_high']), + # bold=True, + # align=PP_ALIGN.CENTER + # ) + # ashp_sub = Substitution( + # 'COST_ASHP', + # '${:,} - ${:,}'.format(cost_estimates['ashp_low'], cost_estimates['ashp_high']), + # bold=True, + # align=PP_ALIGN.CENTER + # ) + # cost_slide.add_substitutions([ + # addr_sub_3, + # window_sub, + # ashp_sub + # ]) # Populate last slide with contact info - name = '\n' + contact_info['name'] - email = contact_info['email'] - phone = contact_info['phone'] - pronoun = 'me' - if external: - pronoun = 'us' - name = ' ' - email = 'BusinessDevelopment@blocpower.io' - phone = '(718) 924-2873' # TODO: don't hardcode these values - - pronoun_sub = Substitution( - 'PRONOUN', - pronoun, - color=(0,0,255), - underline=True - ) - name_sub = Substitution( - 'NAME', - name, - color=(0,0,255) - ) - email_sub = Substitution( - 'BP_EMAIL', - email, - color=(0,0,255) - ) - phone_sub = Substitution( - 'BP_PHONE', - phone, - color=(0,0,255) - ) - final_slide = pna_generator.templateSlideNumber(8) - final_slide.add_substitutions([pronoun_sub, name_sub, email_sub, phone_sub]) - + # name = '\n' + contact_info['name'] + # email = contact_info['email'] + # phone = contact_info['phone'] + # pronoun = 'me' + # if external: + # pronoun = 'us' + # name = ' ' + # email = 'BusinessDevelopment@blocpower.io' + # phone = '(718) 924-2873' # TODO: don't hardcode these values + + # pronoun_sub = Substitution( + # 'PRONOUN', + # pronoun, + # color=(0,0,255), + # underline=True + # ) + # name_sub = Substitution( + # 'NAME', + # name, + # color=(0,0,255) + # ) + # email_sub = Substitution( + # 'BP_EMAIL', + # email, + # color=(0,0,255) + # ) + # phone_sub = Substitution( + # 'BP_PHONE', + # phone, + # color=(0,0,255) + # ) + # final_slide = pna_generator.templateSlideNumber(8) + # final_slide.add_substitutions([pronoun_sub, name_sub, email_sub, phone_sub]) # Save PPT to a temporary file, and pass a reference to BlocLink tmp_dir = '/tmp/bpeng/{}'.format(uuid.uuid4()) escaped_addr = addr.replace(' ', '_') # TODO: replace special characters - save_to = '{}/PNS_{}.pptx'.format(tmp_dir, escaped_addr) + save_to = '{}/PNA_{}.pptx'.format(tmp_dir, escaped_addr) if not os.path.exists(tmp_dir): os.makedirs(tmp_dir) @@ -205,7 +233,7 @@ def calculate_func(building_sq_feet, 'outdoor_electric_connection': 400 } - # Static labor cost + # Static labor cost labor_unit_cost = { 'outdoor': 750, 'indoor': 350, @@ -416,6 +444,6 @@ def calculate_bar_color_number(scores): for num in [12, 18, 22, 26, 31, 36]: if scores[3][1] >= num: - data[3] += 1 - + data[3] += 1 + return data diff --git a/bpeng/pna/score_calculation.py b/bpeng/pna/score_calculation.py index c4266d21b9a8cd58cb07a730635139f92fe707fa..4a43db582177ff74cb0dc50f9db4e3edee6de298 100644 --- a/bpeng/pna/score_calculation.py +++ b/bpeng/pna/score_calculation.py @@ -9,6 +9,7 @@ def calculate_score_weight(weight_list, details_list): index = weight_list[i][0]-1 score_weight[index] += weight_list[i][1] + # WE ARE NOT USING THIS FOR THIS VERSION OF PNA REPORT GENERATION # heating_violations_score = [0, 1, 3, 5] # num = [0, 1, 3, 11] # for i in range(len(num)): diff --git a/bpeng/pna/template.py b/bpeng/pna/template.py index 64c9780f0ceae6810d366b49196f056d886a3cf7..f4fb4e91d0947d6d56b6675a19e73b8a5db7e0f4 100644 --- a/bpeng/pna/template.py +++ b/bpeng/pna/template.py @@ -15,29 +15,29 @@ class TemplateInstantiator(): def __init__(self, presentation_path): self.presentation = Presentation(presentation_path) self.slideInstantiator = [TemplateSlideInstantiator() for slide in self.presentation.slides] - + def templateSlideNumber(self, index): return self.slideInstantiator[index] - + def export(self): i=0 for slide in self.presentation.slides: slide = self.slideInstantiator[i].render(slide) i=i+1 - + return self.presentation class TemplateSlideInstantiator(): def __init__(self): self.substitutions = [] self.extra_functions = [] - + def add_substitutions(self, subs): for sub in subs: self.substitutions.append(sub) - + def add_function(self, fun): - self.extra_functions.append(fun) + self.extra_functions.append(fun) def render(self, slide): for sub in self.substitutions: @@ -45,7 +45,7 @@ class TemplateSlideInstantiator(): for function in self.extra_functions: function(slide) - + return slide class Substitution(): @@ -54,7 +54,7 @@ class Substitution(): into a template. """ def __init__(self, name_in_ppt, value, external_value=None, - font='Trebuchet MS', font_size=16, color=(0,0,0), no_data_color=(255,0,0), formatter=None, + font='Avenir', font_size=21, color=(0,0,0), no_data_color=(255,0,0), formatter=None, bold=False, align=PP_ALIGN.LEFT, underline=False): """ We use 3 underscores to denote a field in the powerpoint template. @@ -90,18 +90,18 @@ class Substitution(): def ___repr___(self): return "[" + self.name_in_ppt + ", " + self.formatter(self.value) + "]" - + def ___str___(self): return self.___repr___() def toString(self): return self.___repr___() - + def render(self, slide): if slide is None: print("slide is None") return - + for shape in slide.shapes: if shape is None: continue @@ -112,27 +112,28 @@ class Substitution(): self.formatter(self.value) ) shape.text = new_text - + for p in shape.text_frame.paragraphs: + p.font.name = self.font p.font.size = Pt(self.font_size) p.font.bold = self.bold p.font.color.rgb = RGBColor(self.color[0], self.color[1], self.color[2]) p.font.underline = self.underline p.alignment = self.alignment - + if shape.has_table: for row in shape.table.rows: for cell in row.cells: if cell.text is not None and cell.text.find(self.name_in_ppt) != -1: cell.text = cell.text.replace( self.name_in_ppt, # underscores from constructor - self.formatter(self.value) + self.formatter(self.value) ) - + for p in cell.text_frame.paragraphs: + p.font.name = self.font p.font.size = Pt(self.font_size) p.font.bold = self.bold p.font.color.rgb = RGBColor(self.color[0], self.color[1], self.color[2]) p.font.underline = self.underline p.alignment = self.alignment - \ No newline at end of file