mirror of
https://github.com/inventree/InvenTree.git
synced 2026-01-11 21:57:57 +00:00
BuildItem quantity fix (#11108)
* Refactor clean check for BuildItem * Don't raise an error when saving a BuildItem * Fix order of operations * remove debug statements
This commit is contained in:
@@ -1743,11 +1743,10 @@ class BuildItem(InvenTree.models.InvenTreeMetadataModel):
|
|||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""Custom save method for the BuildItem model."""
|
"""Custom save method for the BuildItem model."""
|
||||||
self.clean()
|
self.clean(raise_error=False)
|
||||||
|
|
||||||
super().save()
|
super().save()
|
||||||
|
|
||||||
def clean(self):
|
def clean(self, raise_error: bool = True):
|
||||||
"""Check validity of this BuildItem instance.
|
"""Check validity of this BuildItem instance.
|
||||||
|
|
||||||
The following checks are performed:
|
The following checks are performed:
|
||||||
@@ -1771,47 +1770,7 @@ class BuildItem(InvenTree.models.InvenTreeMetadataModel):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Allocated quantity cannot exceed available stock quantity
|
self.check_allocated_quantity(raise_error=raise_error)
|
||||||
if self.quantity > self.stock_item.quantity:
|
|
||||||
q = InvenTree.helpers.normalize(self.quantity)
|
|
||||||
a = InvenTree.helpers.normalize(self.stock_item.quantity)
|
|
||||||
|
|
||||||
raise ValidationError({
|
|
||||||
'quantity': _(
|
|
||||||
f'Allocated quantity ({q}) must not exceed available stock quantity ({a})'
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
# Ensure that we do not 'over allocate' a stock item
|
|
||||||
available = decimal.Decimal(self.stock_item.quantity)
|
|
||||||
quantity = decimal.Decimal(self.quantity)
|
|
||||||
build_allocation_count = decimal.Decimal(
|
|
||||||
self.stock_item.build_allocation_count(
|
|
||||||
exclude_allocations={'pk': self.pk}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
sales_allocation_count = decimal.Decimal(
|
|
||||||
self.stock_item.sales_order_allocation_count()
|
|
||||||
)
|
|
||||||
|
|
||||||
total_allocation = (
|
|
||||||
build_allocation_count + sales_allocation_count + quantity
|
|
||||||
)
|
|
||||||
|
|
||||||
if total_allocation > available:
|
|
||||||
raise ValidationError({'quantity': _('Stock item is over-allocated')})
|
|
||||||
|
|
||||||
# Allocated quantity must be positive
|
|
||||||
if self.quantity <= 0:
|
|
||||||
raise ValidationError({
|
|
||||||
'quantity': _('Allocation quantity must be greater than zero')
|
|
||||||
})
|
|
||||||
|
|
||||||
# Quantity must be 1 for serialized stock
|
|
||||||
if self.stock_item.serialized and self.quantity != 1:
|
|
||||||
raise ValidationError({
|
|
||||||
'quantity': _('Quantity must be 1 for serialized stock')
|
|
||||||
})
|
|
||||||
|
|
||||||
except stock.models.StockItem.DoesNotExist:
|
except stock.models.StockItem.DoesNotExist:
|
||||||
raise ValidationError('Stock item must be specified')
|
raise ValidationError('Stock item must be specified')
|
||||||
@@ -1873,6 +1832,60 @@ class BuildItem(InvenTree.models.InvenTreeMetadataModel):
|
|||||||
'stock_item': _('Selected stock item does not match BOM line')
|
'stock_item': _('Selected stock item does not match BOM line')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def check_allocated_quantity(self, raise_error: bool = False):
|
||||||
|
"""Ensure that the allocated quantity is valid.
|
||||||
|
|
||||||
|
Will reduce the allocated quantity if it exceeds available stock.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
raise_error: If True, raise ValidationError on failure
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValidationError: If the allocated quantity is invalid and raise_error is True
|
||||||
|
"""
|
||||||
|
error = None
|
||||||
|
|
||||||
|
# Allocated quantity must be positive
|
||||||
|
if self.quantity <= 0:
|
||||||
|
self.quantity = 0
|
||||||
|
error = {'quantity': _('Allocated quantity must be greater than zero')}
|
||||||
|
|
||||||
|
# Quantity must be 1 for serialized stock
|
||||||
|
if self.stock_item.serialized and self.quantity != 1:
|
||||||
|
self.quantity = 1
|
||||||
|
raise ValidationError({
|
||||||
|
'quantity': _('Quantity must be 1 for serialized stock')
|
||||||
|
})
|
||||||
|
|
||||||
|
# Allocated quantity cannot exceed available stock quantity
|
||||||
|
if self.quantity > self.stock_item.quantity:
|
||||||
|
q = InvenTree.helpers.normalize(self.quantity)
|
||||||
|
a = InvenTree.helpers.normalize(self.stock_item.quantity)
|
||||||
|
self.quantity = self.stock_item.quantity
|
||||||
|
error = {
|
||||||
|
'quantity': _(
|
||||||
|
f'Allocated quantity ({q}) must not exceed available stock quantity ({a})'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure that we do not 'over allocate' a stock item
|
||||||
|
available = decimal.Decimal(self.stock_item.quantity)
|
||||||
|
quantity = decimal.Decimal(self.quantity)
|
||||||
|
build_allocation_count = decimal.Decimal(
|
||||||
|
self.stock_item.build_allocation_count(exclude_allocations={'pk': self.pk})
|
||||||
|
)
|
||||||
|
sales_allocation_count = decimal.Decimal(
|
||||||
|
self.stock_item.sales_order_allocation_count()
|
||||||
|
)
|
||||||
|
|
||||||
|
total_allocation = build_allocation_count + sales_allocation_count + quantity
|
||||||
|
|
||||||
|
if total_allocation > available:
|
||||||
|
error = {'quantity': _('Stock item is over-allocated')}
|
||||||
|
|
||||||
|
if error and raise_error:
|
||||||
|
raise ValidationError(error)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def build(self):
|
def build(self):
|
||||||
"""Return the BuildOrder associated with this BuildItem."""
|
"""Return the BuildOrder associated with this BuildItem."""
|
||||||
|
|||||||
Reference in New Issue
Block a user