From ce099f43f3ceb283da19c7283cdc09a118de4a15 Mon Sep 17 00:00:00 2001 From: jmht Date: Sat, 14 Sep 2019 21:40:09 +0100 Subject: [PATCH 01/10] Fixes problem with 'New Purchase Order' button not working from Suppliers page. --- .../company/templates/company/detail_purchase_orders.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/InvenTree/company/templates/company/detail_purchase_orders.html b/InvenTree/company/templates/company/detail_purchase_orders.html index aad4f7bf99..077a107848 100644 --- a/InvenTree/company/templates/company/detail_purchase_orders.html +++ b/InvenTree/company/templates/company/detail_purchase_orders.html @@ -9,7 +9,7 @@
- +
@@ -38,7 +38,7 @@ newOrder(); }); - $("#company-order-2").click(function() { + $("#company-order2").click(function() { newOrder(); }); @@ -47,4 +47,4 @@ sortable: true, }); -{% endblock %} \ No newline at end of file +{% endblock %} From 9c84e9076ff18c81d597d987f402385445517f21 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 15 Sep 2019 19:29:18 +1000 Subject: [PATCH 02/10] Consolidate stock export code - Now defined in stock.admin as StockItemResource - Much more control over format of exported data - Exported data can be re-imported! --- InvenTree/InvenTree/helpers.py | 1 + InvenTree/stock/admin.py | 4 ++ InvenTree/stock/views.py | 72 ++-------------------------------- 3 files changed, 9 insertions(+), 68 deletions(-) diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 84409226c2..231423be8f 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -103,6 +103,7 @@ def GetExportFormats(): 'xls', 'xlsx', 'json', + 'yaml', ] diff --git a/InvenTree/stock/admin.py b/InvenTree/stock/admin.py index ef84b0890e..a791b30ae1 100644 --- a/InvenTree/stock/admin.py +++ b/InvenTree/stock/admin.py @@ -61,6 +61,10 @@ class StockItemResource(ModelResource): supplier_part = Field(attribute='supplier_part', widget=widgets.ForeignKeyWidget(SupplierPart)) + supplier = Field(attribute='supplier_part__supplier__id', readonly=True) + + supplier_name = Field(attribute='supplier_part__supplier__name', readonly=True) + location = Field(attribute='location', widget=widgets.ForeignKeyWidget(StockLocation)) location_name = Field(attribute='location__name', readonly=True) diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 26a957a644..b9862aff31 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -29,6 +29,8 @@ from company.models import Company from part.models import Part from .models import StockItem, StockLocation, StockItemTracking +from .admin import StockItemResource + from .forms import EditStockLocationForm from .forms import CreateStockItemForm from .forms import EditStockItemForm @@ -226,75 +228,9 @@ class StockExport(AjaxView): # Pre-fetch related fields to reduce DB queries stock_items = stock_items.prefetch_related('part', 'supplier_part__supplier', 'location', 'purchase_order', 'build') - # Column headers - headers = [ - _('Stock ID'), - _('Part ID'), - _('Part'), - _('Supplier Part ID'), - _('Supplier ID'), - _('Supplier'), - _('Location ID'), - _('Location'), - _('Quantity'), - _('Batch'), - _('Serial'), - _('Status'), - _('Notes'), - _('Review Needed'), - _('Last Updated'), - _('Last Stocktake'), - _('Purchase Order ID'), - _('Build ID'), - ] + dataset = StockItemResource().export(queryset=stock_items) - data = tablib.Dataset(headers=headers) - - for item in stock_items: - line = [] - - line.append(item.pk) - line.append(item.part.pk) - line.append(item.part.full_name) - - if item.supplier_part: - line.append(item.supplier_part.pk) - line.append(item.supplier_part.supplier.pk) - line.append(item.supplier_part.supplier.name) - else: - line.append('') - line.append('') - line.append('') - - if item.location: - line.append(item.location.pk) - line.append(item.location.name) - else: - line.append('') - line.append('') - - line.append(item.quantity) - line.append(item.batch) - line.append(item.serial) - line.append(StockStatus.label(item.status)) - line.append(item.notes) - line.append(item.review_needed) - line.append(item.updated) - line.append(item.stocktake_date) - - if item.purchase_order: - line.append(item.purchase_order.pk) - else: - line.append('') - - if item.build: - line.append(item.build.pk) - else: - line.append('') - - data.append(line) - - filedata = data.export(export_format) + filedata = dataset.export(export_format) return DownloadFile(filedata, filename) From 2bc97764c7de7db76183d2ce008f06b84082e08f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 15 Sep 2019 19:45:59 +1000 Subject: [PATCH 03/10] Allow more file formats for BOM import --- InvenTree/part/bom.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/part/bom.py b/InvenTree/part/bom.py index baf46e8618..d23cb02032 100644 --- a/InvenTree/part/bom.py +++ b/InvenTree/part/bom.py @@ -10,13 +10,13 @@ import os from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError -from InvenTree.helpers import DownloadFile +from InvenTree.helpers import DownloadFile, GetExportFormats def IsValidBOMFormat(fmt): """ Test if a file format specifier is in the valid list of BOM file formats """ - return fmt.strip().lower() in ['csv', 'xls', 'xlsx', 'tsv'] + return fmt.strip().lower() in GetExportFormats() def MakeBomTemplate(fmt): From 2d17f957f16598103173882a52b155acabd61003 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 15 Sep 2019 19:52:28 +1000 Subject: [PATCH 04/10] Remove code duplication for part data export --- InvenTree/part/admin.py | 2 + InvenTree/part/views.py | 105 ++-------------------------------------- 2 files changed, 6 insertions(+), 101 deletions(-) diff --git a/InvenTree/part/admin.py b/InvenTree/part/admin.py index 7a9def473f..331a3f943b 100644 --- a/InvenTree/part/admin.py +++ b/InvenTree/part/admin.py @@ -31,6 +31,8 @@ class PartResource(ModelResource): variant_of = Field(attribute='variant_of', widget=widgets.ForeignKeyWidget(Part)) + suppliers = Field(attribute='supplier_count', readonly=True) + # Extra calculated meta-data (readonly) in_stock = Field(attribute='total_stock', readonly=True, widget=widgets.IntegerWidget()) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 7f66cd7718..9e1b5491e8 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -30,6 +30,8 @@ from company.models import SupplierPart from . import forms as part_forms from .bom import MakeBomTemplate, BomUploadManager +from .admin import PartResource + from InvenTree.views import AjaxView, AjaxCreateView, AjaxUpdateView, AjaxDeleteView from InvenTree.views import QRCodeView @@ -1216,108 +1218,9 @@ class PartExport(AjaxView): parts = self.get_parts(request) - headers = [ - 'ID', - 'Name', - 'Description', - 'Category', - 'Category ID', - 'IPN', - 'Revision', - 'URL', - 'Keywords', - 'Notes', - 'Assembly', - 'Component', - 'Template', - 'Trackable', - 'Purchaseable', - 'Salable', - 'Active', - 'Virtual', + dataset = PartResource().export(queryset=parts) - # Part meta-data - 'Used In', - - # Stock Information - 'Stock Info', - '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) - - if part.category: - line.append(str(part.category)) - line.append(part.category.pk) - else: - line.append('') - line.append('') - - 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.purchaseable) - line.append(part.salable) - line.append(part.active) - line.append(part.virtual) - - # Part meta-data - line.append(part.used_in_count) - - # 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) - - # Supplier Information - 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') + csv = dataset.export('csv') return DownloadFile(csv, 'InvenTree_Parts.csv') From 03043e67c79c25a333e40455be80cc613237266a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 15 Sep 2019 19:58:05 +1000 Subject: [PATCH 05/10] Perform full validation when importing data --- InvenTree/company/admin.py | 3 +++ InvenTree/part/admin.py | 4 ++++ InvenTree/stock/admin.py | 2 ++ 3 files changed, 9 insertions(+) diff --git a/InvenTree/company/admin.py b/InvenTree/company/admin.py index ada60c7975..ce023aedc0 100644 --- a/InvenTree/company/admin.py +++ b/InvenTree/company/admin.py @@ -23,6 +23,7 @@ class CompanyResource(ModelResource): model = Company skip_unchanged = True report_skipped = False + clean_model_instances = True class CompanyAdmin(ImportExportModelAdmin): @@ -43,6 +44,7 @@ class SupplierPartResource(ModelResource): model = SupplierPart skip_unchanged = True report_skipped = False + clean_model_instances = True class SupplierPartAdmin(ImportExportModelAdmin): @@ -63,6 +65,7 @@ class SupplierPriceBreakResource(ModelResource): model = SupplierPriceBreak skip_unchanged = True report_skipped = False + clean_model_instances = True class SupplierPriceBreakAdmin(ImportExportModelAdmin): diff --git a/InvenTree/part/admin.py b/InvenTree/part/admin.py index 331a3f943b..601815caec 100644 --- a/InvenTree/part/admin.py +++ b/InvenTree/part/admin.py @@ -48,6 +48,7 @@ class PartResource(ModelResource): model = Part skip_unchanged = True report_skipped = False + clean_model_instances = True exclude = [ 'bom_checksum', 'bom_checked_by', 'bom_checked_date' ] @@ -91,6 +92,7 @@ class PartCategoryResource(ModelResource): model = PartCategory skip_unchanged = True report_skipped = False + clean_model_instances = True exclude = [ # Exclude MPTT internal model fields @@ -135,6 +137,7 @@ class BomItemResource(ModelResource): model = BomItem skip_unchanged = True report_skipped = False + clean_model_instances = True class BomItemAdmin(ImportExportModelAdmin): @@ -165,6 +168,7 @@ class ParameterResource(ModelResource): model = PartParameter skip_unchanged = True report_skipped = False + clean_model_instance = True class ParameterAdmin(ImportExportModelAdmin): diff --git a/InvenTree/stock/admin.py b/InvenTree/stock/admin.py index a791b30ae1..225c86dfc2 100644 --- a/InvenTree/stock/admin.py +++ b/InvenTree/stock/admin.py @@ -28,6 +28,7 @@ class LocationResource(ModelResource): model = StockLocation skip_unchanged = True report_skipped = False + clean_model_instances = True exclude = [ # Exclude MPTT internal model fields @@ -86,6 +87,7 @@ class StockItemResource(ModelResource): model = StockItem skip_unchanged = True report_skipped = False + clean_model_instance = True class StockItemAdmin(ImportExportModelAdmin): From 204cd967aa72faff467b63498df128085fa8ebb5 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 15 Sep 2019 20:14:27 +1000 Subject: [PATCH 06/10] Include status label text when exporting stocktake data --- InvenTree/part/views.py | 2 -- InvenTree/stock/admin.py | 2 ++ InvenTree/stock/models.py | 5 +++++ InvenTree/stock/views.py | 3 --- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 9e1b5491e8..f8bbd0e841 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -14,8 +14,6 @@ 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 decimal import Decimal diff --git a/InvenTree/stock/admin.py b/InvenTree/stock/admin.py index 225c86dfc2..119aa3e7a8 100644 --- a/InvenTree/stock/admin.py +++ b/InvenTree/stock/admin.py @@ -66,6 +66,8 @@ class StockItemResource(ModelResource): supplier_name = Field(attribute='supplier_part__supplier__name', readonly=True) + status_label = Field(attribute='status_label', readonly=True) + location = Field(attribute='location', widget=widgets.ForeignKeyWidget(StockLocation)) location_name = Field(attribute='location__name', readonly=True) diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 272d212cef..7b5d01c58b 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -140,6 +140,11 @@ class StockItem(models.Model): system=True ) + @property + def status_label(self): + + return StockStatus.label(self.status) + @property def serialized(self): """ Return True if this StockItem is serialized """ diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index b9862aff31..1bb9a27a83 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -18,13 +18,10 @@ from InvenTree.views import AjaxView from InvenTree.views import AjaxUpdateView, AjaxDeleteView, AjaxCreateView from InvenTree.views import QRCodeView -from InvenTree.status_codes import StockStatus from InvenTree.helpers import str2bool, DownloadFile, GetExportFormats from InvenTree.helpers import ExtractSerialNumbers from datetime import datetime -import tablib - from company.models import Company from part.models import Part from .models import StockItem, StockLocation, StockItemTracking From ed20e9d4a16d30521a1731f768126b3d865abb59 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 15 Sep 2019 22:04:52 +1000 Subject: [PATCH 07/10] Simplify code for exporting PurchaseOrder - New resource for managing import/export of POLineItem model --- InvenTree/order/admin.py | 24 +++++++++++++++++++ InvenTree/order/models.py | 49 --------------------------------------- InvenTree/order/tests.py | 10 -------- InvenTree/order/views.py | 5 +++- 4 files changed, 28 insertions(+), 60 deletions(-) diff --git a/InvenTree/order/admin.py b/InvenTree/order/admin.py index 44d26ea3f2..05598928a7 100644 --- a/InvenTree/order/admin.py +++ b/InvenTree/order/admin.py @@ -2,8 +2,12 @@ from __future__ import unicode_literals from django.contrib import admin + from import_export.admin import ImportExportModelAdmin +from import_export.resources import ModelResource +from import_export.fields import Field + from .models import PurchaseOrder, PurchaseOrderLineItem @@ -18,8 +22,28 @@ class PurchaseOrderAdmin(ImportExportModelAdmin): ) +class POLineItemResource(ModelResource): + """ Class for managing import / export of POLineItem data """ + + part_name = Field(attribute='part__part__name', readonly=True) + + manufacturer = Field(attribute='part__manufacturer', readonly=True) + + MPN = Field(attribute='part__MPN', readonly=True) + + SKU = Field(attribute='part__SKU', readonly=True) + + class Meta: + model = PurchaseOrderLineItem + skip_unchanged = True + report_skipped = False + clean_model_instances = True + + class PurchaseOrderLineItemAdmin(ImportExportModelAdmin): + resource_class = POLineItemResource + list_display = ( 'order', 'part', diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index ef79a4d39b..9eff4d11c3 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -12,7 +12,6 @@ from django.contrib.auth.models import User from django.urls import reverse from django.utils.translation import ugettext as _ -import tablib from datetime import datetime from stock.models import StockItem @@ -126,54 +125,6 @@ class PurchaseOrder(Order): related_name='+' ) - def export_to_file(self, **kwargs): - """ Export order information to external file """ - - file_format = kwargs.get('format', 'csv').lower() - - data = tablib.Dataset(headers=[ - 'Line', - 'Part', - 'Description', - 'Manufacturer', - 'MPN', - 'Order Code', - 'Quantity', - 'Received', - 'Reference', - 'Notes', - ]) - - idx = 0 - - for item in self.lines.all(): - - line = [] - - line.append(idx) - - if item.part: - line.append(item.part.part.name) - line.append(item.part.part.description) - - line.append(item.part.manufacturer) - line.append(item.part.MPN) - line.append(item.part.SKU) - - else: - line += [[] * 5] - - line.append(item.quantity) - line.append(item.received) - line.append(item.reference) - line.append(item.notes) - - idx += 1 - - data.append(line) - - return data.export(file_format) - def get_absolute_url(self): return reverse('purchase-order-detail', kwargs={'pk': self.id}) diff --git a/InvenTree/order/tests.py b/InvenTree/order/tests.py index c271e0be43..351c152472 100644 --- a/InvenTree/order/tests.py +++ b/InvenTree/order/tests.py @@ -139,13 +139,3 @@ class OrderTest(TestCase): order.receive_line_item(line, loc, line.quantity, user=None) self.assertEqual(order.status, OrderStatus.COMPLETE) - - def test_export(self): - """ Test order exporting """ - - order = PurchaseOrder.objects.get(pk=1) - - output = order.export_to_file(format='csv') - - self.assertIn('M2x4 LPHS', output) - self.assertIn('Line,Part,Description', output) diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index fafd313022..86a231075e 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -14,6 +14,7 @@ from django.forms import HiddenInput import logging from .models import PurchaseOrder, PurchaseOrderLineItem +from .admin import POLineItemResource from build.models import Build from company.models import Company, SupplierPart from stock.models import StockItem, StockLocation @@ -165,7 +166,9 @@ class PurchaseOrderExport(AjaxView): fmt=export_format ) - filedata = order.export_to_file(format=export_format) + dataset = POLineItemResource().export(queryset=order.lines.all()) + + filedata = dataset.export(format=export_format) return DownloadFile(filedata, filename) From db04f399c17bf524b17ba737f42abfae98ff9336 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 15 Sep 2019 22:21:12 +1000 Subject: [PATCH 08/10] Simplify exporting of BOM for a part --- InvenTree/part/admin.py | 10 ++++- InvenTree/part/bom.py | 31 ++++++++++---- InvenTree/part/models.py | 72 --------------------------------- InvenTree/part/test_bom_item.py | 9 ----- InvenTree/part/views.py | 10 ++--- 5 files changed, 36 insertions(+), 96 deletions(-) diff --git a/InvenTree/part/admin.py b/InvenTree/part/admin.py index 601815caec..2146f76de6 100644 --- a/InvenTree/part/admin.py +++ b/InvenTree/part/admin.py @@ -131,7 +131,13 @@ class BomItemResource(ModelResource): 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: model = BomItem @@ -139,6 +145,8 @@ class BomItemResource(ModelResource): report_skipped = False clean_model_instances = True + exclude = ('checksum') + class BomItemAdmin(ImportExportModelAdmin): diff --git a/InvenTree/part/bom.py b/InvenTree/part/bom.py index d23cb02032..394314d461 100644 --- a/InvenTree/part/bom.py +++ b/InvenTree/part/bom.py @@ -12,6 +12,9 @@ from django.core.exceptions import ValidationError from InvenTree.helpers import DownloadFile, GetExportFormats +from .admin import BomItemResource +from .models import BomItem + def IsValidBOMFormat(fmt): """ 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): fmt = 'csv' - fields = [ - 'Part', - 'Quantity', - 'Overage', - 'Reference', - 'Notes' - ] + query = BomItem.objects.filter(pk=None) + dataset = BomItemResource().export(queryset=query) - data = tablib.Dataset(headers=fields).export(fmt) + data = dataset.export(fmt) filename = 'InvenTree_BOM_Template.' + fmt 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 for managing an uploaded BOM file """ diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 76d9f606d0..5040bdc2f0 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -7,8 +7,6 @@ from __future__ import unicode_literals import os -import tablib - from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError from django.urls import reverse @@ -857,76 +855,6 @@ class Part(models.Model): 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 def attachment_count(self): """ Count the number of attachments for this part. diff --git a/InvenTree/part/test_bom_item.py b/InvenTree/part/test_bom_item.py index ec29dbaab3..e5d94744c0 100644 --- a/InvenTree/part/test_bom_item.py +++ b/InvenTree/part/test_bom_item.py @@ -32,15 +32,6 @@ class BomItemTest(TestCase): 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): self.assertEqual(self.bob.used_in_count, 0) self.assertEqual(self.orphan.used_in_count, 1) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index f8bbd0e841..7d1a3ab633 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -26,7 +26,7 @@ from common.models import Currency from company.models import SupplierPart from . import forms as part_forms -from .bom import MakeBomTemplate, BomUploadManager +from .bom import MakeBomTemplate, BomUploadManager, ExportBom, IsValidBOMFormat from .admin import PartResource @@ -1249,12 +1249,10 @@ class BomDownload(AjaxView): export_format = request.GET.get('format', 'csv') - # Placeholder to test file export - filename = '"' + part.name + '_BOM.' + export_format + '"' + if not IsValidBOMFormat(export_format): + export_format = 'csv' - filedata = part.export_bom(format=export_format) - - return DownloadFile(filedata, filename) + return ExportBom(part, fmt=export_format) def get_data(self): return { From 7f5aba423a93d676ac069c00474e81cb4475b49f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 15 Sep 2019 22:23:28 +1000 Subject: [PATCH 09/10] Export full_name for parts --- InvenTree/part/admin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/part/admin.py b/InvenTree/part/admin.py index 2146f76de6..fcef36a772 100644 --- a/InvenTree/part/admin.py +++ b/InvenTree/part/admin.py @@ -131,11 +131,11 @@ class BomItemResource(ModelResource): part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part)) - part_name = Field(attribute='part__name', readonly=True) + part_name = Field(attribute='part__full_name', readonly=True) sub_part = Field(attribute='sub_part', widget=widgets.ForeignKeyWidget(Part)) - sub_part_name = Field(attribute='sub_part__name', readonly=True) + sub_part_name = Field(attribute='sub_part__full_name', readonly=True) stock = Field(attribute='sub_part__total_stock', readonly=True) From 194ae499147e07ca54f368acc8563201e2f83922 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 15 Sep 2019 22:23:34 +1000 Subject: [PATCH 10/10] Export full_name for parts --- InvenTree/stock/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/stock/admin.py b/InvenTree/stock/admin.py index 119aa3e7a8..c33010bf3b 100644 --- a/InvenTree/stock/admin.py +++ b/InvenTree/stock/admin.py @@ -58,7 +58,7 @@ class StockItemResource(ModelResource): # Custom manaegrs for ForeignKey fields part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part)) - part_name = Field(attribute='part__name', readonly=True) + part_name = Field(attribute='part__full_ame', readonly=True) supplier_part = Field(attribute='supplier_part', widget=widgets.ForeignKeyWidget(SupplierPart))