diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html
index 1e5abb7ebc..42c5df622d 100644
--- a/InvenTree/stock/templates/stock/item_base.html
+++ b/InvenTree/stock/templates/stock/item_base.html
@@ -156,158 +156,7 @@
{% endif %}
- {% if item.serialized %}
-
- |
- {% trans "Serial Number" %} |
-
- {{ item.serial }}
-
- |
-
- {% else %}
-
- |
- {% trans "Quantity" %} |
- {% decimal item.quantity %} {% if item.part.units %}{{ item.part.units }}{% endif %} |
-
- {% endif %}
-
- |
- {% trans "Status" %} |
- {% stock_status_label item.status %} |
-
- {% if item.expiry_date %}
-
- |
- {% trans "Expiry Date" %} |
-
- {% render_date item.expiry_date %}
- {% if item.is_expired %}
- {% trans "Expired" %}
- {% elif item.is_stale %}
- {% trans "Stale" %}
- {% endif %}
- |
-
- {% endif %}
-
- |
- {% trans "Last Updated" %} |
- {{ item.updated }} |
-
-
- |
- {% trans "Last Stocktake" %} |
- {% if item.stocktake_date %}
- {% render_date item.stocktake_date %} {{ item.stocktake_user }} |
- {% else %}
- {% trans "No stocktake performed" %} |
- {% endif %}
-
-
-
-
-
- {% if item.is_building %}
-
- {% trans "This stock item is in production and cannot be edited." %}
- {% trans "Edit the stock item from the build view." %}
-
- {% if item.build %}
-
- {{ item.build }}
-
- {% endif %}
-
-
- {% endif %}
-
- {% if item.hasRequiredTests and not item.passedAllRequiredTests %}
-
- {% trans "This stock item has not passed all required tests" %}
-
- {% endif %}
-
- {% for allocation in item.sales_order_allocations.all %}
-
- {% object_link 'so-detail' allocation.line.order.id allocation.line.order as link %}
- {% decimal allocation.quantity as qty %}
- {% trans "This stock item is allocated to Sales Order" %} {{ link }} {% if qty < item.quantity %}({% trans "Quantity" %}: {{ qty }}){% endif %}
-
- {% endfor %}
-
- {% for allocation in item.allocations.all %}
-
- {% object_link 'build-detail' allocation.build.id allocation.build as link %}
- {% decimal allocation.quantity as qty %}
- {% trans "This stock item is allocated to Build Order" %} {{ link }} {% if qty < item.quantity %}({% trans "Quantity" %}: {{ qty }}){% endif %}
-
- {% endfor %}
-
- {% if item.serialized %}
-
- {% trans "This stock item is serialized - it has a unique serial number and the quantity cannot be adjusted." %}
-
- {% endif %}
-
-
-{% endblock details %}
-
-{% block details_right %}
-
-
-
- {% if item.customer %}
-
- |
- {% trans "Customer" %} |
- {{ item.customer.name }} |
-
- {% endif %}
- {% if item.belongs_to %}
-
- |
-
- {% trans "Installed In" %}
- |
-
- {{ item.belongs_to }}
- |
-
- {% elif item.sales_order %}
-
- |
- {% trans "Sales Order" %} |
- {{ item.sales_order.reference }} - {{ item.sales_order.customer.name }} |
-
- {% else %}
-
- |
- {% trans "Location" %} |
- {% if item.location %}
- {{ item.location.name }} |
- {% else %}
- {% trans "No location set" %} |
- {% endif %}
-
- {% endif %}
+
{% if item.uid %}
|
@@ -322,13 +171,6 @@
{{ item.batch }} |
{% endif %}
- {% if item.packaging %}
-
- |
- {% trans "Packaging" %} |
- {{ item.packaging }} |
-
- {% endif %}
{% if item.build %}
|
@@ -397,18 +239,11 @@
{{ item.supplier_part.SKU }} |
{% endif %}
- {% if item.hasRequiredTests %}
+ {% if item.packaging %}
- |
- {% trans "Tests" %} |
-
- {{ item.requiredTestStatus.passed }} / {{ item.requiredTestStatus.total }}
- {% if item.passedAllRequiredTests %}
-
- {% else %}
-
- {% endif %}
- |
+ |
+ {% trans "Packaging" %} |
+ {{ item.packaging }} |
{% endif %}
{% if ownership_enabled and item_owner %}
@@ -425,6 +260,199 @@
{% endif %}
+
+
+
+
+
+ {% if item.is_building %}
+
+ {% trans "This stock item is in production and cannot be edited." %}
+ {% trans "Edit the stock item from the build view." %}
+
+ {% if item.build %}
+
+ {{ item.build }}
+
+ {% endif %}
+
+
+ {% endif %}
+
+ {% if item.hasRequiredTests and not item.passedAllRequiredTests %}
+
+ {% trans "This stock item has not passed all required tests" %}
+
+ {% endif %}
+
+ {% for allocation in item.sales_order_allocations.all %}
+
+ {% object_link 'so-detail' allocation.line.order.id allocation.line.order as link %}
+ {% decimal allocation.quantity as qty %}
+ {% trans "This stock item is allocated to Sales Order" %} {{ link }} {% if qty < item.quantity %}({% trans "Quantity" %}: {{ qty }}){% endif %}
+
+ {% endfor %}
+
+ {% for allocation in item.allocations.all %}
+
+ {% object_link 'build-detail' allocation.build.id allocation.build as link %}
+ {% decimal allocation.quantity as qty %}
+ {% trans "This stock item is allocated to Build Order" %} {{ link }} {% if qty < item.quantity %}({% trans "Quantity" %}: {{ qty }}){% endif %}
+
+ {% endfor %}
+
+ {% if item.serialized %}
+
+ {% trans "This stock item is serialized - it has a unique serial number and the quantity cannot be adjusted." %}
+
+ {% endif %}
+
+{% endblock details %}
+
+{% block details_right %}
+
+
+
+
+ {% if item.serialized %}
+
+
+ |
+
+ {% trans "Serial Number" %}
+ |
+
+ |
+ {% else %}
+
+
+ |
+
+ {% trans "Available Quantity" %}
+ |
+
+ {% if item.quantity != available %}{% decimal available %} / {% endif %}{% decimal item.quantity %} {% if item.part.units %}{{ item.part.units }}{% endif %}
+ |
+ {% endif %}
+
+ {% if item.belongs_to %}
+
+ |
+
+ {% trans "Installed In" %}
+ |
+
+ {{ item.belongs_to }}
+ |
+
+ {% elif item.sales_order %}
+
+ |
+ {% trans "Sales Order" %} |
+ {{ item.sales_order.reference }} - {{ item.sales_order.customer.name }} |
+
+ {% else %}
+ {% if allocated_to_sales_orders %}
+
+ |
+ {% trans "Allocated to Sales Orders" %} |
+ {% decimal allocated_to_sales_orders %} |
+
+ {% endif %}
+ {% if allocated_to_build_orders %}
+
+ |
+ {% trans "Allocated to Build Orders" %} |
+ {% decimal allocated_to_build_orders %} |
+
+ {% endif %}
+
+ |
+ {% trans "Location" %} |
+ {% if item.location %}
+ {{ item.location.name }} |
+ {% elif not item.customer %}
+ {% trans "No location set" %} |
+ {% endif %}
+
+ {% endif %}
+ {% if item.customer %}
+
+ |
+ {% trans "Customer" %} |
+ {{ item.customer.name }} |
+
+ {% endif %}
+
+ {% if item.hasRequiredTests %}
+
+ |
+ {% trans "Tests" %} |
+
+ {{ item.requiredTestStatus.passed }} / {{ item.requiredTestStatus.total }}
+ {% if item.passedAllRequiredTests %}
+
+ {% else %}
+
+ {% endif %}
+ |
+
+ {% endif %}
+
+
+ |
+ {% trans "Status" %} |
+ {% stock_status_label item.status %} |
+
+ {% if item.expiry_date %}
+
+ |
+ {% trans "Expiry Date" %} |
+
+ {% render_date item.expiry_date %}
+ {% if item.is_expired %}
+ {% trans "Expired" %}
+ {% elif item.is_stale %}
+ {% trans "Stale" %}
+ {% endif %}
+ |
+
+ {% endif %}
+
+ |
+ {% trans "Last Updated" %} |
+ {{ item.updated }} |
+
+
+ |
+ {% trans "Last Stocktake" %} |
+ {% if item.stocktake_date %}
+ {% render_date item.stocktake_date %} {{ item.stocktake_user }} |
+ {% else %}
+ {% trans "No stocktake performed" %} |
+ {% endif %}
+
+
+
{% endblock details_right %}
diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py
index f38d1777a6..7a0f1ab978 100644
--- a/InvenTree/stock/views.py
+++ b/InvenTree/stock/views.py
@@ -94,6 +94,12 @@ class StockItemDetail(InvenTreeRoleMixin, InvenTreePluginViewMixin, DetailView):
data['item_owner'] = self.object.get_item_owner()
data['user_owns_item'] = self.object.check_ownership(self.request.user)
+ # Allocation information
+ data['allocated_to_sales_orders'] = self.object.sales_order_allocation_count()
+ data['allocated_to_build_orders'] = self.object.build_allocation_count()
+ data['allocated_to_orders'] = data['allocated_to_sales_orders'] + data['allocated_to_build_orders']
+ data['available'] = max(0, self.object.quantity - data['allocated_to_orders'])
+
return data
def get(self, request, *args, **kwargs):
diff --git a/InvenTree/templates/js/translated/stock.js b/InvenTree/templates/js/translated/stock.js
index ffac1d58c2..f0b7b28a73 100644
--- a/InvenTree/templates/js/translated/stock.js
+++ b/InvenTree/templates/js/translated/stock.js
@@ -1698,13 +1698,22 @@ function loadStockTable(table, options) {
sortable: true,
formatter: function(value, row) {
- var val = parseFloat(value);
+ var val = '';
+
+ var available = Math.max(0, (row.quantity || 0) - (row.allocated || 0));
- // If there is a single unit with a serial number, use the serial number
if (row.serial && row.quantity == 1) {
+ // If there is a single unit with a serial number, use the serial number
val = '# ' + row.serial;
+ } else if (row.quantity != available) {
+ // Some quantity is available, show available *and* quantity
+ var ava = +parseFloat(available).toFixed(5);
+ var tot = +parseFloat(row.quantity).toFixed(5);
+
+ val = `${ava} / ${tot}`;
} else {
- val = +val.toFixed(5);
+ // Format floating point numbers with this one weird trick
+ val = +parseFloat(value).toFixed(5);
}
var html = renderLink(val, `/stock/item/${row.pk}/`);
@@ -1719,16 +1728,7 @@ function loadStockTable(table, options) {
} else if (row.customer) {
// StockItem has been assigned to a customer
html += makeIconBadge('fa-user', '{% trans "Stock item assigned to customer" %}');
- }
-
- if (row.expired) {
- html += makeIconBadge('fa-calendar-times icon-red', '{% trans "Stock item has expired" %}');
- } else if (row.stale) {
- html += makeIconBadge('fa-stopwatch', '{% trans "Stock item will expire soon" %}');
- }
-
- if (row.allocated) {
-
+ } else if (row.allocated) {
if (row.serial != null && row.quantity == 1) {
html += makeIconBadge('fa-bookmark icon-yellow', '{% trans "Serialized stock item has been allocated" %}');
} else if (row.allocated >= row.quantity) {
@@ -1736,10 +1736,14 @@ function loadStockTable(table, options) {
} else {
html += makeIconBadge('fa-bookmark', '{% trans "Stock item has been partially allocated" %}');
}
+ } else if (row.belongs_to) {
+ html += makeIconBadge('fa-box', '{% trans "Stock item has been installed in another item" %}');
}
- if (row.belongs_to) {
- html += makeIconBadge('fa-box', '{% trans "Stock item has been installed in another item" %}');
+ if (row.expired) {
+ html += makeIconBadge('fa-calendar-times icon-red', '{% trans "Stock item has expired" %}');
+ } else if (row.stale) {
+ html += makeIconBadge('fa-stopwatch', '{% trans "Stock item will expire soon" %}');
}
// Special stock status codes