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:
@ -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
|
||||
|
||||
|
@ -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(
|
||||
|
@ -373,7 +373,11 @@ onPanelLoad('allocate', function() {
|
||||
loadBuildLineTable(
|
||||
"#build-lines-table",
|
||||
{{ build.pk }},
|
||||
{}
|
||||
{
|
||||
{% if build.project_code %}
|
||||
project_code: {{ build.project_code.pk }},
|
||||
{% endif %}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -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 %}
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -2174,7 +2174,8 @@ function loadSalesOrderLineItemTable(table, options={}) {
|
||||
part: pk,
|
||||
sales_order: options.order,
|
||||
quantity: quantity,
|
||||
success: reloadTable
|
||||
success: reloadTable,
|
||||
...options
|
||||
});
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user