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 }} -
- {% if previous %} - - - {{ previous.serial }} - - {% endif %} - - - - {% if next %} - - {{ next.serial }} - - - {% endif %} -
- - - {% 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 %} - - - - - - {% endif %} - {% if item.belongs_to %} - - - - - - {% elif item.sales_order %} - - - - - - {% else %} - - - - {% if item.location %} - - {% else %} - - {% endif %} - - {% endif %} + {% if item.uid %} @@ -322,13 +171,6 @@ {% endif %} - {% if item.packaging %} - - - - - - {% endif %} {% if item.build %} @@ -397,18 +239,11 @@ {% endif %} - {% if item.hasRequiredTests %} + {% if item.packaging %} - - - + + + {% endif %} {% if ownership_enabled and item_owner %} @@ -425,6 +260,199 @@ {% endif %} + +
{% trans "Customer" %}{{ item.customer.name }}
- {% trans "Installed In" %} - - {{ item.belongs_to }} -
{% trans "Sales Order" %}{{ item.sales_order.reference }} - {{ item.sales_order.customer.name }}
{% trans "Location" %}{{ item.location.name }}{% trans "No location set" %}
{{ item.batch }}
{% trans "Packaging" %}{{ item.packaging }}
{{ item.supplier_part.SKU }}
{% trans "Tests" %} - {{ item.requiredTestStatus.passed }} / {{ item.requiredTestStatus.total }} - {% if item.passedAllRequiredTests %} - - {% else %} - - {% endif %} - {% trans "Packaging" %}{{ item.packaging }}
+ +
+ + {% 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 %} + + + + {% else %} + + + + {% endif %} + + {% if item.belongs_to %} + + + + + + {% elif item.sales_order %} + + + + + + {% else %} + {% if allocated_to_sales_orders %} + + + + + + {% endif %} + {% if allocated_to_build_orders %} + + + + + + {% endif %} + + + + {% if item.location %} + + {% elif not item.customer %} + + {% endif %} + + {% endif %} + {% if item.customer %} + + + + + + {% endif %} + + {% if item.hasRequiredTests %} + + + + + + {% endif %} + + + + + + + {% if item.expiry_date %} + + + + + + {% endif %} + + + + + + + + + {% if item.stocktake_date %} + + {% else %} + + {% endif %} + + +
+
+
+
{% trans "Serial Number" %}
+
+ {{ item.serial }} +
+ {% if previous %} + + + {{ previous.serial }} + + {% endif %} + + + + {% if next %} + + {{ next.serial }} + + + {% endif %} +
+
+
+
+
+
{% trans "Available Quantity" %}
+
+
{% if item.quantity != available %}{% decimal available %} / {% endif %}{% decimal item.quantity %} {% if item.part.units %}{{ item.part.units }}{% endif %}
+
+ {% trans "Installed In" %} + + {{ item.belongs_to }} +
{% trans "Sales Order" %}{{ item.sales_order.reference }} - {{ item.sales_order.customer.name }}
{% trans "Allocated to Sales Orders" %}{% decimal allocated_to_sales_orders %}
{% trans "Allocated to Build Orders" %}{% decimal allocated_to_build_orders %}
{% trans "Location" %}{{ item.location.name }}{% trans "No location set" %}
{% trans "Customer" %}{{ item.customer.name }}
{% trans "Tests" %} + {{ item.requiredTestStatus.passed }} / {{ item.requiredTestStatus.total }} + {% if item.passedAllRequiredTests %} + + {% else %} + + {% endif %} +
{% trans "Status" %}{% stock_status_label item.status %}
{% trans "Expiry Date" %} + {% render_date item.expiry_date %} + {% if item.is_expired %} + {% trans "Expired" %} + {% elif item.is_stale %} + {% trans "Stale" %} + {% endif %} +
{% trans "Last Updated" %}{{ item.updated }}
{% trans "Last Stocktake" %}{% render_date item.stocktake_date %} {{ item.stocktake_user }}{% trans "No stocktake performed" %}
{% 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