mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Build completion now handles unique serial numbers
Provide a method to test if a serial number matches for a given part
This commit is contained in:
parent
9a8e4d25d2
commit
23d03d6b9b
@ -199,7 +199,7 @@ class Build(models.Model):
|
||||
build_item.save()
|
||||
|
||||
@transaction.atomic
|
||||
def completeBuild(self, location, user):
|
||||
def completeBuild(self, location, serial_numbers, user):
|
||||
""" Mark the Build as COMPLETE
|
||||
|
||||
- Takes allocated items from stock
|
||||
@ -227,19 +227,36 @@ class Build(models.Model):
|
||||
|
||||
self.completed_by = user
|
||||
|
||||
# Add stock of the newly created item
|
||||
item = StockItem.objects.create(
|
||||
part=self.part,
|
||||
location=location,
|
||||
quantity=self.quantity,
|
||||
batch=str(self.batch) if self.batch else '',
|
||||
notes='Built {q} on {now}'.format(
|
||||
q=self.quantity,
|
||||
now=str(datetime.now().date())
|
||||
)
|
||||
notes = 'Built {q} on {now}'.format(
|
||||
q=self.quantity,
|
||||
now=str(datetime.now().date())
|
||||
)
|
||||
|
||||
item.save()
|
||||
if self.part.trackable:
|
||||
# Add new serial numbers
|
||||
for serial in serial_numbers:
|
||||
item = StockItem.objects.create(
|
||||
part=self.part,
|
||||
location=location,
|
||||
quantity=1,
|
||||
serial=serial,
|
||||
batch=str(self.batch) if self.batch else '',
|
||||
notes=notes
|
||||
)
|
||||
|
||||
item.save()
|
||||
|
||||
else:
|
||||
# Add stock of the newly created item
|
||||
item = StockItem.objects.create(
|
||||
part=self.part,
|
||||
location=location,
|
||||
quantity=self.quantity,
|
||||
batch=str(self.batch) if self.batch else '',
|
||||
notes=notes
|
||||
)
|
||||
|
||||
item.save()
|
||||
|
||||
# Finally, mark the build as complete
|
||||
self.status = BuildStatus.COMPLETE
|
||||
|
@ -225,7 +225,7 @@ class BuildComplete(AjaxUpdateView):
|
||||
build = Build.objects.get(id=self.kwargs['pk'])
|
||||
|
||||
context = {}
|
||||
|
||||
|
||||
# Build object
|
||||
context['build'] = build
|
||||
|
||||
@ -263,21 +263,35 @@ class BuildComplete(AjaxUpdateView):
|
||||
except StockLocation.DoesNotExist:
|
||||
form.errors['location'] = ['Invalid location selected']
|
||||
|
||||
valid = False
|
||||
serials = []
|
||||
|
||||
serials = request.POST.get('serial_numbers', '')
|
||||
if build.part.trackable:
|
||||
# A build for a trackable part must specify serial numbers
|
||||
|
||||
try:
|
||||
serials = ExtractSerialNumbers(serials, build.quantity)
|
||||
sn = request.POST.get('serial_numbers', '')
|
||||
|
||||
print(serials)
|
||||
try:
|
||||
# Exctract a list of provided serial numbers
|
||||
serials = ExtractSerialNumbers(sn, build.quantity)
|
||||
|
||||
except ValidationError as e:
|
||||
form.errors['serial_numbers'] = e.messages
|
||||
valid = False
|
||||
existing = []
|
||||
|
||||
for serial in serials:
|
||||
if not StockItem.check_serial_number(build.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
|
||||
|
||||
if valid:
|
||||
build.completeBuild(location, request.user)
|
||||
build.completeBuild(location, serials, request.user)
|
||||
|
||||
data = {
|
||||
'form_valid': valid,
|
||||
|
@ -280,6 +280,7 @@ 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:
|
||||
|
@ -92,6 +92,7 @@ class StockItem(models.Model):
|
||||
location: Where this StockItem is located
|
||||
quantity: Number of stocked units
|
||||
batch: Batch number for this StockItem
|
||||
serial: Unique serial number for this StockItem
|
||||
URL: Optional URL to link to external resource
|
||||
updated: Date that this stock item was last updated (auto)
|
||||
stocktake_date: Date of last stocktake for this item
|
||||
@ -121,6 +122,32 @@ class StockItem(models.Model):
|
||||
system=True
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def check_serial_number(cls, part, serial_number):
|
||||
""" Check if a new stock item can be created with the provided part_id
|
||||
|
||||
Args:
|
||||
part: The part to be checked
|
||||
"""
|
||||
|
||||
if not part.trackable:
|
||||
return False
|
||||
|
||||
items = StockItem.objects.filter(serial=serial_number)
|
||||
|
||||
# Is this part a variant? If so, check S/N across all sibling variants
|
||||
if part.variant_of is not None:
|
||||
items = items.filter(part__variant_of=part.variant_of)
|
||||
else:
|
||||
items = items.filter(part=part)
|
||||
|
||||
# An existing serial number exists
|
||||
if items.exists():
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def validate_unique(self, exclude=None):
|
||||
super(StockItem, self).validate_unique(exclude)
|
||||
|
||||
@ -129,11 +156,18 @@ class StockItem(models.Model):
|
||||
# across all variants of the same template part
|
||||
|
||||
try:
|
||||
if self.serial is not None and self.part.variant_of is not None:
|
||||
if StockItem.objects.filter(part__variant_of=self.part.variant_of, serial=self.serial).exclude(id=self.id).exists():
|
||||
raise ValidationError({
|
||||
'serial': _('A part with this serial number already exists for template part {part}'.format(part=self.part.variant_of))
|
||||
})
|
||||
if self.serial is not None:
|
||||
# This is a variant part (check S/N across all sibling variants)
|
||||
if self.part.variant_of is not None:
|
||||
if StockItem.objects.filter(part__variant_of=self.part.variant_of, serial=self.serial).exclude(id=self.id).exists():
|
||||
raise ValidationError({
|
||||
'serial': _('A part with this serial number already exists for template part {part}'.format(part=self.part.variant_of))
|
||||
})
|
||||
else:
|
||||
if StockItem.objects.filter(serial=self.serial).exclude(id=self.id).exists():
|
||||
raise ValidationError({
|
||||
'serial': _('A part with this serial number already exists')
|
||||
})
|
||||
except Part.DoesNotExist:
|
||||
pass
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user