mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Set serial numbers when creating a new stock item
This commit is contained in:
parent
23d03d6b9b
commit
9e5eadd6c3
@ -188,4 +188,4 @@ def ExtractSerialNumbers(serials, expected_quantity):
|
||||
if not expected_quantity == len(numbers):
|
||||
raise ValidationError([_("Number of unique serial number ({s}) must match quantity ({q})".format(s=len(numbers), q=expected_quantity))])
|
||||
|
||||
return numbers
|
||||
return numbers
|
||||
|
@ -282,10 +282,9 @@ class BuildComplete(AjaxUpdateView):
|
||||
|
||||
if len(existing) > 0:
|
||||
exists = ",".join([str(x) for x in existing])
|
||||
form.errors['serial_numbers'] = [_('The following serial numbers already exist: {sn}'.format(sn=exists))]
|
||||
form.errors['serial_numbers'] = [_('The following serial numbers already exist: ({sn})'.format(sn=exists))]
|
||||
valid = False
|
||||
|
||||
|
||||
except ValidationError as e:
|
||||
form.errors['serial_numbers'] = e.messages
|
||||
valid = False
|
||||
|
@ -280,7 +280,6 @@ class Part(models.Model):
|
||||
else:
|
||||
return static('/img/blank_image.png')
|
||||
|
||||
|
||||
def validate_unique(self, exclude=None):
|
||||
""" Validate that a part is 'unique'.
|
||||
Uniqueness is checked across the following (case insensitive) fields:
|
||||
|
@ -6,8 +6,9 @@ Django Forms for interacting with Stock app
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django import forms
|
||||
from InvenTree.forms import HelperForm
|
||||
from django.forms.utils import ErrorDict
|
||||
|
||||
from InvenTree.forms import HelperForm
|
||||
from .models import StockLocation, StockItem, StockItemTracking
|
||||
|
||||
|
||||
@ -26,6 +27,8 @@ class EditStockLocationForm(HelperForm):
|
||||
class CreateStockItemForm(HelperForm):
|
||||
""" Form for creating a new StockItem """
|
||||
|
||||
serial_numbers = forms.CharField(label='Serial numbers', required=False, help_text='Enter unique serial numbers')
|
||||
|
||||
class Meta:
|
||||
model = StockItem
|
||||
fields = [
|
||||
@ -34,13 +37,30 @@ class CreateStockItemForm(HelperForm):
|
||||
'location',
|
||||
'quantity',
|
||||
'batch',
|
||||
'serial',
|
||||
'serial_numbers',
|
||||
'delete_on_deplete',
|
||||
'status',
|
||||
'notes',
|
||||
'URL',
|
||||
]
|
||||
|
||||
# Custom clean to prevent complex StockItem.clean() logic from running (yet)
|
||||
def full_clean(self):
|
||||
self._errors = ErrorDict()
|
||||
|
||||
if not self.is_bound: # Stop further processing.
|
||||
return
|
||||
|
||||
self.cleaned_data = {}
|
||||
# If the form is permitted to be empty, and none of the form data has
|
||||
# changed from the initial data, short circuit any validation.
|
||||
if self.empty_permitted and not self.has_changed():
|
||||
return
|
||||
|
||||
# Don't run _post_clean() as this will run StockItem.clean()
|
||||
self._clean_fields()
|
||||
self._clean_form()
|
||||
|
||||
|
||||
class AdjustStockForm(forms.ModelForm):
|
||||
""" Form for performing simple stock adjustments.
|
||||
|
@ -147,7 +147,6 @@ class StockItem(models.Model):
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def validate_unique(self, exclude=None):
|
||||
super(StockItem, self).validate_unique(exclude)
|
||||
|
||||
@ -192,16 +191,23 @@ class StockItem(models.Model):
|
||||
|
||||
if self.part is not None:
|
||||
# A trackable part must have a serial number
|
||||
if self.part.trackable and not self.serial:
|
||||
raise ValidationError({
|
||||
'serial': _('Serial number must be set for trackable items')
|
||||
})
|
||||
if self.part.trackable:
|
||||
if not self.serial:
|
||||
raise ValidationError({'serial': _('Serial number must be set for trackable items')})
|
||||
|
||||
if self.delete_on_deplete:
|
||||
raise ValidationError({'delete_on_deplete': _("Must be set to False for trackable items")})
|
||||
|
||||
# Serial number cannot be set for items with quantity greater than 1
|
||||
if not self.quantity == 1:
|
||||
raise ValidationError({
|
||||
'quantity': _("Quantity must be set to 1 for item with a serial number"),
|
||||
'serial': _("Serial number cannot be set if quantity > 1")
|
||||
})
|
||||
|
||||
# A template part cannot be instantiated as a StockItem
|
||||
if self.part.is_template:
|
||||
raise ValidationError({
|
||||
'part': _('Stock item cannot be created for a template Part')
|
||||
})
|
||||
raise ValidationError({'part': _('Stock item cannot be created for a template Part')})
|
||||
|
||||
except Part.DoesNotExist:
|
||||
# This gets thrown if self.supplier_part is null
|
||||
@ -213,13 +219,6 @@ class StockItem(models.Model):
|
||||
'belongs_to': _('Item cannot belong to itself')
|
||||
})
|
||||
|
||||
# Serial number cannot be set for items with quantity greater than 1
|
||||
if not self.quantity == 1 and self.serial:
|
||||
raise ValidationError({
|
||||
'quantity': _("Quantity must be set to 1 for item with a serial number"),
|
||||
'serial': _("Serial number cannot be set if quantity > 1")
|
||||
})
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('stock-item-detail', kwargs={'pk': self.id})
|
||||
|
||||
|
@ -5,6 +5,7 @@ Django views for interacting with Stock app
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.views.generic.edit import FormMixin
|
||||
from django.views.generic import DetailView, ListView
|
||||
from django.forms.models import model_to_dict
|
||||
@ -17,6 +18,7 @@ from InvenTree.views import AjaxUpdateView, AjaxDeleteView, AjaxCreateView
|
||||
from InvenTree.views import QRCodeView
|
||||
|
||||
from InvenTree.helpers import str2bool
|
||||
from InvenTree.helpers import ExtractSerialNumbers
|
||||
from datetime import datetime
|
||||
|
||||
from part.models import Part
|
||||
@ -476,7 +478,7 @@ class StockItemCreate(AjaxCreateView):
|
||||
ForeignKey choices based on other selections
|
||||
"""
|
||||
|
||||
form = super(AjaxCreateView, self).get_form()
|
||||
form = super().get_form()
|
||||
|
||||
# If the user has selected a Part, limit choices for SupplierPart
|
||||
if form['part'].value():
|
||||
@ -488,10 +490,16 @@ class StockItemCreate(AjaxCreateView):
|
||||
# Hide the 'part' field (as a valid part is selected)
|
||||
form.fields['part'].widget = HiddenInput()
|
||||
|
||||
# trackable parts get special consideration
|
||||
if part.trackable:
|
||||
form.fields['delete_on_deplete'].widget = HiddenInput()
|
||||
form.fields['delete_on_deplete'].initial = False
|
||||
else:
|
||||
form.fields.pop('serial_numbers')
|
||||
|
||||
# If the part is NOT purchaseable, hide the supplier_part field
|
||||
if not part.purchaseable:
|
||||
form.fields['supplier_part'].widget = HiddenInput()
|
||||
|
||||
else:
|
||||
# Pre-select the allowable SupplierPart options
|
||||
parts = form.fields['supplier_part'].queryset
|
||||
@ -555,6 +563,63 @@ class StockItemCreate(AjaxCreateView):
|
||||
|
||||
return initials
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
""" Handle POST of StockItemCreate form.
|
||||
|
||||
- Manage serial-number valdiation for tracked parts
|
||||
"""
|
||||
|
||||
form = self.get_form()
|
||||
|
||||
valid = form.is_valid()
|
||||
|
||||
if valid:
|
||||
part_id = form['part'].value()
|
||||
try:
|
||||
part = Part.objects.get(id=part_id)
|
||||
quantity = int(form['quantity'].value())
|
||||
except (Part.DoesNotExist, ValueError):
|
||||
part = None
|
||||
quantity = 1
|
||||
valid = False
|
||||
|
||||
if part is None:
|
||||
form.errors['part'] = [_('Invalid part selection')]
|
||||
else:
|
||||
# A trackable part must provide serial numbesr
|
||||
if part.trackable:
|
||||
sn = request.POST.get('serial_numbers', '')
|
||||
|
||||
try:
|
||||
serials = ExtractSerialNumbers(sn, quantity)
|
||||
|
||||
existing = []
|
||||
|
||||
for serial in serials:
|
||||
if not StockItem.check_serial_number(part, serial):
|
||||
existing.append(serial)
|
||||
|
||||
if len(existing) > 0:
|
||||
exists = ",".join([str(x) for x in existing])
|
||||
form.errors['serial_numbers'] = [_('The following serial numbers already exist: ({sn})'.format(sn=exists))]
|
||||
valid = False
|
||||
|
||||
except ValidationError as e:
|
||||
form.errors['serial_numbers'] = e.messages
|
||||
valid = False
|
||||
|
||||
print("Valid?", valid)
|
||||
|
||||
valid = False
|
||||
|
||||
print("valid:", valid)
|
||||
|
||||
data = {
|
||||
'form_valid': valid,
|
||||
}
|
||||
|
||||
return self.renderJsonResponse(request, form, data=data)
|
||||
|
||||
|
||||
class StockLocationDelete(AjaxDeleteView):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user