diff --git a/InvenTree/part/bom.py b/InvenTree/part/bom.py index d7906bff6c..fae9eb7b5f 100644 --- a/InvenTree/part/bom.py +++ b/InvenTree/part/bom.py @@ -47,7 +47,7 @@ def MakeBomTemplate(fmt): return DownloadFile(data, filename) -def ExportBom(part, fmt='csv', cascade=False, max_levels=None): +def ExportBom(part, fmt='csv', cascade=False, max_levels=None, supplier_data=False): """ Export a BOM (Bill of Materials) for a given part. Args: @@ -92,67 +92,72 @@ def ExportBom(part, fmt='csv', cascade=False, max_levels=None): dataset = BomItemResource().export(queryset=bom_items, cascade=cascade) - # Expand dataset with manufacturer parts - manufacturer_headers = [ - _('Supplier'), - _('SKU'), - _('Manufacturer'), - _('MPN'), - ] + if supplier_data: + """ + If requested, add extra columns for each SupplierPart associated with the each line item + """ - manufacturer_cols = {} + # Expand dataset with manufacturer parts + manufacturer_headers = [ + _('Supplier'), + _('SKU'), + _('Manufacturer'), + _('MPN'), + ] - for b_idx, bom_item in enumerate(bom_items): - # Get part instance - b_part = bom_item.sub_part + manufacturer_cols = {} - # Filter supplier parts - supplier_parts = SupplierPart.objects.filter(part__pk=b_part.pk) - - # Construct supplier-part data - supplier_part_list = [] - - for idx, supplier_part in enumerate(supplier_parts): + for b_idx, bom_item in enumerate(bom_items): + # Get part instance + b_part = bom_item.sub_part - if supplier_part.supplier: - supplier_name = supplier_part.supplier.name - else: - supplier_name = '' + # Filter supplier parts + supplier_parts = SupplierPart.objects.filter(part__pk=b_part.pk) + + # Construct supplier-part data + supplier_part_list = [] + + for idx, supplier_part in enumerate(supplier_parts): - supplier_sku = supplier_part.SKU + if supplier_part.supplier: + supplier_name = supplier_part.supplier.name + else: + supplier_name = '' - if supplier_part.manufacturer: - manufacturer_name = supplier_part.manufacturer.name - else: - manufacturer_name = '' + supplier_sku = supplier_part.SKU - manufacturer_mpn = supplier_part.MPN + if supplier_part.manufacturer: + manufacturer_name = supplier_part.manufacturer.name + else: + manufacturer_name = '' - # Add manufacturer data to the manufacturer columns + manufacturer_mpn = supplier_part.MPN - # Generate column names for this supplier - k_sup = manufacturer_headers[0] + "_" + str(idx) - k_sku = manufacturer_headers[1] + "_" + str(idx) - k_man = manufacturer_headers[2] + "_" + str(idx) - k_mpn = manufacturer_headers[3] + "_" + str(idx) + # Add manufacturer data to the manufacturer columns - try: - manufacturer_cols[k_sup].update({b_idx: supplier_name}) - manufacturer_cols[k_sku].update({b_idx: supplier_sku}) - manufacturer_cols[k_man].update({b_idx: manufacturer_name}) - manufacturer_cols[k_mpn].update({b_idx: manufacturer_mpn}) - except KeyError: - manufacturer_cols[k_sup] = {b_idx: supplier_name} - manufacturer_cols[k_sku] = {b_idx: supplier_sku} - manufacturer_cols[k_man] = {b_idx: manufacturer_name} - manufacturer_cols[k_mpn] = {b_idx: manufacturer_mpn} + # Generate column names for this supplier + k_sup = manufacturer_headers[0] + "_" + str(idx) + k_sku = manufacturer_headers[1] + "_" + str(idx) + k_man = manufacturer_headers[2] + "_" + str(idx) + k_mpn = manufacturer_headers[3] + "_" + str(idx) - # Add manufacturer columns to dataset - for header, col_dict in manufacturer_cols.items(): - # Construct column tuple - col = tuple(col_dict.get(c_idx, '') for c_idx in range(len(bom_items))) - # Add column to dataset - dataset.append_col(col, header=header) + try: + manufacturer_cols[k_sup].update({b_idx: supplier_name}) + manufacturer_cols[k_sku].update({b_idx: supplier_sku}) + manufacturer_cols[k_man].update({b_idx: manufacturer_name}) + manufacturer_cols[k_mpn].update({b_idx: manufacturer_mpn}) + except KeyError: + manufacturer_cols[k_sup] = {b_idx: supplier_name} + manufacturer_cols[k_sku] = {b_idx: supplier_sku} + manufacturer_cols[k_man] = {b_idx: manufacturer_name} + manufacturer_cols[k_mpn] = {b_idx: manufacturer_mpn} + + # Add manufacturer columns to dataset + for header, col_dict in manufacturer_cols.items(): + # Construct column tuple + col = tuple(col_dict.get(c_idx, '') for c_idx in range(len(bom_items))) + # Add column to dataset + dataset.append_col(col, header=header) data = dataset.export(fmt) diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index dbbced352b..7b252067e8 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -54,10 +54,12 @@ class BomExportForm(forms.Form): file_format = forms.ChoiceField(label=_("File Format"), help_text=_("Select output file format")) - cascading = forms.BooleanField(label=_("Cascading"), required=False, initial=False, help_text=_("Download cascading / multi-level BOM")) + cascading = forms.BooleanField(label=_("Cascading"), required=False, initial=True, help_text=_("Download cascading / multi-level BOM")) levels = forms.IntegerField(label=_("Levels"), required=True, initial=0, help_text=_("Select maximum number of BOM levels to export (0 = all levels)")) + supplier_data = forms.BooleanField(label=_("Include Supplier Data"), required=False, initial=True, help_text=_("Include supplier part data in exported BOM")) + def get_choices(self): """ BOM export format choices """ diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index a01b6b4ff2..3afb863791 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -1499,6 +1499,8 @@ class BomDownload(AjaxView): cascade = str2bool(request.GET.get('cascade', False)) + supplier_data = str2bool(request.GET.get('supplier_data', False)) + levels = request.GET.get('levels', None) if levels is not None: @@ -1514,7 +1516,7 @@ class BomDownload(AjaxView): if not IsValidBOMFormat(export_format): export_format = 'csv' - return ExportBom(part, fmt=export_format, cascade=cascade, max_levels=levels) + return ExportBom(part, fmt=export_format, cascade=cascade, max_levels=levels, supplier_data=supplier_data) def get_data(self): return { @@ -1539,6 +1541,7 @@ class BomExport(AjaxView): fmt = request.POST.get('file_format', 'csv').lower() cascade = str2bool(request.POST.get('cascading', False)) levels = request.POST.get('levels', None) + supplier_data = str2bool(request.POST.get('supplier_data', False)) try: part = Part.objects.get(pk=self.kwargs['pk']) @@ -1553,6 +1556,7 @@ class BomExport(AjaxView): url += '?file_format=' + fmt url += '&cascade=' + str(cascade) + url += '&supplier_data=' + str(supplier_data) if levels: url += '&levels=' + str(levels)