diff options
Diffstat (limited to 'src/ee/order')
-rw-r--r-- | src/ee/order/__init__.py | 119 | ||||
-rw-r--r-- | src/ee/order/templates/order.rst.j2 | 60 |
2 files changed, 117 insertions, 62 deletions
diff --git a/src/ee/order/__init__.py b/src/ee/order/__init__.py index 1652f24..a384cb7 100644 --- a/src/ee/order/__init__.py +++ b/src/ee/order/__init__.py @@ -1,9 +1,9 @@ -from functools import total_ordering -from itertools import groupby +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 @@ -11,96 +11,105 @@ from ee.xml import types, bom_file_utils __all__ = ["create_order"] -@total_ordering -class PartInfo(object): +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.pn = next((p.valueProp for p in bom_file_utils.part_numbers(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 __lt__(self, other: "PartInfo"): - return self.ref == other.ref + +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): - messages = [] - sch_db = load_db(schematic_path) dbs = [(path.parent.name, load_db(path)) for path in part_db_dirs] - out_parts = PartDb() + 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]) - infos = [PartInfo(sch) for sch in sch_db.iterparts()] + def supplier_part_index(op: OrderPart): + return set([s_part.uriProp for s, s_part in op.available_from]) - for info in infos: - sch_part_numbers = info.part.referencesProp.part_number - sch_supplier_part_numbers: List[types.SupplierPartNumber] = info.part.referencesProp.supplier_part_number + 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): - found = None for sch_pn in sch_part_numbers: for pn in bom_file_utils.part_numbers(supplier_part): if sch_pn.valueProp == pn.valueProp: - found = supplier_part - break - if found: - break - - if found: - info.available_from.append((supplier, found)) - break + order_part.available_from.append((supplier, supplier_part)) - found = None 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: - found = supplier_part - break - if found: - break - - if found: - info.available_from.append((supplier, found)) - break - - for info in infos: - if len(info.available_from): - strings = ["{} from {}".format(part.uri, s) for s, part in info.available_from] - text = "Resolved {} to {}".format(info.ref, ", ".join(strings)) - messages.append(report.Message(object=info.ref, text=text)) - - has_missing_parts = False - for info in infos: - if len(info.available_from) == 0: - has_missing_parts = True - text = "Could not find {} in any database, part numbers: {}". \ - format(info.ref, ", ".join([p.value for p in bom_file_utils.part_numbers(info.part)])) - messages.append(report.Message(object=info.ref, text=text)) - - if has_missing_parts and fail_on_missing_parts: + 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") - for info in infos: - if len(info.available_from) == 0: + 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 = info.available_from[0] + supplier, supplier_part = order_part.selected_supplier_and_part - references = types.ReferencesList(schematic_reference=info.part.referencesProp.schematic_reference) + 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) - # messages - kwargs = {"messages_by_object": groupby(messages, lambda m: m.object)} - report.save_report("ee.order", "order.rst.j2", project.report_dir / "order.rst", **kwargs) diff --git a/src/ee/order/templates/order.rst.j2 b/src/ee/order/templates/order.rst.j2 index ea1dbdf..6616167 100644 --- a/src/ee/order/templates/order.rst.j2 +++ b/src/ee/order/templates/order.rst.j2 @@ -1,9 +1,55 @@ -Messages -======== -{% for o, messages in messages_by_object %} -{{ o | subsection }} -{% for m in messages %} -* {{ m.text }} -{% endfor %} +Order +===== + +Has unresolved parts: {{ "yes" if has_unresolved_parts else "no" }}. + +Parts for Order +=============== +{% for op in order_parts %} +{{ op.ref | subsection }} +{% if op.available_from|length == 0 %} +Part not resolved. +{% elif op.available_from|length == 1 %} +{%- set from=op.available_from[0] %} +{%- set part=from[1] %} +{%- set pn=part|first_pn %} +{%- set spn=part|first_spn %} +Selected supplier: {{ from[0] }}{{ (", pn: " + pn.valueProp) if pn else "" }}{{ (", spn: " + spn.valueProp) if spn else "" }}. +Part: part-{{pn.valueProp}}_ +{% else %} +MANY +{% endif %} +{%- endfor %} + +Part details +============ +{% for supplier, parts in parts_by_supplier.items() %} +{{ ("From " + supplier) | subsection }} +{% for part in parts %} +{%- set pn=part|first_pn %} +{%- set spn=part|first_spn %} +{%- set title=pn.valueProp if pn else (spn.valueProp if spn else "???") %} +{%- set links=part.linksProp.link %} +.. _part-{{title}}: + +{{ title|subsubsection }} +{#- + +"Facts" +....... + +{% for f in part.facts.fact %} +f={{f}} {% endfor %} +#} + +"Media" +....... +{% for l in links %} +{%- if l.relationProp == "http://purl.org/ee/link-relation#documentation" %} +* `{{ l.title }} <{{ l.url }}>`__ +{%- endif %} +{%- endfor %} +{% endfor %} +{% endfor %} |