mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +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:
parent
8f298f71ef
commit
8a90b9df6d
@ -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
|
||||
|
@ -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 %}
|
@ -20,12 +20,6 @@ build_detail_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)),
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user