2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-30 20:46:47 +00:00

Improve clean() function for BuildItem model

- BuildItemDelete now handled by API forms
- BuildItemEdit now handled by API forms
This commit is contained in:
Oliver 2021-10-05 00:14:31 +11:00
parent 8f298f71ef
commit 8a90b9df6d
5 changed files with 41 additions and 93 deletions

View File

@ -4,6 +4,7 @@ Build database model definitions
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import decimal
import os import os
from datetime import datetime from datetime import datetime
@ -1185,13 +1186,13 @@ class BuildItem(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.validate_unique()
self.clean() self.clean()
super().save() super().save()
def clean(self): def clean(self):
""" Check validity of the BuildItem model. """
Check validity of this BuildItem instance.
The following checks are performed: The following checks are performed:
- StockItem.part must be in the BOM of the Part object referenced by Build - StockItem.part must be in the BOM of the Part object referenced by Build
@ -1202,8 +1203,6 @@ class BuildItem(models.Model):
super().clean() super().clean()
errors = {}
try: try:
# If the 'part' is trackable, then the 'install_into' field must be set! # 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 # Allocated quantity cannot exceed available stock quantity
if self.quantity > self.stock_item.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.quantity)
q=normalize(self.stock_item.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 # 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: available = decimal.Decimal(self.stock_item.quantity)
errors['quantity'] = _('StockItem is over-allocated') 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 # Allocated quantity must be positive
if self.quantity <= 0: 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 # Quantity must be 1 for serialized stock
if self.stock_item.serialized and not self.quantity == 1: 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): except (StockModels.StockItem.DoesNotExist, PartModels.Part.DoesNotExist):
pass pass
if len(errors) > 0:
raise ValidationError(errors)
""" """
Attempt to find the "BomItem" which links this BuildItem to the build. 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 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: b) Either:
i) The sub_part points to the same part as the referenced StockItem 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 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: if not bom_item_valid:
raise ValidationError({ 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 @transaction.atomic

View File

@ -1,14 +0,0 @@
{% extends "modal_delete_form.html" %}
{% load i18n %}
{% load inventree_extras %}
{% block pre_form_content %}
<div class='alert alert-block alert-danger'>
<p>
{% trans "Are you sure you want to unallocate this stock?" %}
</p>
<p>
{% trans "The selected stock will be unallocated from the build output" %}
</p>
</div>
{% endblock %}

View File

@ -20,12 +20,6 @@ build_detail_urls = [
] ]
build_urls = [ build_urls = [
url(r'item/', include([
url(r'^(?P<pk>\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<pk>\d+)/', include(build_detail_urls)), url(r'^(?P<pk>\d+)/', include(build_detail_urls)),

View File

@ -628,21 +628,6 @@ class BuildDelete(AjaxDeleteView):
ajax_form_title = _('Delete Build Order') 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): class BuildItemCreate(AjaxCreateView):
""" """
@ -859,35 +844,3 @@ class BuildItemCreate(AjaxCreateView):
initials['quantity'] = quantity initials['quantity'] = quantity
return initials 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

View File

@ -596,11 +596,9 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
text = `{% trans "Quantity" %}: ${row.quantity}`; text = `{% trans "Quantity" %}: ${row.quantity}`;
} }
{% if build.status == BuildStatus.COMPLETE %} var pk = row.stock_item || row.pk;
url = `/stock/item/${row.pk}/`;
{% else %} url = `/stock/item/${pk}/`;
url = `/stock/item/${row.stock_item}/`;
{% endif %}
return renderLink(text, url); return renderLink(text, url);
} }
@ -647,15 +645,23 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
// Assign button callbacks to the newly created allocation buttons // Assign button callbacks to the newly created allocation buttons
subTable.find('.button-allocation-edit').click(function() { subTable.find('.button-allocation-edit').click(function() {
var pk = $(this).attr('pk'); 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() { subTable.find('.button-allocation-delete').click(function() {
var pk = $(this).attr('pk'); 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,
}); });
}); });
}, },