Pass file data through to the next form page

This commit is contained in:
Oliver Walters 2019-06-27 23:49:01 +10:00
parent a9396f4c74
commit 4648db6ce5
6 changed files with 161 additions and 42 deletions

View File

@ -59,15 +59,8 @@ class BomUploadManager:
'Notes' 'Notes'
] ]
def __init__(self, bom_file, starting_row=2): def __init__(self, bom_file):
""" Initialize the BomUpload class with a user-uploaded file object """ """ Initialize the BomUpload class with a user-uploaded file object """
try:
start = int(starting_row) - 1
if start < 0:
start = 0
self.starting_row = start
except ValueError:
self.starting_row = 1
self.process(bom_file) self.process(bom_file)
@ -154,6 +147,20 @@ class BomUploadManager:
return None return None
def get_headers(self):
""" Return a list of headers for the thingy """
headers = []
return headers
def col_count(self):
if self.data is None:
return 0
return len(self.data.headers)
def row_count(self): def row_count(self):
""" Return the number of rows in the file. """ Return the number of rows in the file.
Ignored the top rows as indicated by 'starting row' Ignored the top rows as indicated by 'starting row'
@ -162,16 +169,30 @@ class BomUploadManager:
if self.data is None: if self.data is None:
return 0 return 0
# Limit the number of BOM lines to be sensible return len(self.data)
count = min(len(self.data) - self.starting_row, 1000)
return count def rows(self):
""" Return a list of all rows """
rows = []
def get_row(self, index): for i in range(self.row_count()):
row = self.get_row_data(i)
if row:
rows.append(row)
return rows
def get_row_data(self, index):
""" Retrieve row data at a particular index """
if self.data is None or index >= len(self.data):
return None
return self.data[index]
def get_row_dict(self, index):
""" Retrieve a dict object representing the data row at a particular offset """ """ Retrieve a dict object representing the data row at a particular offset """
index += self.starting_row
if self.data is None or index >= len(self.data): if self.data is None or index >= len(self.data):
return None return None

View File

@ -39,25 +39,29 @@ class BomValidateForm(HelperForm):
] ]
class BomImportForm(HelperForm): class BomUploadSelectFile(HelperForm):
""" Form for importing a BOM. Provides a file input box for upload """ """ Form for importing a BOM. Provides a file input box for upload """
bom_file = forms.FileField(label='BOM file', required=True, help_text="Select BOM file to upload") bom_file = forms.FileField(label='BOM file', required=True, help_text="Select BOM file to upload")
starting_row = forms.IntegerField(
required=True,
initial=2,
help_text='First row containing valid BOM data',
validators=[
MinValueValidator(1)
]
)
class Meta: class Meta:
model = Part model = Part
fields = [ fields = [
'bom_file', 'bom_file',
]
class BomUploadSelectFields(HelperForm):
""" Form for selecting BOM fields """
starting_row = forms.IntegerField(required=True, initial=2, help_text='Index of starting row', validators=[MinValueValidator(1)])
row_count = forms.IntegerField(required=True, help_text='Number of rows to process', validators=[MinValueValidator(0)])
class Meta:
model = Part
fields = [
'starting_row', 'starting_row',
'row_count',
] ]

View File

@ -0,0 +1,38 @@
{% extends "modal_form.html" %}
{% load inventree_extras %}
{% block form %}
<h4>Step 2 of 3 - Select BOM Fields</h4>
<form method="post" action='' class='js-modal-form' enctype="multipart/form-data">
{% csrf_token %}
{% load crispy_forms_tags %}
{% crispy form %}
<input type='hidden' name='form_step' value='select_fields'/>
<table class='table table-striped'>
<thead>
<tr>
</tr>
</thead>
<tbody>
{% for row in bom.rows %}
<tr>
{% for item in row %}
<td>
{{ item }}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</form>
<b>BOM Rows: {{ bom.row_count }}</b>
{% endblock %}

View File

