Skip to content
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
aa0e77e
Adds "consumed" field to BuildLine model
SchrodingersGat Sep 26, 2024
c8b37be
Expose new field to serializer
SchrodingersGat Sep 26, 2024
11fdb92
Add "consumed" column to BuildLineTable
SchrodingersGat Sep 26, 2024
81eb49f
Boolean column tweaks
SchrodingersGat Sep 26, 2024
2dbe8b8
Increase consumed count when completing allocation
SchrodingersGat Sep 26, 2024
7c6aac4
Add comment
SchrodingersGat Sep 26, 2024
5f96763
Merge branch 'master' into build-order-consume
SchrodingersGat Oct 1, 2024
3117555
Merge remote-tracking branch 'origin/master' into build-order-consume
SchrodingersGat Oct 16, 2024
d07e2ef
Merge branch 'build-order-consume' of github.com:SchrodingersGat/Inve…
SchrodingersGat Oct 16, 2024
c9858a6
Merge branch 'master' into build-order-consume
SchrodingersGat Oct 17, 2024
ec5987c
Merge branch 'master' into build-order-consume
SchrodingersGat Oct 24, 2024
440d268
Merge branch 'master' into build-order-consume
SchrodingersGat Nov 2, 2024
4c63975
Merge branch 'build-order-consume' of github.com:SchrodingersGat/Inve…
SchrodingersGat Nov 2, 2024
d559ef8
Merge branch 'master' into build-order-consume
SchrodingersGat Nov 4, 2024
4c9b7a9
Merge branch 'master' into build-order-consume
SchrodingersGat Nov 19, 2024
b3a1502
Merge branch 'master' into build-order-consume
SchrodingersGat Nov 22, 2024
ac82968
Merge branch 'master' into build-order-consume
SchrodingersGat Nov 27, 2024
4287af7
Merge branch 'master' into build-order-consume
SchrodingersGat Dec 16, 2024
215d4a7
Merge branch 'master' into build-order-consume
SchrodingersGat Dec 27, 2024
70d67fb
Merge branch 'master' into build-order-consume
SchrodingersGat Dec 28, 2024
9cea437
Merge branch 'master' into build-order-consume
SchrodingersGat Jan 5, 2025
b2f2568
Merge branch 'master' into build-order-consume
SchrodingersGat Jan 6, 2025
f3c38e9
Merge branch 'master' into build-order-consume
SchrodingersGat Jan 7, 2025
e4ff60a
Merge branch 'master' into build-order-consume
SchrodingersGat Jan 10, 2025
ef7fbec
Merge branch 'master' into build-order-consume
SchrodingersGat Jan 19, 2025
05c4e63
Merge branch 'master' into build-order-consume
SchrodingersGat Jan 20, 2025
54616a2
Merge branch 'master' into build-order-consume
SchrodingersGat Feb 8, 2025
8b68216
Update migration
SchrodingersGat Feb 8, 2025
d62b968
Add serializer for consuming build items
SchrodingersGat Feb 8, 2025
af1f62c
Improve build-line sub-table
SchrodingersGat Feb 8, 2025
9a26b52
Refactor BuildItem.complete_allocation method
SchrodingersGat Feb 8, 2025
5d3cc1f
Perform consumption
SchrodingersGat Feb 8, 2025
e59d10f
Add "BuildConsume" API endpoint
SchrodingersGat Feb 8, 2025
2fef4a9
Implement frontend form
SchrodingersGat Feb 8, 2025
2bafdf0
Fixes for serializer
SchrodingersGat Feb 8, 2025
7912a2f
Enhance front-end form
SchrodingersGat Feb 8, 2025
cf8a457
Fix rendering of BuildLineTable
SchrodingersGat Feb 8, 2025
af96a1f
Further improve rendering
SchrodingersGat Feb 8, 2025
9a3c980
Bump API version
SchrodingersGat Feb 8, 2025
9faf3a2
Update API description
SchrodingersGat Feb 8, 2025
8e436e4
Add option to consume by specifying a list of BuildLine objects
SchrodingersGat Feb 8, 2025
2593151
Add form to consume stock via BuildLine reference
SchrodingersGat Feb 8, 2025
edc5931
Merge branch 'master' into build-order-consume
SchrodingersGat Feb 8, 2025
10b7794
Merge remote-tracking branch 'origin/master' into build-order-consume
SchrodingersGat Mar 17, 2025
48fdbfb
Merge branch 'master' into build-order-consume
SchrodingersGat Mar 26, 2025
c43cf9c
Merge branch 'build-order-consume' of github.com:SchrodingersGat/Inve…
SchrodingersGat Mar 30, 2025
19e0b2b
Merge branch 'master' into build-order-consume
SchrodingersGat Mar 30, 2025
b4b61c3
Merge branch 'master' into build-order-consume
SchrodingersGat Apr 6, 2025
8e71235
Merge branch 'master' into build-order-consume
SchrodingersGat Apr 18, 2025
2afcb4d
Merge remote-tracking branch 'origin/master' into build-order-consume
SchrodingersGat Jun 15, 2025
811c188
Fix api_version
SchrodingersGat Jun 15, 2025
eeff864
Fix backup colors
SchrodingersGat Jun 15, 2025
693d536
Fix typo
SchrodingersGat Jun 15, 2025
71dfadf
Merge branch 'master' into build-order-consume
SchrodingersGat Jun 17, 2025
4deefc7
Merge branch 'master' into build-order-consume
SchrodingersGat Jul 16, 2025
a68ac77
Fix migrations
SchrodingersGat Jul 16, 2025
debf1d5
Fix build forms
SchrodingersGat Jul 16, 2025
d67cd9e
Forms fixes
SchrodingersGat Jul 16, 2025
62e7253
Fix formatting
SchrodingersGat Jul 16, 2025
46fdbe3
Merge branch 'master' into build-order-consume
SchrodingersGat Jul 17, 2025
068e478
Merge branch 'master' into build-order-consume
SchrodingersGat Jul 18, 2025
79738eb
Merge branch 'master' into build-order-consume
SchrodingersGat Jul 23, 2025
34b7567
Merge branch 'build-order-consume' of github.com:SchrodingersGat/Inve…
SchrodingersGat Aug 11, 2025
fdda1e2
Merge branch 'master' into build-order-consume
SchrodingersGat Aug 11, 2025
ab95eff
Merge branch 'master' into build-order-consume
SchrodingersGat Aug 17, 2025
c8c6c60
Fixes for BuildLineTable
SchrodingersGat Aug 17, 2025
9d9ea32
Account for consumed stock in requirements calculation
SchrodingersGat Aug 17, 2025
51ce7f3
Reduce API requirements for BuildLineTable
SchrodingersGat Aug 17, 2025
08811f2
Docs updates
SchrodingersGat Aug 17, 2025
af14392
Updated playwright testing
SchrodingersGat Aug 17, 2025
eb4aad3
Update src/frontend/src/forms/BuildForms.tsx
SchrodingersGat Aug 17, 2025
8daa28d
Update src/frontend/src/tables/build/BuildLineTable.tsx
SchrodingersGat Aug 17, 2025
f07d6a0
Add unit test for filters
SchrodingersGat Aug 17, 2025
c0b4711
Add functional tests
SchrodingersGat Aug 17, 2025
04acad6
Tweak query count
SchrodingersGat Aug 17, 2025
5576014
Increase max query time for testing
SchrodingersGat Aug 17, 2025
2a46bb6
Merge branch 'master' into build-order-consume
SchrodingersGat Aug 17, 2025
07dca5c
adjust unit test again
SchrodingersGat Aug 17, 2025
ab4f933
Prevent consumption of "tracked" items
SchrodingersGat Aug 17, 2025
e5d21f7
Adjust playwright tests
SchrodingersGat Aug 18, 2025
d6af8ba
Merge branch 'build-order-consume' of github.com:SchrodingersGat/Inve…
SchrodingersGat Aug 18, 2025
dacf64b
Merge branch 'master' into build-order-consume
SchrodingersGat Aug 18, 2025
0f98de3
Fix table
SchrodingersGat Aug 18, 2025
e0da640
Fix rendering
SchrodingersGat Aug 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions docs/docs/manufacturing/allocate.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,49 @@ Here we can see that the incomplete build outputs (serial numbers 15 and 14) now
!!! note "Example: Tracked Stock"
Let's say we have 5 units of "Tracked Part" in stock - with 1 unit allocated to the build output. Once we complete the build output, there will be 4 units of "Tracked Part" in stock, with 1 unit being marked as "installed" within the assembled part

