2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-18 21:15:41 +00:00

Build order improvements (#6343)

* Auto-fill project code

When creating a new child build order, copy project code from parent build

* Auto-fill project code for sales orders

* Annotate "building" quantity to BuildLine serializer

- So we know how many units are in production

* Display building quantity in build line table

* Update API version info

* Skeleton for BuildLineTable

- No content yet (needs work)

* Refactor part hovercard

* Navigate to part

* Add actions for build line table

* Display more information for "available stock" column

* More updates

* Fix "building" filter

- Rename to "in_production"

* Add filters

* Remove unused imports
This commit is contained in:
Oliver
2024-01-29 10:56:34 +11:00
committed by GitHub
parent 1272b89839
commit f6ba180cc4
14 changed files with 334 additions and 49 deletions

View File

@ -1,11 +1,14 @@
"""InvenTree API version information."""
# InvenTree API version
INVENTREE_API_VERSION = 163
INVENTREE_API_VERSION = 164
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """
v164 -> 2024-01-24 : https://github.com/inventree/InvenTree/pull/6343
- Adds "building" quantity to BuildLine API serializer
v163 -> 2024-01-22 : https://github.com/inventree/InvenTree/pull/6314
- Extends API endpoint to expose auth configuration information for signin pages

View File

@ -1,5 +1,7 @@
"""JSON serializers for Build API."""
from decimal import Decimal
from django.db import transaction
from django.core.exceptions import ValidationError as DjangoValidationError
from django.utils.translation import gettext_lazy as _
@ -7,18 +9,20 @@ from django.utils.translation import gettext_lazy as _
from django.db import models
from django.db.models import ExpressionWrapper, F, FloatField
from django.db.models import Case, Sum, When, Value
from django.db.models import BooleanField
from django.db.models import BooleanField, Q
from django.db.models.functions import Coalesce
from rest_framework import serializers
from rest_framework.serializers import ValidationError
from sql_util.utils import SubquerySum
from InvenTree.serializers import InvenTreeModelSerializer, InvenTreeAttachmentSerializer
from InvenTree.serializers import UserSerializer
import InvenTree.helpers
from InvenTree.serializers import InvenTreeDecimalField
from InvenTree.status_codes import StockStatus
from InvenTree.status_codes import BuildStatusGroups, StockStatus
from stock.models import generate_batch_code, StockItem, StockLocation
from stock.serializers import StockItemSerializerBrief, LocationSerializer
@ -1055,6 +1059,7 @@ class BuildLineSerializer(InvenTreeModelSerializer):
# Annotated fields
'allocated',
'in_production',
'on_order',
'available_stock',
'available_substitute_stock',
@ -1078,6 +1083,7 @@ class BuildLineSerializer(InvenTreeModelSerializer):
# Annotated (calculated) fields
allocated = serializers.FloatField(read_only=True)
on_order = serializers.FloatField(read_only=True)
in_production = serializers.FloatField(read_only=True)
available_stock = serializers.FloatField(read_only=True)
available_substitute_stock = serializers.FloatField(read_only=True)
available_variant_stock = serializers.FloatField(read_only=True)
@ -1090,6 +1096,7 @@ class BuildLineSerializer(InvenTreeModelSerializer):
- allocated: Total stock quantity allocated against this build line
- available: Total stock available for allocation against this build line
- on_order: Total stock on order for this build line
- in_production: Total stock currently in production for this build line
"""
queryset = queryset.select_related(
'build', 'bom_item',
@ -1126,6 +1133,11 @@ class BuildLineSerializer(InvenTreeModelSerializer):
ref = 'bom_item__sub_part__'
# Annotate the "in_production" quantity
queryset = queryset.annotate(
in_production=part.filters.annotate_in_production_quantity(reference=ref)
)
# Annotate the "on_order" quantity
# Difficulty: Medium
queryset = queryset.annotate(

View File

@ -373,7 +373,11 @@ onPanelLoad('allocate', function() {
loadBuildLineTable(
"#build-lines-table",
{{ build.pk }},
{}
{
{% if build.project_code %}
project_code: {{ build.project_code.pk }},
{% endif %}
}
);
});

View File

@ -243,6 +243,9 @@
order: {{ order.pk }},
reference: '{{ order.reference }}',
status: {{ order.status }},
{% if order.project_code %}
project_code: {{ order.project_code.pk }},
{% endif %}
open: {% js_bool order.is_open %},
{% if roles.sales_order.change %}
{% settings_value "SALESORDER_EDIT_COMPLETED_ORDERS" as allow_edit %}

View File

@ -47,6 +47,25 @@ from InvenTree.status_codes import (
)
def annotate_in_production_quantity(reference=''):
"""Annotate the 'in production' quantity for each part in a queryset.
Sum the 'quantity' field for all stock items which are 'in production' for each part.
Arguments:
reference: Reference to the part from the current queryset (default = '')
"""
building_filter = Q(
is_building=True, build__status__in=BuildStatusGroups.ACTIVE_CODES
)
return Coalesce(
SubquerySum(f'{reference}stock_items__quantity', filter=building_filter),
Decimal(0),
output_field=DecimalField(),
)
def annotate_on_order_quantity(reference: str = ''):
"""Annotate the 'on order' quantity for each part in a queryset.

View File

@ -173,6 +173,11 @@ function newBuildOrder(options={}) {
fields.sales_order.value = options.sales_order;
}
// Specify a project code
if (options.project_code) {
fields.project_code.value = options.project_code;
}
if (options.data) {
delete options.data.pk;
}
@ -2553,6 +2558,7 @@ function loadBuildLineTable(table, build_id, options={}) {
sortable: true,
formatter: function(value, row) {
var url = `/part/${row.part_detail.pk}/?display=part-stock`;
// Calculate the "available" quantity
let available = row.available_stock + row.available_substitute_stock;
@ -2603,6 +2609,10 @@ function loadBuildLineTable(table, build_id, options={}) {
icons += makeIconBadge('fa-shopping-cart', `{% trans "On Order" %}: ${formatDecimal(row.on_order)}`);
}
if (row.in_production && row.in_production > 0) {
icons += makeIconBadge('fa-tools icon-blue', `{% trans "In Production" %}: ${formatDecimal(row.in_production)}`);
}
return renderLink(text, url) + icons;
}
},
@ -2695,6 +2705,7 @@ function loadBuildLineTable(table, build_id, options={}) {
part: row.part_detail.pk,
parent: build_id,
quantity: Math.max(row.quantity - row.allocated, 0),
...options,
});
});

View File

@ -2174,7 +2174,8 @@ function loadSalesOrderLineItemTable(table, options={}) {
part: pk,
sales_order: options.order,
quantity: quantity,
success: reloadTable
success: reloadTable,
...options
});
});