diff --git a/InvenTree/InvenTree/static/script/inventree/part.js b/InvenTree/InvenTree/static/script/inventree/part.js index 71f78855f7..18909fff0d 100644 --- a/InvenTree/InvenTree/static/script/inventree/part.js +++ b/InvenTree/InvenTree/static/script/inventree/part.js @@ -241,4 +241,17 @@ function loadPartTable(table, url, options={}) { reload: true, }); }); + + $('#multi-part-export').click(function() { + var selections = $(table).bootstrapTable("getSelections"); + + var parts = ''; + + selections.forEach(function(item) { + parts += item.pk; + parts += ','; + }); + + location.href = '/part/export/?parts=' + parts; + }); } \ No newline at end of file diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html index 4bbb606bec..343d7a8c40 100644 --- a/InvenTree/part/templates/part/category.html +++ b/InvenTree/part/templates/part/category.html @@ -49,7 +49,7 @@ diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index e39375f032..3ec99e7255 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -78,6 +78,9 @@ part_urls = [ # Download a BOM upload template url(r'^bom_template/?', views.BomUploadTemplate.as_view(), name='bom-upload-template'), + # Export data for multiple parts + url(r'^export/', views.PartExport.as_view(), name='part-export'), + # Individual part url(r'^(?P\d+)/', include(part_detail_urls)), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index fae82bfc72..74adc490b8 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -14,6 +14,8 @@ from django.views.generic import DetailView, ListView, FormView from django.forms.models import model_to_dict from django.forms import HiddenInput, CheckboxInput +import tablib + from fuzzywuzzy import fuzz from .models import PartCategory, Part, PartAttachment @@ -1159,6 +1161,107 @@ class BomUpload(FormView): return self.render_to_response(self.get_context_data(form=self.form)) +class PartExport(AjaxView): + """ Export a CSV file containing information on multiple parts """ + + def get(self, request, *args, **kwargs): + part = request.GET.get('parts', '') + parts = [] + + for pk in part.split(','): + try: + parts.append(Part.objects.get(pk=int(pk))) + except (Part.DoesNotExist, ValueError): + continue + + headers = [ + 'ID', + 'Name', + 'Description', + 'Category', + 'Category ID', + 'IPN', + 'Revision', + 'URL', + 'Keywords', + 'Notes', + 'Assembly', + 'Component', + 'Template', + 'Trackable', + 'Salable', + 'Active', + 'Virtual', + 'Stock Info', # Spacer between part data and stock data + 'In Stock', + 'Allocated', + 'Building', + 'On Order', + ] + + # Construct list of suppliers for each part + supplier_names = set() + + for part in parts: + supplier_parts = part.supplier_parts.all() + part.suppliers = {} + + for sp in supplier_parts: + name = sp.supplier.name + supplier_names.add(name) + part.suppliers[name] = sp + + if len(supplier_names) > 0: + headers.append('Suppliers') + for name in supplier_names: + headers.append(name) + + data = tablib.Dataset(headers=headers) + + for part in parts: + line = [] + + line.append(part.pk) + line.append(part.name) + line.append(part.description) + line.append(str(part.category)) + line.append(part.category.pk) + line.append(part.IPN) + line.append(part.revision) + line.append(part.URL) + line.append(part.keywords) + line.append(part.notes) + line.append(part.assembly) + line.append(part.component) + line.append(part.is_template) + line.append(part.trackable) + line.append(part.salable) + line.append(part.active) + line.append(part.virtual) + + # Stock information + line.append('') + line.append(part.total_stock) + line.append(part.allocation_count) + line.append(part.quantity_being_built) + line.append(part.on_order) + + if len(supplier_names) > 0: + line.append('') + + for name in supplier_names: + sp = part.suppliers.get(name, None) + if sp: + line.append(sp.SKU) + else: + line.append('') + + data.append(line) + + csv = data.export('csv') + return DownloadFile(csv, 'InvenTree_Parts.csv') + + class BomUploadTemplate(AjaxView): """ Provide a BOM upload template file for download.