Implement cascading export of BOM

This commit is contained in:
Oliver Walters 2020-02-11 22:32:36 +11:00
parent 434d084371
commit f865573e48
3 changed files with 40 additions and 9 deletions

View File

@ -129,15 +129,17 @@ class PartStarAdmin(admin.ModelAdmin):
class BomItemResource(ModelResource): class BomItemResource(ModelResource):
""" Class for managing BomItem data import/export """ """ Class for managing BomItem data import/export """
level = Field(attribute='level', readonly=True)
part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part)) part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))
part_name = Field(attribute='part__full_name', readonly=True) parent_part_name = Field(attribute='part__full_name', readonly=True)
sub_part = Field(attribute='sub_part', widget=widgets.ForeignKeyWidget(Part)) id = Field(attribute='sub_part', widget=widgets.ForeignKeyWidget(Part))
sub_part_name = Field(attribute='sub_part__full_name', readonly=True) sub_part_name = Field(attribute='sub_part__full_name', readonly=True)
stock = Field(attribute='sub_part__total_stock', readonly=True) sub_assembly = Field(attribute='sub_part__assembly', readonly=True)
class Meta: class Meta:
model = BomItem model = BomItem
@ -145,7 +147,7 @@ class BomItemResource(ModelResource):
report_skipped = False report_skipped = False
clean_model_instances = True clean_model_instances = True
exclude = ('checksum') exclude = ['checksum', ]
class BomItemAdmin(ImportExportModelAdmin): class BomItemAdmin(ImportExportModelAdmin):

View File

@ -40,16 +40,43 @@ def MakeBomTemplate(fmt):
return DownloadFile(data, filename) return DownloadFile(data, filename)
def ExportBom(part, fmt='csv'): def ExportBom(part, fmt='csv', cascade=False):
""" Export a BOM (Bill of Materials) for a given part. """ Export a BOM (Bill of Materials) for a given part.
Args:
fmt: File format (default = 'csv')
cascade: If True, multi-level BOM output is supported. Otherwise, a flat top-level-only BOM is exported.
""" """
if not IsValidBOMFormat(fmt): if not IsValidBOMFormat(fmt):
fmt = 'csv' fmt = 'csv'
bom_items = part.bom_items.all().order_by('id') bom_items = []
dataset = BomItemResource().export(queryset=bom_items) def add_items(items, level):
# Add items at a given layer
for item in items:
item.level = '-' * level
bom_items.append(item)
if item.sub_part.assembly:
add_items(item.sub_part.bom_items.all().order_by('id'), level + 1)
if cascade:
# Cascading (multi-level) BOM
# Start with the top level
items_to_process = part.bom_items.all().order_by('id')
add_items(items_to_process, 1)
else:
# No cascading needed - just the top-level items
bom_items = [item for item in part.bom_items.all().order_by('id')]
dataset = BomItemResource().export(queryset=bom_items, cascade=cascade)
data = dataset.export(fmt) data = dataset.export(fmt)
filename = '{n}_BOM.{fmt}'.format(n=part.full_name, fmt=fmt) filename = '{n}_BOM.{fmt}'.format(n=part.full_name, fmt=fmt)

View File

@ -1334,10 +1334,12 @@ class BomDownload(AjaxView):
export_format = request.GET.get('file_format', 'csv') export_format = request.GET.get('file_format', 'csv')
cascade = str2bool(request.GET.get('cascade', False))
if not IsValidBOMFormat(export_format): if not IsValidBOMFormat(export_format):
export_format = 'csv' export_format = 'csv'
return ExportBom(part, fmt=export_format) return ExportBom(part, fmt=export_format, cascade=cascade)
def get_data(self): def get_data(self):
return { return {