diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index fb90547a04..c9c78eb46b 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -746,6 +746,13 @@ class BomExtractSerializer(serializers.Serializer): """ + class Meta: + fields = [ + 'bom_file', + 'part', + 'clear_existing', + ] + # These columns must be present REQUIRED_COLUMNS = [ 'quantity', @@ -940,16 +947,24 @@ class BomExtractSerializer(serializers.Serializer): 'filename': self.filename, } - class Meta: - fields = [ - 'bom_file', - ] + part = serializers.PrimaryKeyRelatedField(queryset=Part.objects.filter(assembly=True), required=True) + + clear_existing = serializers.BooleanField( + label=_("Clear Existing BOM"), + help_text=_("Delete existing BOM data first"), + ) def save(self): - """ - There is no action associated with "saving" this serializer - """ - pass + + data = self.validated_data + + master_part = data['part'] + clear_existing = data['clear_existing'] + + if clear_existing: + + # Remove all existing BOM items + master_part.bom_items.all().delete() class BomUploadSerializer(serializers.Serializer): @@ -963,13 +978,14 @@ class BomUploadSerializer(serializers.Serializer): def validate(self, data): - data = super().validate(data) items = data['items'] if len(items) == 0: raise serializers.ValidationError(_("At least one BOM item is required")) + data = super().validate(data) + return data def save(self): diff --git a/InvenTree/templates/js/translated/bom.js b/InvenTree/templates/js/translated/bom.js index d5391ab70a..c80f9a2694 100644 --- a/InvenTree/templates/js/translated/bom.js +++ b/InvenTree/templates/js/translated/bom.js @@ -112,7 +112,7 @@ function constructBomUploadTable(data, options={}) { // Add callback for "remove row" button $(`#button-row-remove-${idx}`).click(function() { - $(`#bom_import_row_${idx}`).remove(); + $(`#items_${idx}`).remove(); }); } @@ -172,22 +172,36 @@ function submitBomTable(part_id, options={}) { getApiEndpointOptions(url, function(response) { var fields = response.actions.POST; - inventreePut(url, data, { + constructForm(url, { method: 'POST', - success: function(response) { - // TODO: Return to the "bom" page - }, - error: function(xhr) { - switch (xhr.status) { - case 400: - handleFormErrors(xhr.responseJSON, fields, options); - break; - default: - showApiError(xhr, url); - break; - } + fields: { + clear_existing: {}, + }, + title: '{% trans "Submit BOM Data" %}', + onSubmit: function(fields, opts) { + + data.clear_existing = getFormFieldValue('clear_existing', {}, opts); + + $(opts.modal).modal('hide'); + + inventreePut(url, data, { + method: 'POST', + success: function(response) { + // TODO: Return to the "bom" page + }, + error: function(xhr) { + switch (xhr.status) { + case 400: + handleFormErrors(xhr.responseJSON, fields, options); + break; + default: + showApiError(xhr, url); + break; + } + } + }); } - }); + }); }); } diff --git a/InvenTree/templates/js/translated/forms.js b/InvenTree/templates/js/translated/forms.js index 2742e3f0ca..fe912b3358 100644 --- a/InvenTree/templates/js/translated/forms.js +++ b/InvenTree/templates/js/translated/forms.js @@ -1059,6 +1059,28 @@ function handleNestedErrors(errors, field_name, options={}) { var errors = error_item[sub_field_name]; + if (sub_field_name == 'non_field_errors') { + + var row = null; + + if (options.modal) { + row = $(options.modal).find(`#items_${nest_id}`); + } else { + row = $(`#items_${nest_id}`); + } + + for (var ii = errors.length - 1; ii >= 0; ii--) { + + var html = ` +
+ ${errors[ii]} +
`; + + row.after(html); + } + + } + // Find the target (nested) field var target = `${field_name}_${sub_field_name}_${nest_id}`;