import os.path from pathlib import Path from typing import List, Tuple from ee import EeException from ee.db import ObjDb from ee.part import PartDb, load_db, save_db from ee.project import Project, report from ee.xml import types, bom_file_utils __all__ = ["create_order"] class OrderPart(object): def __init__(self, part: types.Part): self.part = part self.ref = next((ref.referenceProp for ref in bom_file_utils.schematic_references(part)), None) self.available_from: List[Tuple[str, types.Part]] = [] self.selected_supplier_and_part = None rl = part.referencesProp = part.referencesProp or types.ReferencesList() # type: types.ReferencesList rl.schematic_referenceProp = rl.schematic_referenceProp or [] rl.part_numberProp = rl.part_numberProp or [] rl.supplier_part_numberProp = rl.supplier_part_numberProp or [] def make_report(out_file, order_parts: ObjDb[OrderPart], has_unresolved_parts): parts_by_supplier = {} for supplier, order_parts in order_parts.index("selected_part").items(): parts = {} for op in order_parts: p = op.selected_supplier_and_part[1] parts[p.uriProp] = p parts_by_supplier[supplier] = parts.values() kwargs = { "order_parts": order_parts, "parts_by_supplier": parts_by_supplier, "has_unresolved_parts": has_unresolved_parts, } report.save_report("ee.order", "order.rst.j2", out_file, **kwargs) def create_order(project: Project, schematic_path: Path, out_path: Path, part_db_dirs: List[Path], fail_on_missing_parts: bool): sch_db = load_db(schematic_path) dbs = [(path.parent.name, load_db(path)) for path in part_db_dirs] def supplier_index(op: OrderPart): return [spn.supplierProp for spn in bom_file_utils.supplier_part_numbers(op.part)] def selected_part_index(op: OrderPart): return [op.selected_supplier_and_part[0]] if op.selected_supplier_and_part else None def available_from_index(op: OrderPart): return set([s for s, s_part in op.available_from]) def supplier_part_index(op: OrderPart): return set([s_part.uriProp for s, s_part in op.available_from]) def pn_index(op: OrderPart): return [pn.value for pn in bom_file_utils.part_numbers(op.part)] order_parts: ObjDb[OrderPart] = ObjDb[OrderPart]() for sch_part in sch_db.iterparts(): order_parts.add(OrderPart(sch_part)) for order_part in order_parts: sch_part_numbers = order_part.part.referencesProp.part_number sch_supplier_part_numbers: List[types.SupplierPartNumber] = order_part.part.referencesProp.supplier_part_number for supplier, db in dbs: for supplier_part in db.iterparts(sort=True): for sch_pn in sch_part_numbers: for pn in bom_file_utils.part_numbers(supplier_part): if sch_pn.valueProp == pn.valueProp: order_part.available_from.append((supplier, supplier_part)) for sch_spn in sch_supplier_part_numbers: for spn in bom_file_utils.supplier_part_numbers(supplier_part): if sch_spn.valueProp == spn.valueProp and sch_spn.supplierProp == spn.supplierProp: order_part.available_from.append((supplier, supplier_part)) has_unresolved_parts = False for order_part in order_parts: if len(order_part.available_from) == 0: has_unresolved_parts = True elif len(order_part.available_from) == 1: order_part.selected_supplier_and_part = order_part.available_from[0] else: raise EeException("unimplemented: part available from multiple suppliers") if has_unresolved_parts and fail_on_missing_parts: raise EeException("The order has parts that can't be found from any supplier") order_parts.add_index("selected_part", selected_part_index) out_file = project.report_dir / (os.path.splitext(out_path.name)[0] + ".rst") make_report(out_file, order_parts, has_unresolved_parts) out_parts = PartDb() for order_part in order_parts: if not order_part.selected_supplier_and_part: continue supplier, supplier_part = order_part.selected_supplier_and_part references = types.ReferencesList(schematic_reference=order_part.part.referencesProp.schematic_reference) part = types.Part(uri=supplier_part.uri, references=references) out_parts.add_entry(part, True) save_db(out_path, out_parts)