## Consuming Stock

Allocating stock items to a build order does not immediately remove them from stock. Instead, the stock items are marked as "allocated" against the build order, and are only removed from stock when they are "consumed" by the build order.

In the *Required Parts* tab, you can see the *consumed* vs *allocated* state of each line item in the BOM:

{{ image("build/parts_allocated_consumed.png", "Partially allocated and consumed") }}

Consuming items against the build order can be performed in two ways:

- Manually, by consuming selected stock allocations against the build order
- Automatically, by completing the build order

### Manual Consumption

Manual consuming stock items (before the build order is completed) can be performed at any point after stock has been allocated against the build order. Manual stock consumption may be desired in some situations, for example if the build order is being performed in stages, or to ensure that stock levels are kept up to date.

Manual consumption of stock items can be performed in the in the following ways:

#### Required Parts Tab

Consuming stock items can be performed against BOM line items in the *Required Parts* tab, either against a single line or multiple selected lines:

- Navigate to the *Required Parts* tab
- Select the individual line items which you wish to consume
- Click the *Consume Stock* button

#### Allocated Stock Tab

Consuming stock items can also be performed against the *Allocated Stock* tab, either against a single allocation or multiple allocations:

- Navigate to the *Allocated Stock* tab
- Select the individual stock allocations which you wish to consume
- Click the *Consume Stock* button

