diff --git a/src/wireviz/wv_bom.py b/src/wireviz/wv_bom.py index b70a93ac..47aebc10 100644 --- a/src/wireviz/wv_bom.py +++ b/src/wireviz/wv_bom.py @@ -9,13 +9,18 @@ from wireviz.wv_gv_html import html_line_breaks from wireviz.wv_helper import clean_whitespace +BOM_COLUMNS_ALWAYS = ('id', 'description', 'qty', 'unit', 'designators') +BOM_COLUMNS_OPTIONAL = ('pn', 'manufacturer', 'mpn') +BOM_COLUMNS_IN_KEY = ('description', 'unit') + BOM_COLUMNS_OPTIONAL + BOMKey = Tuple[str, ...] -BOMColumn = str # = Literal['id', 'description', 'qty', 'unit', 'designators', 'pn', 'manufacturer', 'mpn'] +BOMColumn = str # = Literal[BOM_COLUMNS_ALWAYS, BOM_COLUMNS_OPTIONAL] BOMEntry = Dict[BOMColumn, Union[str, int, float, List[str], None]] def optional_fields(part: Union[Connector, Cable, AdditionalComponent]) -> BOMEntry: """Return part field values for the optional BOM columns as a dict.""" - return {'pn': part.pn, 'manufacturer': part.manufacturer, 'mpn': part.mpn} + part = asdict(part) + return {field: part.get(field) for field in BOM_COLUMNS_OPTIONAL} def get_additional_component_table(harness: "Harness", component: Union[Connector, Cable]) -> List[str]: """Return a list of diagram node table row strings with additional components.""" @@ -50,7 +55,7 @@ def get_additional_component_bom(component: Union[Connector, Cable]) -> List[BOM def bom_entry_key(entry: BOMEntry) -> BOMKey: """Return a tuple of string values from the dict that must be equal to join BOM entries.""" if 'key' not in entry: - entry['key'] = tuple(clean_whitespace(make_str(entry.get(k))) for k in ('description', 'unit', 'manufacturer', 'mpn', 'pn')) + entry['key'] = tuple(clean_whitespace(make_str(entry.get(c))) for c in BOM_COLUMNS_IN_KEY) return entry['key'] def generate_bom(harness: "Harness") -> List[BOMEntry]: @@ -130,8 +135,8 @@ def get_bom_index(bom: List[BOMEntry], target: BOMKey) -> int: def bom_list(bom: List[BOMEntry]) -> List[List[str]]: """Return list of BOM rows as lists of column strings with headings in top row.""" - keys = ['id', 'description', 'qty', 'unit', 'designators'] # these BOM columns will always be included - for fieldname in ['pn', 'manufacturer', 'mpn']: # these optional BOM columns will only be included if at least one BOM entry actually uses them + keys = list(BOM_COLUMNS_ALWAYS) # Always include this fixed set of BOM columns. + for fieldname in BOM_COLUMNS_OPTIONAL: # Include only those optional BOM columns that are in use. if any(entry.get(fieldname) for entry in bom): keys.append(fieldname) # list of staic bom header names, headers not specified here are generated by capitilising the internal name