import csv from enum import Enum from io import StringIO class PanelDataColumn(Enum): Handle = 'HANDLE' Blockname = 'BLOCKNAME' Subarray = 'SUBARRAY' PanelType = 'POS' WindZone = 'WIND' Ballast = 'BAL' LinkTray = 'LT_CALCULATED' CrossTray = 'XTRAY' WindAnchor = 'ANC' SeismicAnchor = 'SEISMIC' Coordinate = 'COORDINATE' Pressure = 'PSF' Id = 'ID' PresentedLinkTray = 'LTRAY' Xcoord = 'XCOORD' Ycoord = 'YCOORD' Rotation = 'ANGLE' FuzzyWindZone = 'FUZZYWINDZONE' class CSVDataColumn(Enum): PresentedAnchors = "ANC" class CsvBuilder(object): def build_cad_output(self, panels): panels.sort(key=lambda x: x.id) output_columns = [ PanelDataColumn.Handle, PanelDataColumn.Blockname, PanelDataColumn.WindZone, PanelDataColumn.PanelType, PanelDataColumn.Subarray, PanelDataColumn.Pressure, PanelDataColumn.Ballast, PanelDataColumn.PresentedLinkTray, PanelDataColumn.CrossTray, CSVDataColumn.PresentedAnchors, PanelDataColumn.Id, PanelDataColumn.Xcoord, PanelDataColumn.Ycoord, PanelDataColumn.Rotation ] use_fuzzy_wind_zone = False for panel in panels: if panel.fuzzy_wind_zone: output_columns.append(PanelDataColumn.FuzzyWindZone) use_fuzzy_wind_zone = True break header_row = [col.value for col in output_columns] matrix = [self.format_panel_for_csv(panel, include_fuzzy_wind_zone=use_fuzzy_wind_zone) for panel in panels] return self.output_csv(header_row, matrix) def build_bom_output(self, rows): headers = ['Part #', 'Description', 'Total'] return self.output_csv(headers, rows) def output_csv(self, headers, rows): output = StringIO() writer = csv.writer(output, dialect='excel-tab', quoting=csv.QUOTE_NONE, quotechar='') writer.writerow(headers) writer.writerows(rows) return output.getvalue() def format_panel_for_csv(self, panel, include_fuzzy_wind_zone=False): row = [ panel.handle or "", panel.blockname or "", self.int_to_wind_zone(panel.wind_zone), panel.panel_type.number() if panel.panel_type else "", panel.subarray, round(panel.pressure, 2) if panel.pressure else "", self.present_value(panel.ballast), self.present_value(panel.presented_link_tray) or '-', self.present_value(panel.cross_tray) or '-', self.present_anchors(panel.wind_anchors, panel.seismic_anchors), panel.id, round(panel.original_coordinate.x, 14), round(panel.original_coordinate.y, 14), round(panel.original_coordinate.rotation, 14) ] if include_fuzzy_wind_zone: row.append(int(panel.fuzzy_wind_zone)) return row def round_two_digits(self, value): return round(value, 2) def zero_to_dash(self, value): return int(value) or '-' def int_to_wind_zone(self, value): if value is None: return "" return ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"][value] def present_value(self, value, default=''): if value is None: return default return int(value) def present_anchors(self, wind, seismic): if not wind and not seismic: return '-' wind_string = str(int(wind)) if wind != 0 else '' return wind_string + 'S' * int(seismic)