diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index 9678819e41..2256f28210 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -24,6 +24,21 @@ class PartImageForm(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, help_text='Confirm that the BOM is correct') + + class Meta: + model = Part + fields = [ + 'validate' + ] + + class BomExportForm(HelperForm): # TODO - Define these choices somewhere else, and import them here diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 22b0073e6c..b781287930 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -24,6 +24,7 @@ from django.contrib.auth.models import User from django.db.models.signals import pre_delete from django.dispatch import receiver +from datetime import datetime from fuzzywuzzy import fuzz import hashlib @@ -468,14 +469,16 @@ class Part(models.Model): @property def bom_count(self): + """ Return the number of items contained in the BOM for this part """ return self.bom_items.count() @property def used_in_count(self): + """ Return the number of part BOMs that this part appears in """ return self.used_in.count() def get_bom_hash(self): - """ Return a checksum hash for the BOM for this part. + """ Return a checksum hash for the BOM for this part. Used to determine if the BOM has changed (and needs to be signed off!) For hash is calculated from the following fields of each BOM item: @@ -511,7 +514,7 @@ class Part(models.Model): - Saves the current date and the checking user """ - self.bom_checksum = get_bom_hash() + self.bom_checksum = self.get_bom_hash() self.bom_checked_by = user self.bom_checked_date = datetime.now().date() diff --git a/InvenTree/part/templates/part/bom.html b/InvenTree/part/templates/part/bom.html index a94569d42c..295fed23d6 100644 --- a/InvenTree/part/templates/part/bom.html +++ b/InvenTree/part/templates/part/bom.html @@ -39,6 +39,9 @@ @@ -87,6 +90,15 @@ {% else %} + $("#validate-bom").click(function() { + launchModalForm( + "{% url 'bom-validate' part.id %}", + { + reload: true, + } + ); + }); + $("#edit-bom").click(function () { location.href = "{% url 'part-bom' part.id %}?edit=True"; }); diff --git a/InvenTree/part/templates/part/bom_validate.html b/InvenTree/part/templates/part/bom_validate.html new file mode 100644 index 0000000000..f2c159349f --- /dev/null +++ b/InvenTree/part/templates/part/bom_validate.html @@ -0,0 +1,5 @@ +{% extends "modal_form.html" %} + +{% block pre_form_content %} +Confirm that the Bill of Materials (BOM) is valid for:
{{ part.full_name }} +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 64b6517489..fb49af8a9b 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -35,6 +35,7 @@ part_detail_urls = [ url(r'^edit/?', views.PartEdit.as_view(), name='part-edit'), url(r'^delete/?', views.PartDelete.as_view(), name='part-delete'), url(r'^bom-export/?', views.BomDownload.as_view(), name='bom-export'), + url(r'^validate-bom/', views.BomValidate.as_view(), name='bom-validate'), url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), url(r'^attachments/?', views.PartDetail.as_view(template_name='part/attachments.html'), name='part-attachments'), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 890cb8a519..135e3da144 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -331,12 +331,50 @@ class PartEdit(AjaxUpdateView): return form +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 post(self, request, *args, **kwargs): + + form = self.get_form() + part = self.get_object() + + confirmed = str2bool(request.POST.get('validate', False)) + + if confirmed: + part.validate_bom(request.user) + else: + form.errors['validate'] = ['Confirm that the BOM is valid'] + + data = { + 'form_valid': confirmed + } + + return self.renderJsonResponse(request, form, data, context=self.get_context()) + + class BomExport(AjaxView): model = Part ajax_form_title = 'Export BOM' ajax_template_name = 'part/bom_export.html' - context_object_name = 'part' form_class = part_forms.BomExportForm def get_object(self): @@ -345,17 +383,6 @@ class BomExport(AjaxView): def get(self, request, *args, **kwargs): form = self.form_class() - """ - part = self.get_object() - - context = { - 'part': part - } - - if request.is_ajax(): - passs - """ - return self.renderJsonResponse(request, form) def post(self, request, *args, **kwargs):