@ -2,9 +2,13 @@
{% block pre_form_content %} {% block pre_form_content %}
<h4>Step 1 of 3 - Select BOM File</h4>
{{ block.super }} {{ block.super }}
<p>Select a BOM file to upload for <b>{{ part.name }} - <i>{{ part.description }}</i></b>.</p> <p>Select a BOM file to upload for:<br>
<b>{{ part.name }} - <i>{{ part.description }}</i></b>
</p>
<p>The BOM file must contain the required named columns as provided in the <a href="/part/bom_template/">BOM Upload Template</a></a></p> <p>The BOM file must contain the required named columns as provided in the <a href="/part/bom_template/">BOM Upload Template</a></a></p>
@ -15,3 +19,7 @@
</ul> </ul>
{% endblock %} {% endblock %}
{% block form_data %}
<input type='hidden' name='form_step' value='select_file'/>
{% endblock %}

View File

@ -8,6 +8,11 @@ from InvenTree import version
register = template.Library() register = template.Library()
@register.simple_tag()
def inrange(n, *args, **kwargs):
""" Return range(n) for iterating through a numeric quantity """
return range(n)
@register.simple_tag() @register.simple_tag()
def multiply(x, y, *args, **kwargs): def multiply(x, y, *args, **kwargs):
""" Multiply two numbers together """ """ Multiply two numbers together """

View File

@ -650,8 +650,17 @@ class BomUpload(AjaxView, FormMixin):
""" """
ajax_form_title = 'Upload Bill of Materials' ajax_form_title = 'Upload Bill of Materials'
ajax_template_name = 'part/bom_upload.html' ajax_template_name = 'part/bom_upload/select_file.html'
form_class = part_forms.BomImportForm
def get_form_class(self):
form_step = self.request.POST.get('form_step', None)
if form_step == 'select_fields':
return part_forms.BomUploadSelectFields
else:
# Default form is the starting point
return part_forms.BomUploadSelectFile
def get_context_data(self): def get_context_data(self):
ctx = { ctx = {
@ -674,24 +683,54 @@ class BomUpload(AjaxView, FormMixin):
return self.renderJsonResponse(request, self.form) return self.renderJsonResponse(request, self.form)
def handleBomFileUpload(self, bom_file): def handleBomFileUpload(self):
bom_file = self.request.FILES.get('bom_file', None)
manager = None
bom_file_valid = False
if bom_file is None:
self.form.errors['bom_file'] = [_('No BOM file provided')]
else:
# Create a BomUploadManager object - will perform initial data validation
# (and raise a ValidationError if there is something wrong with the file)
try:
manager = BomUploadManager(bom_file)
bom_file_valid = True
except ValidationError as e:
errors = e.error_dict
for k,v in errors.items():
self.form.errors[k] = v
data = { data = {
# TODO - Validate the form if there isn't actually an error!
'form_valid': False 'form_valid': False
} }
# Create a BomUploadManager object - will perform initial data validation ctx = {}
# (and raise a ValidationError if there is something wrong with the file)
try:
manager = BomUploadManager(bom_file, self.form['starting_row'].value())
except ValidationError as e:
errors = e.error_dict
for k,v in errors.items(): if bom_file_valid:
self.form.errors[k] = v # BOM file is valid? Proceed to the next step!
form = part_forms.BomUploadSelectFields
self.ajax_template_name = 'part/bom_upload/select_fields.html'
ctx['bom'] = manager
else:
form = self.form
return self.renderJsonResponse(self.request, self.form, data=data) return self.renderJsonResponse(self.request, form, data=data, context=ctx)
def handleFieldSelection(self):
data = {
'form_valid': False,
}
self.ajax_template_name = 'part/bom_upload/select_fields.html'
ctx = {}
return self.renderJsonResponse(self.request, form=self.get_form(), data=data, context=ctx)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
""" Perform the various 'POST' requests required. """ Perform the various 'POST' requests required.
@ -703,10 +742,14 @@ class BomUpload(AjaxView, FormMixin):
self.form = self.get_form() self.form = self.get_form()
# Did the user POST a file named bom_file? # Did the user POST a file named bom_file?
bom_file = request.FILES.get('bom_file', None)
if bom_file:
return self.handleBomFileUpload(bom_file) form_step = request.POST.get('form_step', None)
if form_step == 'select_file':
return self.handleBomFileUpload()
elif form_step == 'select_fields':
return self.handleFieldSelection()
data = { data = {
'form_valid': False, 'form_valid': False,