Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2020-11-24 20:43:02 +11:00
commit 332a419ab9
2 changed files with 49 additions and 34 deletions

View File

@ -1083,7 +1083,9 @@ class Part(MPTTModel):
parts: Set of parts already found (to prevent recursion issues) parts: Set of parts already found (to prevent recursion issues)
""" """
for bom_item in self.bom_items.all().select_related('sub_part'): items = self.bom_items.all().prefetch_related('sub_part')
for bom_item in items:
sub_part = bom_item.sub_part sub_part = bom_item.sub_part
@ -1885,25 +1887,27 @@ class BomItem(models.Model):
- If the "sub_part" is trackable, then the "part" must be trackable too! - If the "sub_part" is trackable, then the "part" must be trackable too!
""" """
# If the sub_part is 'trackable' then the 'quantity' field must be an integer
try: try:
if self.sub_part.trackable: # Check for circular BOM references
if not self.quantity == int(self.quantity): if self.sub_part:
raise ValidationError({ self.sub_part.checkAddToBOM(self.part)
"quantity": _("Quantity must be integer value for trackable parts")
}) # If the sub_part is 'trackable' then the 'quantity' field must be an integer
if self.sub_part.trackable:
# Force the upstream part to be trackable if the sub_part is trackable if not self.quantity == int(self.quantity):
if not self.part.trackable: raise ValidationError({
self.part.trackable = True "quantity": _("Quantity must be integer value for trackable parts")
self.part.clean() })
self.part.save()
# Force the upstream part to be trackable if the sub_part is trackable
if not self.part.trackable:
self.part.trackable = True
self.part.clean()
self.part.save()
else:
raise ValidationError({'sub_part': _('Sub part must be specified')})
except Part.DoesNotExist: except Part.DoesNotExist:
pass raise ValidationError({'sub_part': _('Sub part must be specified')})
# Check for circular BOM references
self.sub_part.checkAddToBOM(self.part)
class Meta: class Meta:
verbose_name = _("BOM Item") verbose_name = _("BOM Item")

View File

@ -2428,30 +2428,34 @@ class BomItemCreate(AjaxCreateView):
part_id = form['part'].value() part_id = form['part'].value()
# Construct a queryset for the part field
part_query = Part.objects.filter(active=True)
# Construct a queryset for the sub_part field
sub_part_query = Part.objects.filter(
component=True,
active=True
)
try: try:
part = Part.objects.get(id=part_id) part = Part.objects.get(id=part_id)
# Only allow active parts to be selected
query = form.fields['part'].queryset.filter(active=True)
form.fields['part'].queryset = query
# Don't allow selection of sub_part objects which are already added to the Bom!
query = form.fields['sub_part'].queryset
# Don't allow a part to be added to its own BOM # Hide the 'part' field
query = query.exclude(id=part.id) form.fields['part'].widget = HiddenInput()
query = query.filter(active=True)
# Exclude the part from its own BOM
sub_part_query = sub_part_query.exclude(id=part.id)
# Eliminate any options that are already in the BOM! # Eliminate any options that are already in the BOM!
query = query.exclude(id__in=[item.id for item in part.getRequiredParts()]) sub_part_query = sub_part_query.exclude(id__in=[item.id for item in part.getRequiredParts()])
form.fields['sub_part'].queryset = query
form.fields['part'].widget = HiddenInput()
except (ValueError, Part.DoesNotExist): except (ValueError, Part.DoesNotExist):
pass pass
# Set the querysets for the fields
form.fields['part'].queryset = part_query
form.fields['sub_part'].queryset = sub_part_query
return form return form
def get_initial(self): def get_initial(self):
@ -2492,6 +2496,8 @@ class BomItemEdit(AjaxUpdateView):
- Remove any part items that are already in the BOM - Remove any part items that are already in the BOM
""" """
item = self.get_object()
form = super().get_form() form = super().get_form()
part_id = form['part'].value() part_id = form['part'].value()
@ -2499,9 +2505,14 @@ class BomItemEdit(AjaxUpdateView):
try: try:
part = Part.objects.get(pk=part_id) part = Part.objects.get(pk=part_id)
query = form.fields['sub_part'].queryset # Construct a queryset
query = Part.objects.filter(component=True)
# Reduce the available selection options # Limit to "active" items, *unless* the currently selected item is not active
if item.sub_part.active:
query = query.filter(active=True)
# Prevent the parent part from being selected
query = query.exclude(pk=part_id) query = query.exclude(pk=part_id)
# Eliminate any options that are already in the BOM, # Eliminate any options that are already in the BOM,