From 2c0da25cbc9e123f4b108295d4a5836cb374ddcb Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 21 Dec 2021 22:45:59 +1100 Subject: [PATCH] "Validate BOM" now uses the API also --- InvenTree/part/api.py | 57 ++++++++++++++++++- InvenTree/part/forms.py | 15 ----- .../part/templates/part/bom_validate.html | 12 ---- InvenTree/part/templates/part/detail.html | 10 ++-- InvenTree/part/urls.py | 1 - InvenTree/part/views.py | 42 -------------- InvenTree/templates/js/translated/api.js | 5 ++ InvenTree/templates/js/translated/part.js | 28 ++++++++- 8 files changed, 91 insertions(+), 79 deletions(-) delete mode 100644 InvenTree/part/templates/part/bom_validate.html diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 8f31eb0b77..0625a717a5 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -474,6 +474,56 @@ class PartCopyBOM(generics.CreateAPIView): return ctx +class PartValidateBOM(generics.RetrieveUpdateAPIView): + """ + API endpoint for 'validating' the BOM for a given Part + """ + + class BOMValidateSerializer(serializers.ModelSerializer): + + class Meta: + model = Part + fields = [ + 'checksum', + 'valid', + ] + + checksum = serializers.CharField( + read_only=True, + source='bom_checksum', + ) + + valid = serializers.BooleanField( + write_only=True, + default=False, + label=_('Valid'), + help_text=_('Validate entire Bill of Materials'), + ) + + def validate_valid(self, valid): + if not valid: + raise ValidationError(_('This option must be selected')) + + queryset = Part.objects.all() + + serializer_class = BOMValidateSerializer + + def update(self, request, *args, **kwargs): + + part = self.get_object() + + partial = kwargs.pop('partial', False) + + serializer = self.get_serializer(part, data=request.data, partial=partial) + serializer.is_valid(raise_exception=True) + + part.validate_bom(request.user) + + return Response({ + 'checksum': part.bom_checksum, + }) + + class PartDetail(generics.RetrieveUpdateDestroyAPIView): """ API endpoint for detail view of a single Part object """ @@ -1605,8 +1655,11 @@ part_api_urls = [ # Endpoint for extra serial number information url(r'^serial-numbers/', PartSerialNumberDetail.as_view(), name='api-part-serial-number-detail'), - # Endpoint for duplicating a BOM - url(r'^copy-bom/', PartCopyBOM.as_view(), name='api-part-copy-bom'), + # Endpoint for duplicating a BOM for the specific Part + url(r'^bom-copy/', PartCopyBOM.as_view(), name='api-part-bom-copy'), + + # Endpoint for validating a BOM for the specific Part + url(r'^bom-validate/', PartValidateBOM.as_view(), name='api-part-bom-validate'), # Part detail endpoint url(r'^.*$', PartDetail.as_view(), name='api-part-detail'), diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index 5afd037c63..c4c7d29228 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -55,21 +55,6 @@ class PartImageDownloadForm(HelperForm): ] -class BomValidateForm(HelperForm): - """ Simple confirmation form for BOM validation. - User is presented with a single checkbox input, - to confirm that the BOM for this part is valid - """ - - validate = forms.BooleanField(required=False, initial=False, label=_('validate'), help_text=_('Confirm that the BOM is correct')) - - class Meta: - model = Part - fields = [ - 'validate' - ] - - class BomMatchItemForm(MatchItemForm): """ Override MatchItemForm fields """ diff --git a/InvenTree/part/templates/part/bom_validate.html b/InvenTree/part/templates/part/bom_validate.html deleted file mode 100644 index 3554f9c56a..0000000000 --- a/InvenTree/part/templates/part/bom_validate.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "modal_form.html" %} - -{% load i18n %} - -{% block pre_form_content %} -{% blocktrans with part.full_name as part %}Confirm that the Bill of Materials (BOM) is valid for:
{{ part }}{% endblocktrans %} - -
- {% trans 'This will validate each line in the BOM.' %} -
- -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index c768c61257..63bd747d0c 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -609,12 +609,10 @@ }); $("#validate-bom").click(function() { - launchModalForm( - "{% url 'bom-validate' part.id %}", - { - reload: true, - } - ); + + validateBom({{ part.id }}, { + reload: true + }); }); $("#download-bom").click(function () { diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index a10da3f587..14f3e28b24 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -35,7 +35,6 @@ part_detail_urls = [ url(r'^delete/?', views.PartDelete.as_view(), name='part-delete'), url(r'^bom-export/?', views.BomExport.as_view(), name='bom-export'), url(r'^bom-download/?', views.BomDownload.as_view(), name='bom-download'), - url(r'^validate-bom/', views.BomValidate.as_view(), name='bom-validate'), url(r'^pricing/', views.PartPricing.as_view(), name='part-pricing'), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 2aa2d5324a..4304d2a95d 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -694,48 +694,6 @@ class PartImageSelect(AjaxUpdateView): return self.renderJsonResponse(request, form, data) -class BomValidate(AjaxUpdateView): - """ - Modal form view for validating a part BOM - """ - - model = Part - ajax_form_title = _("Validate BOM") - ajax_template_name = 'part/bom_validate.html' - context_object_name = 'part' - form_class = part_forms.BomValidateForm - - def get_context(self): - return { - 'part': self.get_object(), - } - - def get(self, request, *args, **kwargs): - - form = self.get_form() - - return self.renderJsonResponse(request, form, context=self.get_context()) - - def validate(self, part, form, **kwargs): - - confirm = str2bool(form.cleaned_data.get('validate', False)) - - if not confirm: - form.add_error('validate', _('Confirm that the BOM is valid')) - - def save(self, part, form, **kwargs): - """ - Mark the BOM as validated - """ - - part.validate_bom(self.request.user) - - def get_data(self): - return { - 'success': _('Validated Bill of Materials') - } - - class BomUpload(InvenTreeRoleMixin, FileManagementFormView): """ View for uploading a BOM file, and handling BOM data importing. diff --git a/InvenTree/templates/js/translated/api.js b/InvenTree/templates/js/translated/api.js index d9c23f035f..eadf2e2afc 100644 --- a/InvenTree/templates/js/translated/api.js +++ b/InvenTree/templates/js/translated/api.js @@ -207,6 +207,11 @@ function showApiError(xhr, url) { title = '{% trans "Error 404: Resource Not Found" %}'; message = '{% trans "The requested resource could not be located on the server" %}'; break; + // Method not allowed + case 405: + title = '{% trans "Error 405: Method Not Allowed" %}'; + message = '{% trans "HTTP method not allowed at URL" %}'; + break; // Timeout case 408: title = '{% trans "Error 408: Timeout" %}'; diff --git a/InvenTree/templates/js/translated/part.js b/InvenTree/templates/js/translated/part.js index 1cfd50d66c..fafbfb37c8 100644 --- a/InvenTree/templates/js/translated/part.js +++ b/InvenTree/templates/js/translated/part.js @@ -40,6 +40,7 @@ loadStockPricingChart, partStockLabel, toggleStar, + validateBom, */ /* Part API functions @@ -429,9 +430,34 @@ function toggleStar(options) { } +/* Validate a BOM */ +function validateBom(part_id, options={}) { + + var html = ` +
+ {% trans "Validating the BOM will mark each line item as valid" %} +
+ `; + + constructForm(`/api/part/${part_id}/bom-validate/`, { + method: 'PUT', + fields: { + valid: {}, + }, + preFormContent: html, + title: '{% trans "Validate Bill of Materials" %}', + reload: options.reload, + onSuccess: function(response) { + showMessage('{% trans "Validated Bill of Materials" %}'); + } + }); +} + + /* Duplicate a BOM */ function duplicateBom(part_id, options={}) { - constructForm(`/api/part/${part_id}/copy-bom/`, { + + constructForm(`/api/part/${part_id}/bom-copy/`, { method: 'POST', fields: { part: {