2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-10-03 15:52:51 +00:00

Improve typing (#10408)

* Improve typing

- build/models.py

* More typing
This commit is contained in:
Oliver
2025-09-27 14:14:50 +10:00
committed by GitHub
parent 6fdc6b3a8c
commit 1279001d8e

View File

@@ -1,6 +1,7 @@
"""Build database model definitions."""
import decimal
from typing import Optional
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
@@ -422,14 +423,14 @@ class Build(
help_text=_('Project code for this build order'),
)
def sub_builds(self, cascade=True):
def sub_builds(self, cascade: bool = True) -> QuerySet:
"""Return all Build Order objects under this one."""
if cascade:
return self.get_descendants(include_self=False)
else:
return self.get_children()
def sub_build_count(self, cascade=True):
def sub_build_count(self, cascade: bool = True) -> int:
"""Return the number of sub builds under this one.
Args:
@@ -438,14 +439,14 @@ class Build(
return self.sub_builds(cascade=cascade).count()
@property
def has_open_child_builds(self):
def has_open_child_builds(self) -> bool:
"""Return True if this build order has any open child builds."""
return (
self.sub_builds().filter(status__in=BuildStatusGroups.ACTIVE_CODES).exists()
)
@property
def is_overdue(self):
def is_overdue(self) -> bool:
"""Returns true if this build is "overdue".
Makes use of the OVERDUE_FILTER to avoid code duplication
@@ -459,30 +460,30 @@ class Build(
return query.exists()
@property
def active(self):
def active(self) -> bool:
"""Return True if this build is active."""
return self.status in BuildStatusGroups.ACTIVE_CODES
@property
def tracked_line_items(self):
def tracked_line_items(self) -> QuerySet:
"""Returns the "trackable" BOM lines for this BuildOrder."""
return self.build_lines.filter(bom_item__sub_part__trackable=True)
def has_tracked_line_items(self):
def has_tracked_line_items(self) -> bool:
"""Returns True if this BuildOrder has trackable BomItems."""
return self.tracked_line_items.count() > 0
@property
def untracked_line_items(self):
def untracked_line_items(self) -> bool:
"""Returns the "non trackable" BOM items for this BuildOrder."""
return self.build_lines.filter(bom_item__sub_part__trackable=False)
@property
def are_untracked_parts_allocated(self):
def are_untracked_parts_allocated(self) -> bool:
"""Returns True if all untracked parts are allocated for this BuildOrder."""
return self.is_fully_allocated(tracked=False)
def has_untracked_line_items(self):
def has_untracked_line_items(self) -> bool:
"""Returns True if this BuildOrder has non trackable BomItems."""
return self.has_untracked_line_items.count() > 0
@@ -492,15 +493,15 @@ class Build(
return max(0, self.quantity - self.completed)
@property
def output_count(self):
def output_count(self) -> int:
"""Return the number of build outputs (StockItem) associated with this build order."""
return self.build_outputs.count()
def has_build_outputs(self):
def has_build_outputs(self) -> bool:
"""Returns True if this build has more than zero build outputs."""
return self.output_count > 0
def get_build_outputs(self, **kwargs):
def get_build_outputs(self, **kwargs) -> QuerySet:
"""Return a list of build outputs.
kwargs:
@@ -530,7 +531,7 @@ class Build(
return outputs
@property
def complete_outputs(self):
def complete_outputs(self) -> bool:
"""Return all the "completed" build outputs."""
outputs = self.get_build_outputs(complete=True)
@@ -546,12 +547,12 @@ class Build(
return quantity
def is_partially_allocated(self):
def is_partially_allocated(self) -> bool:
"""Test is this build order has any stock allocated against it."""
return self.allocated_stock.count() > 0
@property
def incomplete_outputs(self):
def incomplete_outputs(self) -> QuerySet:
"""Return all the "incomplete" build outputs."""
outputs = self.get_build_outputs(complete=False)
@@ -605,7 +606,7 @@ class Build(
return new_ref
@property
def can_complete(self):
def can_complete(self) -> bool:
"""Returns True if this BuildOrder is ready to be completed.
- Must not have any outstanding build outputs
@@ -630,7 +631,7 @@ class Build(
return self.is_fully_allocated(tracked=False)
@transaction.atomic
def complete_allocations(self, user):
def complete_allocations(self, user) -> None:
"""Complete all stock allocations for this build order.
- This function is called when a build order is completed
@@ -752,7 +753,7 @@ class Build(
)
@property
def can_issue(self):
def can_issue(self) -> bool:
"""Returns True if this BuildOrder can be issued."""
return self.status in [BuildStatus.PENDING.value, BuildStatus.ON_HOLD.value]
@@ -779,7 +780,7 @@ class Build(
)
@property
def can_hold(self):
def can_hold(self) -> bool:
"""Returns True if this BuildOrder can be placed on hold."""
return self.status in [BuildStatus.PENDING.value, BuildStatus.PRODUCTION.value]
@@ -1094,13 +1095,13 @@ class Build(
BuildItem.objects.filter(pk__in=[item.pk for item in items_to_delete]).delete()
@property
def allocated_stock(self):
def allocated_stock(self) -> QuerySet:
"""Returns a QuerySet object of all BuildItem objects which point back to this Build."""
return BuildItem.objects.filter(build_line__build=self)
@transaction.atomic
def subtract_allocated_stock(self, user):
"""Called when the Build is marked as "complete", this function removes the allocated untracked items from stock."""
def subtract_allocated_stock(self, user) -> None:
"""Removes the allocated untracked items from stock."""
# Find all BuildItem objects which point to this build
items = self.allocated_stock.filter(
build_line__bom_item__sub_part__trackable=False
@@ -1369,7 +1370,7 @@ class Build(
# Bulk-create the new BuildItem objects
BuildItem.objects.bulk_create(new_items)
def unallocated_lines(self, tracked=None):
def unallocated_lines(self, tracked: Optional[bool] = None) -> QuerySet:
"""Returns a list of BuildLine objects which have not been fully allocated."""
lines = self.build_lines.all()
@@ -1390,11 +1391,9 @@ class Build(
return lines
def is_fully_allocated(self, tracked=None):
def is_fully_allocated(self, tracked: Optional[bool] = None) -> bool:
"""Test if the BuildOrder has been fully allocated.
This is *true* if *all* associated BuildLine items have sufficient allocation
Arguments:
tracked: If True, only consider tracked BuildLine items. If False, only consider untracked BuildLine items.
@@ -1403,10 +1402,10 @@ class Build(
"""
return self.unallocated_lines(tracked=tracked).count() == 0
def is_output_fully_allocated(self, output):
def is_output_fully_allocated(self, output) -> bool:
"""Determine if the specified output (StockItem) has been fully allocated for this build.
Args:
Arguments:
output: StockItem object (the "in production" output to test against)
To determine if the output has been fully allocated,
@@ -1431,7 +1430,7 @@ class Build(
# At this stage, we can assume that the output is fully allocated
return True
def is_overallocated(self):
def is_overallocated(self) -> bool:
"""Test if the BuildOrder has been over-allocated.
Returns:
@@ -1450,7 +1449,7 @@ class Build(
return lines.count() > 0
@property
def is_active(self):
def is_active(self) -> bool:
"""Is this build active?
An active build is either:
@@ -1460,12 +1459,12 @@ class Build(
return self.status in BuildStatusGroups.ACTIVE_CODES
@property
def is_complete(self):
def is_complete(self) -> bool:
"""Returns True if the build status is COMPLETE."""
return self.status == BuildStatus.COMPLETE.value
@transaction.atomic
def create_build_line_items(self, prevent_duplicates=True):
def create_build_line_items(self, prevent_duplicates: bool = True) -> None:
"""Create BuildLine objects for each BOM line in this BuildOrder."""
lines = []
@@ -1500,7 +1499,7 @@ class Build(
logger.info('Created %s BuildLine objects for BuildOrder', len(lines))
@transaction.atomic
def update_build_line_items(self):
def update_build_line_items(self) -> None:
"""Rebuild required quantity field for each BuildLine object."""
lines_to_update = []
@@ -1660,7 +1659,7 @@ class BuildLine(report.mixins.InvenTreeReportMixin, InvenTree.models.InvenTreeMo
"""
return max(self.quantity - self.consumed - self.allocated_quantity(), 0)
def is_fully_allocated(self):
def is_fully_allocated(self) -> bool:
"""Return True if this BuildLine is fully allocated."""
if self.bom_item.consumable:
return True
@@ -1675,7 +1674,7 @@ class BuildLine(report.mixins.InvenTreeReportMixin, InvenTree.models.InvenTreeMo
return self.allocated_quantity() > required
def is_fully_consumed(self):
def is_fully_consumed(self) -> bool:
"""Return True if this BuildLine is fully consumed."""
return self.consumed >= self.quantity
@@ -1846,7 +1845,7 @@ class BuildItem(InvenTree.models.InvenTreeMetadataModel):
return self.build_line.bom_item if self.build_line else None
@transaction.atomic
def complete_allocation(self, quantity=None, notes='', user=None):
def complete_allocation(self, quantity=None, notes='', user=None) -> None:
"""Complete the allocation of this BuildItem into the output stock item.
Arguments: