From 2831ac55c47a786c021963f8415793dc729ca00b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 27 Jun 2019 22:15:58 +1000 Subject: [PATCH] Link to download a BOM template file --- InvenTree/InvenTree/helpers.py | 28 +++++++++++++++++++ InvenTree/part/forms.py | 1 + InvenTree/part/templates/part/bom_upload.html | 13 +++++++++ InvenTree/part/urls.py | 3 ++ InvenTree/part/views.py | 14 +++++++++- 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 InvenTree/part/templates/part/bom_upload.html diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index ddb4e35fee..2c2f74fde6 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -6,6 +6,7 @@ import io import json import os.path from PIL import Image +import tablib from wsgiref.util import FileWrapper from django.http import StreamingHttpResponse @@ -91,6 +92,33 @@ def MakeBarcode(object_type, object_id, object_url, data={}): return json.dumps(data, sort_keys=True) +def IsValidSpreadsheetFormat(fmt): + """ Test if a file format specifier is in the valid list of spreadsheet file formats """ + + return fmt.lower() in ['csv', 'xls', 'xlsx', 'tsv'] + + +def MakeBomTemplate(fmt): + """ Generate a Bill of Materials upload template file (for user download) """ + + if not IsValidSpreadsheetFormat(fmt): + fmt = 'csv' + + fields = [ + 'Part', + 'Quantity', + 'Overage', + 'Reference', + 'Notes' + ] + + data = tablib.Dataset(headers=fields).export(fmt) + + filename = 'InvenTree_BOM_Template.' + fmt + + return DownloadFile(data, filename) + + def DownloadFile(data, filename, content_type='application/text'): """ Create a dynamic file for the user to download. diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index 4512859828..8c90de9dd2 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -8,6 +8,7 @@ from __future__ import unicode_literals from InvenTree.forms import HelperForm from django import forms +from django.core.validators import MinValueValidator from .models import Part, PartCategory, PartAttachment from .models import BomItem diff --git a/InvenTree/part/templates/part/bom_upload.html b/InvenTree/part/templates/part/bom_upload.html new file mode 100644 index 0000000000..b62cbc9c49 --- /dev/null +++ b/InvenTree/part/templates/part/bom_upload.html @@ -0,0 +1,13 @@ +{% extends "modal_form.html" %} + +{% block pre_form_content %} + +{{ block.super }} + +

Select a BOM file to upload for {{ part.name }} - {{ part.description }}.

+ +

The BOM file must contain the required named columns as provided in the BOM Upload Template

+ +

Supported file formats: .csv, .tsv, .xls, .xlsx

+ +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index a8f5184972..bfb542cb3f 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -74,6 +74,9 @@ part_urls = [ # Create a new BOM item url(r'^bom/new/?', views.BomItemCreate.as_view(), name='bom-item-create'), + # Download a BOM upload template + url(r'^bom_template/?', views.BomUploadTemplate.as_view(), name='bom-upload-template'), + # Individual part url(r'^(?P\d+)/', include(part_detail_urls)), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 08e3be79cb..1415547d86 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -12,6 +12,7 @@ from django.shortcuts import get_object_or_404 from django.utils.translation import gettext_lazy as _ from django.urls import reverse_lazy from django.views.generic import DetailView, ListView +from django.views.generic.edit import FormMixin from django.forms.models import model_to_dict from django.forms import HiddenInput, CheckboxInput @@ -26,7 +27,7 @@ from . import forms as part_forms from InvenTree.views import AjaxView, AjaxCreateView, AjaxUpdateView, AjaxDeleteView from InvenTree.views import QRCodeView -from InvenTree.helpers import DownloadFile, str2bool +from InvenTree.helpers import DownloadFile, str2bool, MakeBomTemplate from InvenTree.status_codes import OrderStatus @@ -722,6 +723,17 @@ class BomUpload(AjaxView): } return self.renderJsonResponse(request, form, data=data) +class BomUploadTemplate(AjaxView): + """ + Provide a BOM upload template file for download. + - Generates a template file in the provided format e.g. ?format=csv + """ + + def get(self, request, *args, **kwargs): + + export_format = request.GET.get('format', 'csv') + + return MakeBomTemplate(export_format) class BomDownload(AjaxView):