mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Adds "stock value" calculation to stock table (#4471)
* Add part pricing data to stockitem list serializer * Add "stock value" column to stock list table
This commit is contained in:
parent
34875828d7
commit
2edb7f2b55
@ -281,6 +281,8 @@ class PartBriefSerializer(InvenTreeModelSerializer):
|
|||||||
'trackable',
|
'trackable',
|
||||||
'virtual',
|
'virtual',
|
||||||
'units',
|
'units',
|
||||||
|
'pricing_min',
|
||||||
|
'pricing_max',
|
||||||
]
|
]
|
||||||
|
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
@ -289,6 +291,10 @@ class PartBriefSerializer(InvenTreeModelSerializer):
|
|||||||
|
|
||||||
thumbnail = serializers.CharField(source='get_thumbnail_url', read_only=True)
|
thumbnail = serializers.CharField(source='get_thumbnail_url', read_only=True)
|
||||||
|
|
||||||
|
# Pricing fields
|
||||||
|
pricing_min = InvenTreeMoneySerializer(source='pricing_data.overall_min', allow_null=True, read_only=True)
|
||||||
|
pricing_max = InvenTreeMoneySerializer(source='pricing_data.overall_max', allow_null=True, read_only=True)
|
||||||
|
|
||||||
|
|
||||||
class DuplicatePartSerializer(serializers.Serializer):
|
class DuplicatePartSerializer(serializers.Serializer):
|
||||||
"""Serializer for specifying options when duplicating a Part.
|
"""Serializer for specifying options when duplicating a Part.
|
||||||
|
@ -165,6 +165,8 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
queryset = queryset.prefetch_related(
|
queryset = queryset.prefetch_related(
|
||||||
'sales_order',
|
'sales_order',
|
||||||
'purchase_order',
|
'purchase_order',
|
||||||
|
'part',
|
||||||
|
'part__pricing_data',
|
||||||
)
|
)
|
||||||
|
|
||||||
# Annotate the queryset with the total allocated to sales orders
|
# Annotate the queryset with the total allocated to sales orders
|
||||||
|
@ -136,7 +136,7 @@ function calculateTotalPrice(dataset, value_func, currency_func, options={}) {
|
|||||||
|
|
||||||
var currency = options.currency;
|
var currency = options.currency;
|
||||||
|
|
||||||
var rates = getCurrencyConversionRates();
|
var rates = options.rates || getCurrencyConversionRates();
|
||||||
|
|
||||||
if (!rates) {
|
if (!rates) {
|
||||||
console.error('Could not retrieve currency conversion information from the server');
|
console.error('Could not retrieve currency conversion information from the server');
|
||||||
|
@ -2065,6 +2065,86 @@ function loadStockTable(table, options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Total value of stock
|
||||||
|
// This is not sortable, and may default to the 'price range' for the parent part
|
||||||
|
columns.push({
|
||||||
|
field: 'stock_value',
|
||||||
|
title: '{% trans "Stock Value" %}',
|
||||||
|
sortable: false,
|
||||||
|
switchable: true,
|
||||||
|
formatter: function(value, row) {
|
||||||
|
let min_price = row.purchase_price;
|
||||||
|
let max_price = row.purchase_price;
|
||||||
|
let currency = row.purchase_price_currency;
|
||||||
|
|
||||||
|
if (min_price == null && max_price == null && row.part_detail) {
|
||||||
|
min_price = row.part_detail.pricing_min;
|
||||||
|
max_price = row.part_detail.pricing_max;
|
||||||
|
currency = baseCurrency();
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatPriceRange(
|
||||||
|
min_price,
|
||||||
|
max_price,
|
||||||
|
{
|
||||||
|
quantity: row.quantity,
|
||||||
|
currency: currency
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
footerFormatter: function(data) {
|
||||||
|
// Display overall range of value for the selected items
|
||||||
|
let rates = getCurrencyConversionRates();
|
||||||
|
let base = baseCurrency();
|
||||||
|
|
||||||
|
let min_price = calculateTotalPrice(
|
||||||
|
data,
|
||||||
|
function(row) {
|
||||||
|
return row.quantity * (row.purchase_price || row.part_detail.pricing_min);
|
||||||
|
},
|
||||||
|
function(row) {
|
||||||
|
if (row.purchase_price) {
|
||||||
|
return row.purchase_price_currency;
|
||||||
|
} else {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
currency: base,
|
||||||
|
rates: rates,
|
||||||
|
raw: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let max_price = calculateTotalPrice(
|
||||||
|
data,
|
||||||
|
function(row) {
|
||||||
|
return row.quantity * (row.purchase_price || row.part_detail.pricing_max);
|
||||||
|
},
|
||||||
|
function(row) {
|
||||||
|
if (row.purchase_price) {
|
||||||
|
return row.purchase_price_currency;
|
||||||
|
} else {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
currency: base,
|
||||||
|
rates: rates,
|
||||||
|
raw: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return formatPriceRange(
|
||||||
|
min_price,
|
||||||
|
max_price,
|
||||||
|
{
|
||||||
|
currency: base,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
columns.push({
|
columns.push({
|
||||||
field: 'packaging',
|
field: 'packaging',
|
||||||
title: '{% trans "Packaging" %}',
|
title: '{% trans "Packaging" %}',
|
||||||
@ -2085,6 +2165,7 @@ function loadStockTable(table, options) {
|
|||||||
name: 'stock',
|
name: 'stock',
|
||||||
original: original,
|
original: original,
|
||||||
showColumns: true,
|
showColumns: true,
|
||||||
|
showFooter: true,
|
||||||
columns: columns,
|
columns: columns,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user