diff --git a/InvenTree/common/files.py b/InvenTree/common/files.py index 377120f44d..759ff04ee7 100644 --- a/InvenTree/common/files.py +++ b/InvenTree/common/files.py @@ -109,6 +109,27 @@ class FileManager: # Update headers self.update_headers() + if self.name == 'part': + self.REQUIRED_HEADERS = [ + 'Name', + 'Description', + ] + + self.OPTIONAL_HEADERS = [ + 'Keywords', + 'IPN', + 'Revision', + 'Link', + 'default_expiry', + 'minimum_stock', + 'Units', + 'Notes', + ] + + # Update headers + self.update_headers() + + def guess_header(self, header, threshold=80): """ Try to match a header (from the file) to a list of known headers diff --git a/InvenTree/part/templates/part/import_wizard/match_fields.html b/InvenTree/part/templates/part/import_wizard/match_fields.html new file mode 100644 index 0000000000..54008d6bae --- /dev/null +++ b/InvenTree/part/templates/part/import_wizard/match_fields.html @@ -0,0 +1,99 @@ +{% extends "part/import_wizard/part_upload.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} + +{% block form_alert %} +{% if missing_columns and missing_columns|length > 0 %} + +{% endif %} +{% if duplicates and duplicates|length > 0 %} + +{% endif %} +{% endblock form_alert %} + +{% block form_buttons_top %} + {% if wizard.steps.prev %} + + {% endif %} + +{% endblock form_buttons_top %} + +{% block form_content %} + + + {% trans "File Fields" %} + + {% for col in form %} + +
+ + {{ col.name }} + +
+ + {% endfor %} + + + + + {% trans "Match Fields" %} + + {% for col in form %} + + {{ col }} + {% for duplicate in duplicates %} + {% if duplicate == col.name %} + + {% endif %} + {% endfor %} + + {% endfor %} + + {% for row in rows %} + {% with forloop.counter as row_index %} + + + + + {{ row_index }} + {% for item in row.data %} + + + {{ item }} + + {% endfor %} + + {% endwith %} + {% endfor %} + +{% endblock form_content %} + +{% block form_buttons_bottom %} +{% endblock form_buttons_bottom %} + +{% block js_ready %} +{{ block.super }} + +$('.fieldselect').select2({ + width: '100%', + matcher: partialMatcher, +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/import_wizard/match_references.html b/InvenTree/part/templates/part/import_wizard/match_references.html new file mode 100644 index 0000000000..efc69b98d5 --- /dev/null +++ b/InvenTree/part/templates/part/import_wizard/match_references.html @@ -0,0 +1,90 @@ +{% extends "part/import_wizard/part_upload.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} + +{% block form_alert %} +{% if form.errors %} +{% endif %} +{% if form_errors %} + +{% endif %} +{% endblock form_alert %} + +{% block form_buttons_top %} + {% if wizard.steps.prev %} + + {% endif %} + +{% endblock form_buttons_top %} + +{% block form_content %} + + + + {% trans "Row" %} + {% for col in columns %} + + + + + {% if col.guess %} + {{ col.guess }} + {% else %} + {{ col.name }} + {% endif %} + + {% endfor %} + + + + {% comment %} Dummy row for javascript del_row method {% endcomment %} + {% for row in rows %} + + + + + + {% add row.index 1 %} + + {% for item in row.data %} + + {% if item.column.guess %} + {% with row_name=item.column.guess|lower %} + {% for field in form.visible_fields %} + {% if field.name == row|keyvalue:row_name %} + {{ field }} + {% endif %} + {% endfor %} + {% endwith %} + {% else %} + {{ item.cell }} + {% endif %} + + + {% endfor %} + + {% endfor %} + +{% endblock form_content %} + +{% block form_buttons_bottom %} +{% endblock form_buttons_bottom %} + +{% block js_ready %} +{{ block.super }} + +$('.bomselect').select2({ + dropdownAutoWidth: true, + matcher: partialMatcher, +}); + +$('.currencyselect').select2({ + dropdownAutoWidth: true, +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/import_wizard/part_upload.html b/InvenTree/part/templates/part/import_wizard/part_upload.html new file mode 100644 index 0000000000..87809603bb --- /dev/null +++ b/InvenTree/part/templates/part/import_wizard/part_upload.html @@ -0,0 +1,61 @@ +{% extends "part/category.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} + +{% block menubar %} +{% include 'part/category_navbar.html' with tab='import' %} +{% endblock %} + +{% block category_content %} +
+
+

+ {% trans "Import Parts from File" %} + {{ wizard.form.media }} +

+
+
+ {% if roles.part.change %} + +

{% blocktrans with step=wizard.steps.step1 count=wizard.steps.count %}Step {{step}} of {{count}}{% endblocktrans %} + {% if description %}- {{ description }}{% endif %}

+ + {% block form_alert %} + {% endblock form_alert %} + +
+ {% csrf_token %} + {% load crispy_forms_tags %} + + {% block form_buttons_top %} + {% endblock form_buttons_top %} + + + {{ wizard.management_form }} + {% block form_content %} + {% crispy wizard.form %} + {% endblock form_content %} +
+ + {% block form_buttons_bottom %} + {% if wizard.steps.prev %} + + {% endif %} + +
+ {% endblock form_buttons_bottom %} + + {% else %} + + {% endif %} +
+
+{% endblock %} + +{% block js_ready %} +{{ block.super }} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index d9b0b51693..1e19387e81 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -722,6 +722,31 @@ class PartCreate(AjaxCreateView): class PartImport(FileManagementFormView): ''' Part: Upload file, match to fields and import parts(using multi-Step form) ''' + name = 'part' + form_steps_template = [ + 'part/import_wizard/part_upload.html', + 'part/import_wizard/match_fields.html', + 'part/import_wizard/match_references.html', + ] + form_steps_description = [ + _("Upload File"), + _("Match Fields"), + _("Match References"), + ] + + form_field_map = { + 'name': 'name', + 'description': 'description', + 'keywords': 'keywords', + 'IPN': 'IPN', + 'revision': 'revision', + 'link': 'link', + 'default_expiry': 'default_expiry', + 'minimum_stock': 'minimum_stock', + 'units': 'units', + 'notes': 'notes', + } + class PartNotes(UpdateView): """ View for editing the 'notes' field of a Part object. Presents a live markdown editor.