### Automatic Consumption

When a build order is completed, all remaining allocated stock items are automatically consumed by the build order.

### Returning Items to Stock

Consumed items may be manually returned into stock if required. This can be performed in the *Consumed Stock* tab.

## Completing a Build

!!! warning "Complete Build Outputs"
Expand Down
6 changes: 5 additions & 1 deletion src/backend/InvenTree/InvenTree/api_version.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
"""InvenTree API version information."""

# InvenTree API version
INVENTREE_API_VERSION = 385
INVENTREE_API_VERSION = 386

"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""

INVENTREE_API_TEXT = """
v386 -> 2025-08-11 : https://github.com/inventree/InvenTree/pull/8191
- Adds "consumed" field to the BuildItem API
- Adds API endpoint to consume stock against a BuildOrder

v385 -> 2025-08-15 : https://github.com/inventree/InvenTree/pull/10174
- Adjust return type of PurchaseOrderReceive API serializer
- Now returns list of of the created stock items when receiving
Expand Down
22 changes: 19 additions & 3 deletions src/backend/InvenTree/build/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,14 @@ def filter_allocated(self, queryset, name, value):
return queryset.filter(allocated__gte=F('quantity'))
return queryset.filter(allocated__lt=F('quantity'))

consumed = rest_filters.BooleanFilter(label=_('Consumed'), method='filter_consumed')

def filter_consumed(self, queryset, name, value):
"""Filter by whether each BuildLine is fully consumed."""
if str2bool(value):
return queryset.filter(consumed__gte=F('quantity'))
return queryset.filter(consumed__lt=F('quantity'))

available = rest_filters.BooleanFilter(
label=_('Available'), method='filter_available'
)
Expand All @@ -504,7 +512,7 @@ def filter_available(self, queryset, name, value):
return queryset.exclude(flt)


class BuildLineEndpoint:
class BuildLineMixin:
"""Mixin class for BuildLine API endpoints."""

queryset = BuildLine.objects.all()
Expand Down Expand Up @@ -553,7 +561,7 @@ def get_queryset(self):
)


class BuildLineList(BuildLineEndpoint, DataExportViewMixin, ListCreateAPI):
class BuildLineList(BuildLineMixin, DataExportViewMixin, ListCreateAPI):
"""API endpoint for accessing a list of BuildLine objects."""

filterset_class = BuildLineFilter
Expand Down Expand Up @@ -605,7 +613,7 @@ def get_source_build(self) -> Build | None:
return source_build


class BuildLineDetail(BuildLineEndpoint, RetrieveUpdateDestroyAPI):
class BuildLineDetail(BuildLineMixin, RetrieveUpdateDestroyAPI):
"""API endpoint for detail view of a BuildLine object."""

def get_source_build(self) -> Build | None:
Expand Down Expand Up @@ -734,6 +742,13 @@ class BuildAllocate(BuildOrderContextMixin, CreateAPI):
serializer_class = build.serializers.BuildAllocationSerializer


class BuildConsume(BuildOrderContextMixin, CreateAPI):
"""API endpoint to consume stock against a build order."""

queryset = Build.objects.none()
serializer_class = build.serializers.BuildConsumeSerializer


class BuildIssue(BuildOrderContextMixin, CreateAPI):
"""API endpoint for issuing a BuildOrder."""

Expand Down Expand Up @@ -953,6 +968,7 @@ def filter_queryset(self, queryset):
'<int:pk>/',
include([
path('allocate/', BuildAllocate.as_view(), name='api-build-allocate'),
path('consume/', BuildConsume.as_view(), name='api-build-consume'),
path(
'auto-allocate/',
BuildAutoAllocate.as_view(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.2.15 on 2024-09-26 10:11

import django.core.validators
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('build', '0057_build_external'),
]

operations = [
migrations.AddField(
model_name='buildline',
name='consumed',
field=models.DecimalField(decimal_places=5, default=0, help_text='Quantity of consumed stock', max_digits=15, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Consumed'),
),
]
56 changes: 49 additions & 7 deletions src/backend/InvenTree/build/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1106,7 +1106,7 @@ def subtract_allocated_stock(self, user):

# Remove stock
for item in items:
item.complete_allocation(user)
item.complete_allocation(user=user)

# Delete allocation
items.all().delete()
Expand Down Expand Up @@ -1151,7 +1151,7 @@ def scrap_build_output(self, output, quantity, location, **kwargs):
# Complete or discard allocations
for build_item in allocated_items:
if not discard_allocations:
build_item.complete_allocation(user)
build_item.complete_allocation(user=user)

# Delete allocations
allocated_items.delete()
Expand Down Expand Up @@ -1200,7 +1200,7 @@ def complete_build_output(self, output, user, **kwargs):

for build_item in allocated_items:
# Complete the allocation of stock for that item
build_item.complete_allocation(user)
build_item.complete_allocation(user=user)

# Delete the BuildItem objects from the database
allocated_items.all().delete()
Expand Down Expand Up @@ -1569,6 +1569,7 @@ class BuildLine(report.mixins.InvenTreeReportMixin, InvenTree.models.InvenTreeMo
build: Link to a Build object
bom_item: Link to a BomItem object
quantity: Number of units required for the Build
consumed: Number of units which have been consumed against this line item
"""

