mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Simplify exporting of BOM for a part
This commit is contained in:
parent
ed20e9d4a1
commit
db04f399c1
@ -131,7 +131,13 @@ class BomItemResource(ModelResource):
|
|||||||
|
|
||||||
part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))
|
part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))
|
||||||
|
|
||||||
sub_part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))
|
part_name = Field(attribute='part__name', readonly=True)
|
||||||
|
|
||||||
|
sub_part = Field(attribute='sub_part', widget=widgets.ForeignKeyWidget(Part))
|
||||||
|
|
||||||
|
sub_part_name = Field(attribute='sub_part__name', readonly=True)
|
||||||
|
|
||||||
|
stock = Field(attribute='sub_part__total_stock', readonly=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = BomItem
|
model = BomItem
|
||||||
@ -139,6 +145,8 @@ class BomItemResource(ModelResource):
|
|||||||
report_skipped = False
|
report_skipped = False
|
||||||
clean_model_instances = True
|
clean_model_instances = True
|
||||||
|
|
||||||
|
exclude = ('checksum')
|
||||||
|
|
||||||
|
|
||||||
class BomItemAdmin(ImportExportModelAdmin):
|
class BomItemAdmin(ImportExportModelAdmin):
|
||||||
|
|
||||||
|
@ -12,6 +12,9 @@ from django.core.exceptions import ValidationError
|
|||||||
|
|
||||||
from InvenTree.helpers import DownloadFile, GetExportFormats
|
from InvenTree.helpers import DownloadFile, GetExportFormats
|
||||||
|
|
||||||
|
from .admin import BomItemResource
|
||||||
|
from .models import BomItem
|
||||||
|
|
||||||
|
|
||||||
def IsValidBOMFormat(fmt):
|
def IsValidBOMFormat(fmt):
|
||||||
""" Test if a file format specifier is in the valid list of BOM file formats """
|
""" Test if a file format specifier is in the valid list of BOM file formats """
|
||||||
@ -27,21 +30,33 @@ def MakeBomTemplate(fmt):
|
|||||||
if not IsValidBOMFormat(fmt):
|
if not IsValidBOMFormat(fmt):
|
||||||
fmt = 'csv'
|
fmt = 'csv'
|
||||||
|
|
||||||
fields = [
|
query = BomItem.objects.filter(pk=None)
|
||||||
'Part',
|
dataset = BomItemResource().export(queryset=query)
|
||||||
'Quantity',
|
|
||||||
'Overage',
|
|
||||||
'Reference',
|
|
||||||
'Notes'
|
|
||||||
]
|
|
||||||
|
|
||||||
data = tablib.Dataset(headers=fields).export(fmt)
|
data = dataset.export(fmt)
|
||||||
|
|
||||||
filename = 'InvenTree_BOM_Template.' + fmt
|
filename = 'InvenTree_BOM_Template.' + fmt
|
||||||
|
|
||||||
return DownloadFile(data, filename)
|
return DownloadFile(data, filename)
|
||||||
|
|
||||||
|
|
||||||
|
def ExportBom(part, fmt='csv'):
|
||||||
|
""" Export a BOM (Bill of Materials) for a given part.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not IsValidBOMFormat(fmt):
|
||||||
|
fmt = 'csv'
|
||||||
|
|
||||||
|
bom_items = part.bom_items.all().order_by('id')
|
||||||
|
|
||||||
|
dataset = BomItemResource().export(queryset=bom_items)
|
||||||
|
data = dataset.export(fmt)
|
||||||
|
|
||||||
|
filename = '{n}_BOM.{fmt}'.format(n=part.full_name, fmt=fmt)
|
||||||
|
|
||||||
|
return DownloadFile(data, filename)
|
||||||
|
|
||||||
|
|
||||||
class BomUploadManager:
|
class BomUploadManager:
|
||||||
""" Class for managing an uploaded BOM file """
|
""" Class for managing an uploaded BOM file """
|
||||||
|
|
||||||
|
@ -7,8 +7,6 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import tablib
|
|
||||||
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@ -857,76 +855,6 @@ class Part(models.Model):
|
|||||||
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def export_bom(self, **kwargs):
|
|
||||||
""" Export Bill of Materials to a spreadsheet file.
|
|
||||||
Includes a row for each item in the BOM.
|
|
||||||
Also includes extra information such as supplier data.
|
|
||||||
"""
|
|
||||||
|
|
||||||
items = self.bom_items.all().order_by('id')
|
|
||||||
|
|
||||||
supplier_names = set()
|
|
||||||
|
|
||||||
headers = [
|
|
||||||
'Part',
|
|
||||||
'Description',
|
|
||||||
'Quantity',
|
|
||||||
'Overage',
|
|
||||||
'Reference',
|
|
||||||
'Note',
|
|
||||||
'',
|
|
||||||
'In Stock',
|
|
||||||
]
|
|
||||||
|
|
||||||
# Contstruct list of suppliers for each part
|
|
||||||
for item in items:
|
|
||||||
part = item.sub_part
|
|
||||||
supplier_parts = part.supplier_parts.all()
|
|
||||||
item.suppliers = {}
|
|
||||||
|
|
||||||
for sp in supplier_parts:
|
|
||||||
name = sp.supplier.name
|
|
||||||
supplier_names.add(name)
|
|
||||||
item.suppliers[name] = sp
|
|
||||||
|
|
||||||
if len(supplier_names) > 0:
|
|
||||||
headers.append('')
|
|
||||||
for name in supplier_names:
|
|
||||||
headers.append(name)
|
|
||||||
|
|
||||||
data = tablib.Dataset(headers=headers)
|
|
||||||
|
|
||||||
for it in items:
|
|
||||||
line = []
|
|
||||||
|
|
||||||
# Information about each BOM item
|
|
||||||
line.append(it.sub_part.full_name)
|
|
||||||
line.append(it.sub_part.description)
|
|
||||||
line.append(it.quantity)
|
|
||||||
line.append(it.overage)
|
|
||||||
line.append(it.reference)
|
|
||||||
line.append(it.note)
|
|
||||||
|
|
||||||
# Extra information about the part
|
|
||||||
line.append('')
|
|
||||||
line.append(it.sub_part.available_stock)
|
|
||||||
|
|
||||||
if len(supplier_names) > 0:
|
|
||||||
line.append('') # Blank column separates supplier info
|
|
||||||
|
|
||||||
for name in supplier_names:
|
|
||||||
sp = it.suppliers.get(name, None)
|
|
||||||
if sp:
|
|
||||||
line.append(sp.SKU)
|
|
||||||
else:
|
|
||||||
line.append('')
|
|
||||||
|
|
||||||
data.append(line)
|
|
||||||
|
|
||||||
file_format = kwargs.get('format', 'csv').lower()
|
|
||||||
|
|
||||||
return data.export(file_format)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def attachment_count(self):
|
def attachment_count(self):
|
||||||
""" Count the number of attachments for this part.
|
""" Count the number of attachments for this part.
|
||||||
|
@ -32,15 +32,6 @@ class BomItemTest(TestCase):
|
|||||||
|
|
||||||
self.assertIn(self.orphan, parts)
|
self.assertIn(self.orphan, parts)
|
||||||
|
|
||||||
def test_bom_export(self):
|
|
||||||
parts = self.bob.required_parts()
|
|
||||||
|
|
||||||
data = self.bob.export_bom(format='csv')
|
|
||||||
|
|
||||||
for p in parts:
|
|
||||||
self.assertIn(p.name, data)
|
|
||||||
self.assertIn(p.description, data)
|
|
||||||
|
|
||||||
def test_used_in(self):
|
def test_used_in(self):
|
||||||
self.assertEqual(self.bob.used_in_count, 0)
|
self.assertEqual(self.bob.used_in_count, 0)
|
||||||
self.assertEqual(self.orphan.used_in_count, 1)
|
self.assertEqual(self.orphan.used_in_count, 1)
|
||||||
|
@ -26,7 +26,7 @@ from common.models import Currency
|
|||||||
from company.models import SupplierPart
|
from company.models import SupplierPart
|
||||||
|
|
||||||
from . import forms as part_forms
|
from . import forms as part_forms
|
||||||
from .bom import MakeBomTemplate, BomUploadManager
|
from .bom import MakeBomTemplate, BomUploadManager, ExportBom, IsValidBOMFormat
|
||||||
|
|
||||||
from .admin import PartResource
|
from .admin import PartResource
|
||||||
|
|
||||||
@ -1249,12 +1249,10 @@ class BomDownload(AjaxView):
|
|||||||
|
|
||||||
export_format = request.GET.get('format', 'csv')
|
export_format = request.GET.get('format', 'csv')
|
||||||
|
|
||||||
# Placeholder to test file export
|
if not IsValidBOMFormat(export_format):
|
||||||
filename = '"' + part.name + '_BOM.' + export_format + '"'
|
export_format = 'csv'
|
||||||
|
|
||||||
filedata = part.export_bom(format=export_format)
|
return ExportBom(part, fmt=export_format)
|
||||||
|
|
||||||
return DownloadFile(filedata, filename)
|
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
|
Loading…
Reference in New Issue
Block a user