mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Update required parts for build orders (#5542)
- When a BomItem is created or edited, update any active build orders which use it - Runs as a background task - Fixes https://github.com/inventree/InvenTree/issues/5541
This commit is contained in:
parent
56fdbc00c9
commit
c8021ec319
@ -1186,7 +1186,8 @@ class Build(MPTTModel, InvenTree.models.InvenTreeBarcodeMixin, InvenTree.models.
|
||||
|
||||
BuildLine.objects.bulk_create(lines)
|
||||
|
||||
logger.info(f"Created {len(lines)} BuildLine objects for BuildOrder")
|
||||
if len(lines) > 0:
|
||||
logger.info(f"Created {len(lines)} BuildLine objects for BuildOrder")
|
||||
|
||||
@transaction.atomic
|
||||
def update_build_line_items(self):
|
||||
|
@ -24,6 +24,55 @@ import part.models as part_models
|
||||
logger = logging.getLogger('inventree')
|
||||
|
||||
|
||||
def update_build_order_lines(bom_item_pk: int):
|
||||
"""Update all BuildOrderLineItem objects which reference a particular BomItem.
|
||||
|
||||
This task is triggered when a BomItem is created or updated.
|
||||
"""
|
||||
|
||||
logger.info(f"Updating build order lines for BomItem {bom_item_pk}")
|
||||
|
||||
bom_item = part_models.BomItem.objects.filter(pk=bom_item_pk).first()
|
||||
|
||||
# If the BomItem has been deleted, there is nothing to do
|
||||
if not bom_item:
|
||||
return
|
||||
|
||||
assemblies = bom_item.get_assemblies()
|
||||
|
||||
# Find all active builds which reference any of the parts
|
||||
builds = build.models.Build.objects.filter(
|
||||
part__in=list(assemblies),
|
||||
status__in=BuildStatusGroups.ACTIVE_CODES
|
||||
)
|
||||
|
||||
# Iterate through each build, and update the relevant line items
|
||||
for bo in builds:
|
||||
# Try to find a matching build order line
|
||||
line = build.models.BuildLine.objects.filter(
|
||||
build=bo,
|
||||
bom_item=bom_item,
|
||||
).first()
|
||||
|
||||
q = bom_item.get_required_quantity(bo.quantity)
|
||||
|
||||
if line:
|
||||
# Ensure quantity is correct
|
||||
if line.quantity != q:
|
||||
line.quantity = q
|
||||
line.save()
|
||||
else:
|
||||
# Create a new line item
|
||||
build.models.BuildLine.objects.create(
|
||||
build=bo,
|
||||
bom_item=bom_item,
|
||||
quantity=q,
|
||||
)
|
||||
|
||||
if builds.count() > 0:
|
||||
logger.info(f"Updated {builds.count()} build orders for part {bom_item.part}")
|
||||
|
||||
|
||||
def check_build_stock(build: build.models.Build):
|
||||
"""Check the required stock for a newly created build order.
|
||||
|
||||
|
@ -3749,6 +3749,18 @@ class BomItem(DataImportMixin, MetadataMixin, models.Model):
|
||||
"""Return the list API endpoint URL associated with the BomItem model"""
|
||||
return reverse('api-bom-list')
|
||||
|
||||
def get_assemblies(self):
|
||||
"""Return a list of assemblies which use this BomItem"""
|
||||
|
||||
assemblies = [self.part]
|
||||
|
||||
if self.inherited:
|
||||
assemblies += list(
|
||||
self.part.get_descendants(include_self=False)
|
||||
)
|
||||
|
||||
return assemblies
|
||||
|
||||
def get_valid_parts_for_allocation(self, allow_variants=True, allow_substitutes=True):
|
||||
"""Return a list of valid parts which can be allocated against this BomItem.
|
||||
|
||||
@ -4048,6 +4060,18 @@ class BomItem(DataImportMixin, MetadataMixin, models.Model):
|
||||
return "{pmin} to {pmax}".format(pmin=pmin, pmax=pmax)
|
||||
|
||||
|
||||
@receiver(post_save, sender=BomItem, dispatch_uid='update_bom_build_lines')
|
||||
def update_bom_build_lines(sender, instance, created, **kwargs):
|
||||
"""Update existing build orders when a BomItem is created or edited"""
|
||||
|
||||
if InvenTree.ready.canAppAccessDatabase() and not InvenTree.ready.isImportingData():
|
||||
import build.tasks
|
||||
InvenTree.tasks.offload_task(
|
||||
build.tasks.update_build_order_lines,
|
||||
instance.pk
|
||||
)
|
||||
|
||||
|
||||
@receiver(post_save, sender=BomItem, dispatch_uid='post_save_bom_item')
|
||||
@receiver(post_save, sender=PartSellPriceBreak, dispatch_uid='post_save_sale_price_break')
|
||||
@receiver(post_save, sender=PartInternalPriceBreak, dispatch_uid='post_save_internal_price_break')
|
||||
|
Loading…
Reference in New Issue
Block a user