class Meta:
Expand Down Expand Up @@ -1614,6 +1615,15 @@ def report_context(self) -> BuildLineReportContext:
help_text=_('Required quantity for build order'),
)

consumed = models.DecimalField(
decimal_places=5,
max_digits=15,
default=0,
validators=[MinValueValidator(0)],
verbose_name=_('Consumed'),
help_text=_('Quantity of consumed stock'),
)

@property
def part(self):
"""Return the sub_part reference from the link bom_item."""
Expand Down Expand Up @@ -1645,6 +1655,10 @@ def is_overallocated(self):
"""Return True if this BuildLine is over-allocated."""
return self.allocated_quantity() > self.quantity

def is_fully_consumed(self):
"""Return True if this BuildLine is fully consumed."""
return self.consumed >= self.quantity


class BuildItem(InvenTree.models.InvenTreeMetadataModel):
"""A BuildItem links multiple StockItem objects to a Build.
Expand Down Expand Up @@ -1812,20 +1826,36 @@ def bom_item(self):
return self.build_line.bom_item if self.build_line else None

@transaction.atomic
def complete_allocation(self, user, notes=''):
def complete_allocation(self, quantity=None, notes='', user=None):
"""Complete the allocation of this BuildItem into the output stock item.

Arguments:
quantity: The quantity to allocate (default is the full quantity)
notes: Additional notes to add to the transaction
user: The user completing the allocation

- If the referenced part is trackable, the stock item will be *installed* into the build output
- If the referenced part is *not* trackable, the stock item will be *consumed* by the build order

TODO: This is quite expensive (in terms of number of database hits) - and requires some thought
TODO: Revisit, and refactor!

"""
# If the quantity is not provided, use the quantity of this BuildItem
if quantity is None:
quantity = self.quantity

item = self.stock_item

# Ensure we are not allocating more than available
if quantity > item.quantity:
raise ValidationError({
'quantity': _('Allocated quantity exceeds available stock quantity')
})

# Split the allocated stock if there are more available than allocated
if item.quantity > self.quantity:
item = item.splitStock(self.quantity, None, user, notes=notes)
if item.quantity > quantity:
item = item.splitStock(quantity, None, user, notes=notes)

# For a trackable part, special consideration needed!
if item.part.trackable:
Expand All @@ -1835,7 +1865,7 @@ def complete_allocation(self, user, notes=''):

# Install the stock item into the output
self.install_into.installStockItem(
item, self.quantity, user, notes, build=self.build
item, quantity, user, notes, build=self.build
)

else:
Expand All @@ -1851,6 +1881,18 @@ def complete_allocation(self, user, notes=''):
deltas={'buildorder': self.build.pk, 'quantity': float(item.quantity)},
)

# Increase the "consumed" count for the associated BuildLine
self.build_line.consumed += quantity
self.build_line.save()

# Decrease the allocated quantity
self.quantity = max(0, self.quantity - quantity)

if self.quantity <= 0:
self.delete()
else:
self.save()

build_line = models.ForeignKey(
BuildLine, on_delete=models.CASCADE, null=True, related_name='allocations'
)
Expand Down
Loading
Loading