diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py index 3224554156..4bd4d2e757 100644 --- a/InvenTree/build/models.py +++ b/InvenTree/build/models.py @@ -4,6 +4,7 @@ Build database model definitions # -*- coding: utf-8 -*- from __future__ import unicode_literals +import decimal import os from datetime import datetime @@ -1185,13 +1186,13 @@ class BuildItem(models.Model): def save(self, *args, **kwargs): - self.validate_unique() self.clean() super().save() def clean(self): - """ Check validity of the BuildItem model. + """ + Check validity of this BuildItem instance. The following checks are performed: - StockItem.part must be in the BOM of the Part object referenced by Build @@ -1202,8 +1203,6 @@ class BuildItem(models.Model): super().clean() - errors = {} - try: # If the 'part' is trackable, then the 'install_into' field must be set! @@ -1212,29 +1211,39 @@ class BuildItem(models.Model): # Allocated quantity cannot exceed available stock quantity if self.quantity > self.stock_item.quantity: - errors['quantity'] = [_("Allocated quantity ({n}) must not exceed available quantity ({q})").format( - n=normalize(self.quantity), - q=normalize(self.stock_item.quantity) - )] + + q = normalize(self.quantity) + a = normalize(self.stock_item.quantity) + + raise ValidationError({ + 'quantity': _(f'Allocated quantity ({q}) must not execed available stock quantity ({a})') + }) # Allocated quantity cannot cause the stock item to be over-allocated - if self.stock_item.quantity - self.stock_item.allocation_count() + self.quantity < self.quantity: - errors['quantity'] = _('StockItem is over-allocated') + available = decimal.Decimal(self.stock_item.quantity) + allocated = decimal.Decimal(self.stock_item.allocation_count()) + quantity = decimal.Decimal(self.quantity) + + if available - allocated + quantity < quantity: + raise ValidationError({ + 'quantity': _('Stock item is over-allocated') + }) # Allocated quantity must be positive if self.quantity <= 0: - errors['quantity'] = _('Allocation quantity must be greater than zero') + raise ValidationError({ + 'quantity': _('Allocation quantity must be greater than zero'), + }) # Quantity must be 1 for serialized stock if self.stock_item.serialized and not self.quantity == 1: - errors['quantity'] = _('Quantity must be 1 for serialized stock') + raise ValidationError({ + 'quantity': _('Quantity must be 1 for serialized stock') + }) except (StockModels.StockItem.DoesNotExist, PartModels.Part.DoesNotExist): pass - if len(errors) > 0: - raise ValidationError(errors) - """ Attempt to find the "BomItem" which links this BuildItem to the build. @@ -1247,7 +1256,7 @@ class BuildItem(models.Model): """ A BomItem object has already been assigned. This is valid if: - a) It points to the same "part" as the referened build + a) It points to the same "part" as the referenced build b) Either: i) The sub_part points to the same part as the referenced StockItem ii) The BomItem allows variants and the part referenced by the StockItem @@ -1287,7 +1296,7 @@ class BuildItem(models.Model): if not bom_item_valid: raise ValidationError({ - 'stock_item': _("Selected stock item not found in BOM for part '{p}'").format(p=self.build.part.full_name) + 'stock_item': _("Selected stock item not found in BOM") }) @transaction.atomic diff --git a/InvenTree/build/templates/build/delete_build_item.html b/InvenTree/build/templates/build/delete_build_item.html deleted file mode 100644 index d5cc285466..0000000000 --- a/InvenTree/build/templates/build/delete_build_item.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "modal_delete_form.html" %} -{% load i18n %} -{% load inventree_extras %} - -{% block pre_form_content %} -
-

- {% trans "Are you sure you want to unallocate this stock?" %} -

-

- {% trans "The selected stock will be unallocated from the build output" %} -

-
-{% endblock %} \ No newline at end of file diff --git a/InvenTree/build/urls.py b/InvenTree/build/urls.py index 7246e48d9a..e7e6ddb5e2 100644 --- a/InvenTree/build/urls.py +++ b/InvenTree/build/urls.py @@ -20,12 +20,6 @@ build_detail_urls = [ ] build_urls = [ - url(r'item/', include([ - url(r'^(?P\d+)/', include([ - url('^edit/', views.BuildItemEdit.as_view(), name='build-item-edit'), - url('^delete/', views.BuildItemDelete.as_view(), name='build-item-delete'), - ])), - ])), url(r'^(?P\d+)/', include(build_detail_urls)), diff --git a/InvenTree/build/views.py b/InvenTree/build/views.py index dfa655f9a4..7c92fa1846 100644 --- a/InvenTree/build/views.py +++ b/InvenTree/build/views.py @@ -628,21 +628,6 @@ class BuildDelete(AjaxDeleteView): ajax_form_title = _('Delete Build Order') -class BuildItemDelete(AjaxDeleteView): - """ View to 'unallocate' a BuildItem. - Really we are deleting the BuildItem object from the database. - """ - - model = BuildItem - ajax_template_name = 'build/delete_build_item.html' - ajax_form_title = _('Unallocate Stock') - context_object_name = 'item' - - def get_data(self): - return { - 'danger': _('Removed parts from build allocation') - } - class BuildItemCreate(AjaxCreateView): """ @@ -859,35 +844,3 @@ class BuildItemCreate(AjaxCreateView): initials['quantity'] = quantity return initials - - -class BuildItemEdit(AjaxUpdateView): - """ View to edit a BuildItem object """ - - model = BuildItem - ajax_template_name = 'build/edit_build_item.html' - form_class = forms.EditBuildItemForm - ajax_form_title = _('Edit Stock Allocation') - - def get_data(self): - return { - 'info': _('Updated Build Item'), - } - - def get_form(self): - """ - Create form for editing a BuildItem. - - - Limit the StockItem options to items that match the part - """ - - form = super(BuildItemEdit, self).get_form() - - # Hide fields which we do not wish the user to edit - for field in ['build', 'stock_item']: - if form[field].value(): - form.fields[field].widget = HiddenInput() - - form.fields['install_into'].widget = HiddenInput() - - return form diff --git a/InvenTree/templates/js/translated/build.js b/InvenTree/templates/js/translated/build.js index 14523e445a..27b189902e 100644 --- a/InvenTree/templates/js/translated/build.js +++ b/InvenTree/templates/js/translated/build.js @@ -596,11 +596,9 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { text = `{% trans "Quantity" %}: ${row.quantity}`; } - {% if build.status == BuildStatus.COMPLETE %} - url = `/stock/item/${row.pk}/`; - {% else %} - url = `/stock/item/${row.stock_item}/`; - {% endif %} + var pk = row.stock_item || row.pk; + + url = `/stock/item/${pk}/`; return renderLink(text, url); } @@ -647,15 +645,23 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { // Assign button callbacks to the newly created allocation buttons subTable.find('.button-allocation-edit').click(function() { var pk = $(this).attr('pk'); - launchModalForm(`/build/item/${pk}/edit/`, { - success: reloadTable, + + constructForm(`/api/build/item/${pk}/`, { + fields: { + quantity: {}, + }, + title: '{% trans "Edit Allocation" %}', + onSuccess: reloadTable, }); }); subTable.find('.button-allocation-delete').click(function() { var pk = $(this).attr('pk'); - launchModalForm(`/build/item/${pk}/delete/`, { - success: reloadTable, + + constructForm(`/api/build/item/${pk}/`, { + method: 'DELETE', + title: '{% trans "Remove Allocation" %}', + onSuccess: reloadTable, }); }); },