mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Getting there...
This commit is contained in:
parent
6e269ae41a
commit
fbf24621f3
@ -107,6 +107,8 @@ class MatchItem(forms.Form):
|
|||||||
|
|
||||||
if 'row_data' in kwargs:
|
if 'row_data' in kwargs:
|
||||||
row_data = kwargs.pop('row_data')
|
row_data = kwargs.pop('row_data')
|
||||||
|
else:
|
||||||
|
row_data = None
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
@ -115,44 +117,46 @@ class MatchItem(forms.Form):
|
|||||||
# Get columns
|
# Get columns
|
||||||
columns = file_manager.columns()
|
columns = file_manager.columns()
|
||||||
|
|
||||||
# Create fields
|
if row_data:
|
||||||
# Item selection
|
# Create fields
|
||||||
for row in row_data:
|
for row in row_data:
|
||||||
for col in row['data']:
|
for col in row['data']:
|
||||||
if col['column']['guess'] in file_manager.REQUIRED_HEADERS:
|
# print(f"{col=}")
|
||||||
field_name = col['column']['guess'].lower() + '-' + str(row['index'] - 1)
|
if col['column']['guess'] in file_manager.REQUIRED_HEADERS:
|
||||||
if 'quantity' in col['column']['guess'].lower():
|
field_name = col['column']['guess'].lower() + '-' + str(row['index'])
|
||||||
self.fields[field_name] = forms.CharField(
|
if 'quantity' in col['column']['guess'].lower():
|
||||||
required=True,
|
self.fields[field_name] = forms.CharField(
|
||||||
widget=forms.NumberInput(attrs={
|
required=True,
|
||||||
'name': 'quantity' + str(row['index']),
|
widget=forms.NumberInput(attrs={
|
||||||
'class': 'numberinput',
|
'name': 'quantity' + str(row['index']),
|
||||||
'type': 'number',
|
'class': 'numberinput',
|
||||||
'min': '1',
|
'type': 'number',
|
||||||
'step': 'any',
|
'min': '0',
|
||||||
'value': row['quantity'],
|
'step': 'any',
|
||||||
})
|
'value': row['quantity'],
|
||||||
)
|
})
|
||||||
else:
|
)
|
||||||
self.fields[field_name] = forms.Input(
|
else:
|
||||||
|
self.fields[field_name] = forms.Input(
|
||||||
|
required=True,
|
||||||
|
widget=forms.Select(attrs={
|
||||||
|
})
|
||||||
|
)
|
||||||
|
elif col['column']['guess'] in file_manager.ITEM_MATCH_HEADERS:
|
||||||
|
# print(f'{row["index"]=} | {col["column"]["guess"]=} | {row.get("item_match", "No Match")}')
|
||||||
|
|
||||||
|
# Get item options
|
||||||
|
item_options = [(option.id, option) for option in row['item_options']]
|
||||||
|
# Get item match
|
||||||
|
item_match = row['item_match']
|
||||||
|
|
||||||
|
field_name = col['column']['guess'].lower() + '-' + str(row['index'])
|
||||||
|
self.fields[field_name] = forms.ChoiceField(
|
||||||
|
choices=[('', '-' * 10)] + item_options,
|
||||||
required=True,
|
required=True,
|
||||||
widget=forms.Select(attrs={
|
widget=forms.Select(attrs={
|
||||||
|
'class': 'select bomselect',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
elif col['column']['guess'] in file_manager.ITEM_MATCH_HEADERS:
|
if item_match:
|
||||||
print(f'{row["index"]=} | {col["column"]["guess"]=} | {row.get("item_match", "No Match")}')
|
self.fields[field_name].initial = item_match.id
|
||||||
|
|
||||||
# Get item options
|
|
||||||
item_options = [(option.id, option) for option in row['item_options']]
|
|
||||||
# Get item match
|
|
||||||
item_match = row['item_match']
|
|
||||||
|
|
||||||
field_name = col['column']['guess'].lower() + '-' + str(row['index'] - 1)
|
|
||||||
self.fields[field_name] = forms.ChoiceField(
|
|
||||||
choices=[('', '-' * 10)] + item_options,
|
|
||||||
required=True,
|
|
||||||
widget=forms.Select(attrs={'class': 'bomselect'})
|
|
||||||
)
|
|
||||||
if item_match:
|
|
||||||
print(f'{item_match=}')
|
|
||||||
self.fields[field_name].initial = item_match.id
|
|
||||||
|
@ -197,66 +197,24 @@ class FileManagementFormView(MultiStepFormView):
|
|||||||
|
|
||||||
if self.steps.current == 'fields' or self.steps.current == 'items':
|
if self.steps.current == 'fields' or self.steps.current == 'items':
|
||||||
# Get columns and row data
|
# Get columns and row data
|
||||||
columns = self.file_manager.columns()
|
self.columns = self.file_manager.columns()
|
||||||
rows = self.file_manager.rows()
|
self.rows = self.file_manager.rows()
|
||||||
|
# Set form table data
|
||||||
|
self.set_form_table_data(form=form)
|
||||||
|
|
||||||
key_item_select = ''
|
# if self.steps.current == 'items':
|
||||||
key_quantity_select = ''
|
# for row in self.rows:
|
||||||
if self.steps.current == 'items':
|
# print(f'{row=}')
|
||||||
# Get file manager
|
context.update({'rows': self.rows})
|
||||||
self.getFileManager()
|
context.update({'columns': self.columns})
|
||||||
# Find column key for item selection
|
|
||||||
for item in self.file_manager.ITEM_MATCH_HEADERS:
|
|
||||||
item = item.lower()
|
|
||||||
for key in form.fields.keys():
|
|
||||||
print(f'{item=} is in {key=} ?')
|
|
||||||
if item in key:
|
|
||||||
key_item_select = item
|
|
||||||
break
|
|
||||||
break
|
|
||||||
|
|
||||||
# Find column key for quantity selection
|
|
||||||
key_quantity_select = 'quantity'
|
|
||||||
|
|
||||||
# Optimize for template
|
|
||||||
for row in rows:
|
|
||||||
|
|
||||||
# Add item select field
|
|
||||||
if key_item_select:
|
|
||||||
row['item_select'] = key_item_select + '-' + str(row['index'])
|
|
||||||
print(f'{row["item_select"]}')
|
|
||||||
# Add quantity select field
|
|
||||||
if key_quantity_select:
|
|
||||||
row['quantity_select'] = key_quantity_select + '-' + str(row['index'])
|
|
||||||
|
|
||||||
row_data = row['data']
|
|
||||||
|
|
||||||
data = []
|
|
||||||
|
|
||||||
for idx, item in enumerate(row_data):
|
|
||||||
data.append({
|
|
||||||
'cell': item,
|
|
||||||
'idx': idx,
|
|
||||||
'column': columns[idx],
|
|
||||||
})
|
|
||||||
|
|
||||||
row['data'] = data
|
|
||||||
|
|
||||||
print(f'\n{row=}')
|
|
||||||
|
|
||||||
context.update({'rows': rows})
|
|
||||||
if self.steps.current == 'items':
|
|
||||||
context.update({'columns': columns})
|
|
||||||
|
|
||||||
# Load extra context data
|
# Load extra context data
|
||||||
print(f'{self.extra_context_data=}')
|
|
||||||
for key, items in self.extra_context_data.items():
|
for key, items in self.extra_context_data.items():
|
||||||
context.update({key: items})
|
context.update({key: items})
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def getFileManager(self, step=None, form=None):
|
def get_file_manager(self, step=None, form=None):
|
||||||
""" Get FileManager instance from uploaded file """
|
""" Get FileManager instance from uploaded file """
|
||||||
|
|
||||||
if self.file_manager:
|
if self.file_manager:
|
||||||
@ -274,10 +232,8 @@ class FileManagementFormView(MultiStepFormView):
|
|||||||
def get_form_kwargs(self, step=None):
|
def get_form_kwargs(self, step=None):
|
||||||
""" Update kwargs to dynamically build forms """
|
""" Update kwargs to dynamically build forms """
|
||||||
|
|
||||||
print(f'[STEP] {step}')
|
|
||||||
|
|
||||||
# Always retrieve FileManager instance from uploaded file
|
# Always retrieve FileManager instance from uploaded file
|
||||||
self.getFileManager(step)
|
self.get_file_manager(step)
|
||||||
|
|
||||||
if step == 'upload':
|
if step == 'upload':
|
||||||
# Dynamically build upload form
|
# Dynamically build upload form
|
||||||
@ -296,14 +252,25 @@ class FileManagementFormView(MultiStepFormView):
|
|||||||
# Dynamically build match item form
|
# Dynamically build match item form
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
kwargs['file_manager'] = self.file_manager
|
kwargs['file_manager'] = self.file_manager
|
||||||
self.getFieldSelections()
|
|
||||||
|
# Get data from fields step
|
||||||
|
data = self.storage.get_step_data('fields')
|
||||||
|
|
||||||
|
# Process to update columns and rows
|
||||||
|
self.rows = self.file_manager.rows()
|
||||||
|
self.columns = self.file_manager.columns()
|
||||||
|
self.get_form_table_data(data)
|
||||||
|
self.set_form_table_data()
|
||||||
|
self.get_field_selection()
|
||||||
|
|
||||||
kwargs['row_data'] = self.rows
|
kwargs['row_data'] = self.rows
|
||||||
|
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
return super().get_form_kwargs()
|
return super().get_form_kwargs()
|
||||||
|
|
||||||
def getFormTableData(self, form_data):
|
def get_form_table_data(self, form_data):
|
||||||
""" Extract table cell data from form data.
|
""" Extract table cell data from form data and fields.
|
||||||
These data are used to maintain state between sessions.
|
These data are used to maintain state between sessions.
|
||||||
|
|
||||||
Table data keys are as follows:
|
Table data keys are as follows:
|
||||||
@ -314,18 +281,15 @@ class FileManagementFormView(MultiStepFormView):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Store extra context data
|
|
||||||
self.extra_context_data = {}
|
|
||||||
|
|
||||||
# Map the columns
|
# Map the columns
|
||||||
self.column_names = {}
|
self.column_names = {}
|
||||||
self.column_selections = {}
|
self.column_selections = {}
|
||||||
|
|
||||||
self.row_data = {}
|
self.row_data = {}
|
||||||
|
|
||||||
for item in form_data:
|
for item, value in form_data.items():
|
||||||
# print(f'{item} | {form_data[item]} | {type(form_data[item])}')
|
# print(f'{item} | {form_data[item]} | {type(form_data[item])}')
|
||||||
value = form_data[item]
|
# value = form.data[item]
|
||||||
|
|
||||||
# Column names as passed as col_name_<idx> where idx is an integer
|
# Column names as passed as col_name_<idx> where idx is an integer
|
||||||
|
|
||||||
@ -368,79 +332,85 @@ class FileManagementFormView(MultiStepFormView):
|
|||||||
|
|
||||||
# TODO: this is a hack
|
# TODO: this is a hack
|
||||||
value = value.replace("'", '"')
|
value = value.replace("'", '"')
|
||||||
self.row_data[row_id][col_id] = ast.literal_eval(value)
|
# print(f'{type(value)=} | {value=}')
|
||||||
|
try:
|
||||||
|
self.row_data[row_id][col_id] = ast.literal_eval(value)
|
||||||
|
except (ValueError, SyntaxError):
|
||||||
|
pass
|
||||||
|
|
||||||
# self.col_ids = sorted(self.column_names.keys())
|
def set_form_table_data(self, form=None):
|
||||||
|
if self.row_data:
|
||||||
|
# Re-construct the row data
|
||||||
|
self.rows = []
|
||||||
|
|
||||||
# Re-construct the data table
|
for row_idx in sorted(self.row_data.keys()):
|
||||||
self.rows = []
|
row = self.row_data[row_idx]
|
||||||
|
items = []
|
||||||
|
|
||||||
for row_idx in sorted(self.row_data.keys()):
|
for col_idx in sorted(row.keys()):
|
||||||
row = self.row_data[row_idx]
|
|
||||||
items = []
|
|
||||||
|
|
||||||
for col_idx in sorted(row.keys()):
|
value = row[col_idx]
|
||||||
|
items.append(value)
|
||||||
|
|
||||||
value = row[col_idx]
|
self.rows.append({
|
||||||
items.append(value)
|
'index': row_idx,
|
||||||
|
'data': items,
|
||||||
|
'errors': {},
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
# Update the row data
|
||||||
|
for row in self.rows:
|
||||||
|
row_data = row['data']
|
||||||
|
|
||||||
self.rows.append({
|
data = []
|
||||||
'index': row_idx,
|
|
||||||
'data': items,
|
|
||||||
'errors': {},
|
|
||||||
})
|
|
||||||
|
|
||||||
# Construct the column data
|
for idx, item in enumerate(row_data):
|
||||||
self.columns = []
|
data.append({
|
||||||
|
'cell': item,
|
||||||
|
'idx': idx,
|
||||||
|
'column': self.columns[idx],
|
||||||
|
})
|
||||||
|
|
||||||
|
row['data'] = data
|
||||||
|
|
||||||
# Track any duplicate column selections
|
# In the item selection step: update row data to contain fields
|
||||||
duplicates = []
|
if form and self.steps.current == 'items':
|
||||||
|
key_item_select = ''
|
||||||
|
key_quantity_select = ''
|
||||||
|
|
||||||
for col in self.column_names:
|
# Find column key for item selection
|
||||||
|
for item in self.file_manager.ITEM_MATCH_HEADERS:
|
||||||
|
item = item.lower()
|
||||||
|
for key in form.fields.keys():
|
||||||
|
if item in key:
|
||||||
|
key_item_select = item
|
||||||
|
break
|
||||||
|
break
|
||||||
|
|
||||||
if col in self.column_selections:
|
# Find column key for quantity selection
|
||||||
guess = self.column_selections[col]
|
key_quantity_select = 'quantity'
|
||||||
else:
|
|
||||||
guess = None
|
|
||||||
|
|
||||||
header = ({
|
# Update row data
|
||||||
'name': self.column_names[col],
|
for row in self.rows:
|
||||||
'guess': guess
|
# Add item select field
|
||||||
})
|
if key_item_select:
|
||||||
|
row['item_select'] = key_item_select + '-' + str(row['index'])
|
||||||
|
# Add quantity select field
|
||||||
|
if key_quantity_select:
|
||||||
|
row['quantity_select'] = key_quantity_select + '-' + str(row['index'])
|
||||||
|
|
||||||
if guess:
|
if self.column_names:
|
||||||
n = list(self.column_selections.values()).count(self.column_selections[col])
|
# Re-construct the column data
|
||||||
if n > 1:
|
self.columns = []
|
||||||
header['duplicate'] = True
|
|
||||||
duplicates.append(col)
|
|
||||||
|
|
||||||
self.columns.append(header)
|
for key in self.column_names:
|
||||||
|
header = ({
|
||||||
|
'name': key,
|
||||||
|
'guess': self.column_selections[key],
|
||||||
|
})
|
||||||
|
self.columns.append(header)
|
||||||
|
|
||||||
# Are there any missing columns?
|
def get_column_index(self, name):
|
||||||
missing_columns = []
|
|
||||||
|
|
||||||
# Check that all required fields are present
|
|
||||||
for col in self.file_manager.REQUIRED_HEADERS:
|
|
||||||
if col not in self.column_selections.values():
|
|
||||||
missing_columns.append(col)
|
|
||||||
|
|
||||||
# Check that at least one of the part match field is present
|
|
||||||
part_match_found = False
|
|
||||||
for col in self.file_manager.ITEM_MATCH_HEADERS:
|
|
||||||
if col in self.column_selections.values():
|
|
||||||
part_match_found = True
|
|
||||||
break
|
|
||||||
|
|
||||||
# If not, notify user
|
|
||||||
if not part_match_found:
|
|
||||||
for col in self.file_manager.ITEM_MATCH_HEADERS:
|
|
||||||
missing_columns.append(col)
|
|
||||||
|
|
||||||
# Store extra context data
|
|
||||||
self.extra_context_data['missing_columns'] = missing_columns
|
|
||||||
self.extra_context_data['duplicates'] = duplicates
|
|
||||||
|
|
||||||
def getColumnIndex(self, name):
|
|
||||||
""" Return the index of the column with the given name.
|
""" Return the index of the column with the given name.
|
||||||
It named column is not found, return -1
|
It named column is not found, return -1
|
||||||
"""
|
"""
|
||||||
@ -452,7 +422,7 @@ class FileManagementFormView(MultiStepFormView):
|
|||||||
|
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
def getFieldSelections(self):
|
def get_field_selection(self):
|
||||||
""" Once data columns have been selected, attempt to pre-select the proper data from the database.
|
""" Once data columns have been selected, attempt to pre-select the proper data from the database.
|
||||||
This function is called once the field selection has been validated.
|
This function is called once the field selection has been validated.
|
||||||
The pre-fill data are then passed through to the part selection form.
|
The pre-fill data are then passed through to the part selection form.
|
||||||
@ -460,13 +430,14 @@ class FileManagementFormView(MultiStepFormView):
|
|||||||
|
|
||||||
match_supplier = False
|
match_supplier = False
|
||||||
match_manufacturer = False
|
match_manufacturer = False
|
||||||
|
self.allowed_items = None
|
||||||
|
|
||||||
# Fields prefixed with "Part_" can be used to do "smart matching" against Part objects in the database
|
# Fields prefixed with "Part_" can be used to do "smart matching" against Part objects in the database
|
||||||
q_idx = self.getColumnIndex('Quantity')
|
q_idx = self.get_column_index('Quantity')
|
||||||
s_idx = self.getColumnIndex('Supplier_SKU')
|
s_idx = self.get_column_index('Supplier_SKU')
|
||||||
m_idx = self.getColumnIndex('Manufacturer_MPN')
|
m_idx = self.get_column_index('Manufacturer_MPN')
|
||||||
# p_idx = self.getColumnIndex('Unit_Price')
|
# p_idx = self.get_column_index('Unit_Price')
|
||||||
# e_idx = self.getColumnIndex('Extended_Price')
|
# e_idx = self.get_column_index('Extended_Price')
|
||||||
|
|
||||||
for row in self.rows:
|
for row in self.rows:
|
||||||
|
|
||||||
@ -495,6 +466,7 @@ class FileManagementFormView(MultiStepFormView):
|
|||||||
|
|
||||||
# Check if there is a column corresponding to "Supplier SKU"
|
# Check if there is a column corresponding to "Supplier SKU"
|
||||||
if s_idx >= 0:
|
if s_idx >= 0:
|
||||||
|
print(f'{row["data"][s_idx]=}')
|
||||||
sku = row['data'][s_idx]['cell']
|
sku = row['data'][s_idx]['cell']
|
||||||
|
|
||||||
# Match for supplier
|
# Match for supplier
|
||||||
@ -536,22 +508,51 @@ class FileManagementFormView(MultiStepFormView):
|
|||||||
# If there is an exact match based on SKU or MPN, use that
|
# If there is an exact match based on SKU or MPN, use that
|
||||||
row['item_match'] = exact_match_part
|
row['item_match'] = exact_match_part
|
||||||
|
|
||||||
def checkFieldSelection(self, form):
|
def check_field_selection(self, form):
|
||||||
""" Check field matching """
|
""" Check field matching """
|
||||||
|
|
||||||
# Extract form data
|
# Are there any missing columns?
|
||||||
self.getFormTableData(form.data)
|
missing_columns = []
|
||||||
|
|
||||||
valid = len(self.extra_context_data.get('missing_columns', [])) == 0 and not self.extra_context_data.get('duplicates', [])
|
# Check that all required fields are present
|
||||||
|
for col in self.file_manager.REQUIRED_HEADERS:
|
||||||
|
if col not in self.column_selections.values():
|
||||||
|
missing_columns.append(col)
|
||||||
|
|
||||||
return valid
|
# Check that at least one of the part match field is present
|
||||||
|
part_match_found = False
|
||||||
|
for col in self.file_manager.ITEM_MATCH_HEADERS:
|
||||||
|
if col in self.column_selections.values():
|
||||||
|
part_match_found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# If not, notify user
|
||||||
|
if not part_match_found:
|
||||||
|
for col in self.file_manager.ITEM_MATCH_HEADERS:
|
||||||
|
missing_columns.append(col)
|
||||||
|
|
||||||
def checkPartSelection(self, form):
|
# Track any duplicate column selections
|
||||||
""" Check part matching """
|
duplicates = []
|
||||||
|
|
||||||
# Extract form data
|
for col in self.column_names:
|
||||||
self.getFormTableData(form.data)
|
|
||||||
|
|
||||||
|
if col in self.column_selections:
|
||||||
|
guess = self.column_selections[col]
|
||||||
|
else:
|
||||||
|
guess = None
|
||||||
|
|
||||||
|
if guess:
|
||||||
|
n = list(self.column_selections.values()).count(self.column_selections[col])
|
||||||
|
if n > 1:
|
||||||
|
duplicates.append(col)
|
||||||
|
|
||||||
|
# Store extra context data
|
||||||
|
self.extra_context_data = {
|
||||||
|
'missing_columns': missing_columns,
|
||||||
|
'duplicates': duplicates,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Data validation
|
||||||
valid = len(self.extra_context_data.get('missing_columns', [])) == 0 and not self.extra_context_data.get('duplicates', [])
|
valid = len(self.extra_context_data.get('missing_columns', [])) == 0 and not self.extra_context_data.get('duplicates', [])
|
||||||
|
|
||||||
return valid
|
return valid
|
||||||
@ -559,24 +560,20 @@ class FileManagementFormView(MultiStepFormView):
|
|||||||
def validate(self, step, form):
|
def validate(self, step, form):
|
||||||
""" Validate forms """
|
""" Validate forms """
|
||||||
|
|
||||||
valid = False
|
valid = True
|
||||||
|
|
||||||
# Process steps
|
# Get form table data
|
||||||
if step == 'upload':
|
self.get_form_table_data(form.data)
|
||||||
# Validation is done during POST
|
|
||||||
valid = True
|
if step == 'fields':
|
||||||
elif step == 'fields':
|
|
||||||
# Validate user form data
|
# Validate user form data
|
||||||
valid = self.checkFieldSelection(form)
|
valid = self.check_field_selection(form)
|
||||||
|
|
||||||
if not valid:
|
if not valid:
|
||||||
form.add_error(None, 'Fields matching failed')
|
form.add_error(None, 'Fields matching failed')
|
||||||
|
|
||||||
elif step == 'items':
|
elif step == 'items':
|
||||||
valid = self.checkPartSelection(form)
|
pass
|
||||||
|
|
||||||
if not valid:
|
|
||||||
form.add_error(None, 'Items matching failed')
|
|
||||||
|
|
||||||
return valid
|
return valid
|
||||||
|
|
||||||
@ -593,5 +590,4 @@ class FileManagementFormView(MultiStepFormView):
|
|||||||
# Re-render same step
|
# Re-render same step
|
||||||
return self.render(form)
|
return self.render(form)
|
||||||
|
|
||||||
print('\nPosting... ')
|
|
||||||
return super().post(*args, **kwargs)
|
return super().post(*args, **kwargs)
|
||||||
|
@ -54,12 +54,6 @@
|
|||||||
{% for col in form %}
|
{% for col in form %}
|
||||||
<td>
|
<td>
|
||||||
{{ col }}
|
{{ col }}
|
||||||
{% comment %} <select class='select' id='id_col_{{ forloop.counter0 }}' name='col_guess_{{ forloop.counter0 }}'>
|
|
||||||
<option value=''>---------</option>
|
|
||||||
{% for req in headers %}
|
|
||||||
<option value='{{ req }}'{% if req == col.guess %}selected='selected'{% endif %}>{{ req }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select> {% endcomment %}
|
|
||||||
{% for duplicate in duplicates %}
|
{% for duplicate in duplicates %}
|
||||||
{% if duplicate == col.name %}
|
{% if duplicate == col.name %}
|
||||||
<div class='alert alert-danger alert-block text-center' role='alert' style='padding:2px; margin-top:6px; margin-bottom:2px'>
|
<div class='alert alert-danger alert-block text-center' role='alert' style='padding:2px; margin-top:6px; margin-bottom:2px'>
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for row in rows %}
|
{% for row in rows %}
|
||||||
<tr {% if row.errors %} style='background: #ffeaea;'{% endif %} part-name='{{ row.part_name }}' part-description='{{ row.description }}' part-select='#select_part_{{ row.index }}'>
|
<tr {% if row.errors %} style='background: #ffeaea;'{% endif %} part-select='#select_part_{{ row.index }}'>
|
||||||
<td>
|
<td>
|
||||||
<button class='btn btn-default btn-remove' onClick='removeRowFromBomWizard()' id='del_row_{{ forloop.counter }}' style='display: inline; float: right;' title='{% trans "Remove row" %}'>
|
<button class='btn btn-default btn-remove' onClick='removeRowFromBomWizard()' id='del_row_{{ forloop.counter }}' style='display: inline; float: right;' title='{% trans "Remove row" %}'>
|
||||||
<span row_id='{{ forloop.counter }}' class='fas fa-trash-alt icon-red'></span>
|
<span row_id='{{ forloop.counter }}' class='fas fa-trash-alt icon-red'></span>
|
||||||
@ -51,26 +51,14 @@
|
|||||||
{% add row.index 1 %}
|
{% add row.index 1 %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button class='btn btn-default btn-create' onClick='newPartFromBomWizard()' id='new_part_row_{{ row.index }}' title='{% trans "Create new part" %}' type='button'>
|
|
||||||
<span row_id='{{ row.index }}' class='fas fa-plus icon-green'/>
|
|
||||||
</button>
|
|
||||||
{% for field in form.visible_fields %}
|
{% for field in form.visible_fields %}
|
||||||
{% if field.name == row.item_select %}
|
{% if field.name == row.item_select %}
|
||||||
{{ field }}
|
{{ field }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% comment %}
|
|
||||||
<select class='select bomselect' id='select_part_{{ row.index }}' name='part_{{ row.index }}'>
|
|
||||||
<option value=''>--- {% trans "Select Part" %} ---</option>
|
|
||||||
{% for part in row.part_options %}
|
|
||||||
<option value='{{ part.id }}' {% if part.id == row.part.id %} selected='selected' {% elif part.id == row.part_match.id %} selected='selected' {% endif %}>
|
|
||||||
{{ part }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
{% if row.errors.part %}
|
{% if row.errors.part %}
|
||||||
<p class='help-inline'>{{ row.errors.part }}</p>
|
<p class='help-inline'>{{ row.errors.part }}</p>
|
||||||
{% endif %} {% endcomment %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
{% for item in row.data %}
|
{% for item in row.data %}
|
||||||
<td>
|
<td>
|
||||||
@ -80,7 +68,6 @@
|
|||||||
{{ field }}
|
{{ field }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% comment %} <input name='quantity_{{ row.index }}' class='numberinput' type='number' min='1' step='any' value='{% decimal row.quantity %}'/> {% endcomment %}
|
|
||||||
{% if row.errors.quantity %}
|
{% if row.errors.quantity %}
|
||||||
<p class='help-inline'>{{ row.errors.quantity }}</p>
|
<p class='help-inline'>{{ row.errors.quantity }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
Loading…
Reference in New Issue
Block a user