Sales order variant stock (#5415)

* Annotate available variant stock to SalesOrderLine serializer

* Filter variant stock by:

- active = True
- salable = True

* Add 'salable' filter to StockList API

* Filter available stock in sales order table:

- Must be salable
- Must be active

* Update table display

* Bump API version
This commit is contained in:
Oliver 2023-08-09 21:45:12 +10:00 committed by GitHub
parent 1fe382e318
commit 62362455b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 7 deletions

View File

@ -2,11 +2,14 @@
# InvenTree API version
INVENTREE_API_VERSION = 130
INVENTREE_API_VERSION = 131
"""
Increment this API version number whenever there is a significant change to the API that any clients need to know about
v131 -> 2023-08-09 : https://github.com/inventree/InvenTree/pull/5415
- Annotate 'available_variant_stock' to the SalesOrderLine serializer
v130 -> 2023-07-14 : https://github.com/inventree/InvenTree/pull/5251
- Refactor label printing interface

View File

@ -862,6 +862,7 @@ class SalesOrderLineItemSerializer(InvenTreeModelSerializer):
'allocated',
'allocations',
'available_stock',
'available_variant_stock',
'customer_detail',
'quantity',
'reference',
@ -934,6 +935,26 @@ class SalesOrderLineItemSerializer(InvenTreeModelSerializer):
)
)
# Filter for "variant" stock: Variant stock items must be salable and active
variant_stock_query = part.filters.variant_stock_query(reference='part__').filter(
part__salable=True,
part__active=True
)
# Also add in available "variant" stock
queryset = queryset.alias(
variant_stock_total=part.filters.annotate_variant_quantity(variant_stock_query, reference='quantity'),
variant_bo_allocations=part.filters.annotate_variant_quantity(variant_stock_query, reference='sales_order_allocations__quantity'),
variant_so_allocations=part.filters.annotate_variant_quantity(variant_stock_query, reference='allocations__quantity'),
)
queryset = queryset.annotate(
available_variant_stock=ExpressionWrapper(
F('variant_stock_total') - F('variant_bo_allocations') - F('variant_so_allocations'),
output_field=models.DecimalField(),
)
)
return queryset
customer_detail = CompanyBriefSerializer(source='order.customer', many=False, read_only=True)
@ -944,6 +965,7 @@ class SalesOrderLineItemSerializer(InvenTreeModelSerializer):
# Annotated fields
overdue = serializers.BooleanField(required=False, read_only=True)
available_stock = serializers.FloatField(read_only=True)
available_variant_stock = serializers.FloatField(read_only=True)
quantity = InvenTreeDecimalField()

View File

@ -387,6 +387,7 @@ class StockFilter(rest_filters.FilterSet):
# Part attribute filters
assembly = rest_filters.BooleanFilter(label="Assembly", field_name='part__assembly')
active = rest_filters.BooleanFilter(label="Active", field_name='part__active')
salable = rest_filters.BooleanFilter(label="Salable", field_name='part__salable')
min_stock = rest_filters.NumberFilter(label='Minimum stock', field_name='quantity', lookup_expr='gte')
max_stock = rest_filters.NumberFilter(label='Maximum stock', field_name='quantity', lookup_expr='lte')

View File

@ -1308,6 +1308,8 @@ function allocateStockToSalesOrder(order_id, line_items, options={}) {
part_detail: true,
location_detail: true,
available: true,
salable: true,
active: true,
},
model: 'stockitem',
required: true,
@ -1881,17 +1883,20 @@ function loadSalesOrderLineItemTable(table, options={}) {
field: 'stock',
title: '{% trans "Available Stock" %}',
formatter: function(value, row) {
var available = row.available_stock;
var required = Math.max(row.quantity - row.allocated - row.shipped, 0);
var html = '';
let available = row.available_stock + row.available_variant_stock;
let required = Math.max(row.quantity - row.allocated - row.shipped, 0);
let html = '';
if (available > 0) {
var url = `/part/${row.part}/?display=part-stock`;
let url = `/part/${row.part}/?display=part-stock`;
var text = available;
html = renderLink(available, url);
html = renderLink(text, url);
if (row.available_variant_stock && row.available_variant_stock > 0) {
html += makeIconBadge('fa-info-circle icon-blue', '{% trans "Includes variant stock" %}');
}
} else {
html += `<span class='badge rounded-pill bg-danger'>{% trans "No Stock Available" %}</span>`;
}