From b827f14bf6e654c995de263768738c4f277c5cd8 Mon Sep 17 00:00:00 2001 From: Oliver <oliver.henry.walters@gmail.com> Date: Thu, 8 Sep 2022 13:44:53 +1000 Subject: [PATCH] Pack quantity improvements (#3661) * Specify serializer label * Add units to part grid view * improve display of stock units in part table * Add units display to stock on part page * Display units in supplier part table * Simplify stock quantity display in stock table --- InvenTree/InvenTree/fields.py | 5 +-- InvenTree/company/serializers.py | 2 +- InvenTree/part/templates/part/part_base.html | 4 +-- .../part/templates/part/stock_count.html | 2 +- InvenTree/templates/js/translated/company.js | 9 +++++ InvenTree/templates/js/translated/part.js | 33 ++++++++++++------- InvenTree/templates/js/translated/stock.js | 12 +++---- 7 files changed, 39 insertions(+), 28 deletions(-) diff --git a/InvenTree/InvenTree/fields.py b/InvenTree/InvenTree/fields.py index d8eff33093..caf625f2b8 100644 --- a/InvenTree/InvenTree/fields.py +++ b/InvenTree/InvenTree/fields.py @@ -165,11 +165,8 @@ class RoundingDecimalField(models.DecimalField): def formfield(self, **kwargs): """Return a Field instance for this field.""" - defaults = { - 'form_class': RoundingDecimalFormField - } - defaults.update(kwargs) + kwargs['form_class'] = RoundingDecimalFormField return super().formfield(**kwargs) diff --git a/InvenTree/company/serializers.py b/InvenTree/company/serializers.py index ae88131997..2f74501fd0 100644 --- a/InvenTree/company/serializers.py +++ b/InvenTree/company/serializers.py @@ -239,7 +239,7 @@ class SupplierPartSerializer(InvenTreeModelSerializer): pretty_name = serializers.CharField(read_only=True) - pack_size = serializers.FloatField() + pack_size = serializers.FloatField(label=_('Pack Quantity')) def __init__(self, *args, **kwargs): """Initialize this serializer with extra detail fields as required""" diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index a0ad88bed6..69e6ccfdf8 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -198,14 +198,14 @@ <tr> <td><span class='fas fa-flag'></span></td> <td>{% trans "Minimum Stock" %}</td> - <td>{{ part.minimum_stock }}</td> + <td>{{ part.minimum_stock }} {{ part.units }}</td> </tr> {% endif %} {% if on_order > 0 %} <tr> <td><span class='fas fa-shopping-cart'></span></td> <td>{% trans "On Order" %}</td> - <td>{% decimal on_order %}</td> + <td>{% decimal on_order %} {{ part.units }}</td> </tr> {% endif %} {% if part.component %} diff --git a/InvenTree/part/templates/part/stock_count.html b/InvenTree/part/templates/part/stock_count.html index 237c12b83e..517d502f9d 100644 --- a/InvenTree/part/templates/part/stock_count.html +++ b/InvenTree/part/templates/part/stock_count.html @@ -1,7 +1,7 @@ {% load inventree_extras %} {% load i18n %} -{% decimal total_stock %} +{% decimal total_stock %} {{ part.units }} {% if total_stock == 0 %} <span class='badge badge-right rounded-pill bg-danger'>{% trans "No Stock" %}</span> diff --git a/InvenTree/templates/js/translated/company.js b/InvenTree/templates/js/translated/company.js index 6b90a78c87..4025e8b82c 100644 --- a/InvenTree/templates/js/translated/company.js +++ b/InvenTree/templates/js/translated/company.js @@ -995,6 +995,15 @@ function loadSupplierPartTable(table, url, options) { field: 'pack_size', title: '{% trans "Pack Quantity" %}', sortable: true, + formatter: function(value, row) { + var output = `${value}`; + + if (row.part_detail) { + output += ` ${row.part_detail.units}`; + } + + return output; + } }, { field: 'link', diff --git a/InvenTree/templates/js/translated/part.js b/InvenTree/templates/js/translated/part.js index bc0e8c81db..46e9c7dba1 100644 --- a/InvenTree/templates/js/translated/part.js +++ b/InvenTree/templates/js/translated/part.js @@ -1324,22 +1324,23 @@ function partGridTile(part) { // Rows for table view var rows = ''; - var stock = `${part.in_stock}`; + var units = part.units; + var stock = `${part.in_stock} ${part.units}`; if (!part.in_stock) { stock = `<span class='badge rounded-pill bg-danger'>{% trans "No Stock" %}</span>`; } else if (!part.unallocated_stock) { - stock = `<span class='badge rounded-pill bg-warning'>{% trans "Not available" %}</span>`; + stock = `<span class='badge rounded-pill bg-warning'>{% trans "No Stock" %}</span>`; } rows += `<tr><td><b>{% trans "Stock" %}</b></td><td>${stock}</td></tr>`; if (part.ordering) { - rows += `<tr><td><b>{% trans "On Order" %}</b></td><td>${part.ordering}</td></tr>`; + rows += `<tr><td><b>{% trans "On Order" %}</b></td><td>${part.ordering} ${units}</td></tr>`; } if (part.building) { - rows += `<tr><td><b>{% trans "Building" %}</b></td><td>${part.building}</td></tr>`; + rows += `<tr><td><b>{% trans "Building" %}</b></td><td>${part.building} ${units}</td></tr>`; } var html = ` @@ -1356,10 +1357,10 @@ function partGridTile(part) { </div> <div class='panel-content'> <div class='row'> - <div class='col-sm-6'> - <img src='${part.thumbnail}' class='card-thumb' onclick='showModalImage("${part.image}")'> + <div class='col-sm-4'> + <img src='${part.thumbnail}' style='width: 100%;' class='card-thumb' onclick='showModalImage("${part.image}")'> </div> - <div class='col-sm-6'> + <div class='col-sm-8'> <table class='table table-striped table-condensed'> ${rows} </table> @@ -1505,11 +1506,7 @@ function loadPartTable(table, url, options={}) { total_stock += row.variant_stock; } - if (row.unallocated_stock != row.in_stock) { - text = `${row.unallocated_stock} / ${total_stock}`; - } else { - text = `${total_stock}`; - } + var text = `${total_stock}`; // Construct extra informational badges var badges = ''; @@ -1538,6 +1535,18 @@ function loadPartTable(table, url, options={}) { badges += `<span class='fas fa-info-circle float-right' title='{% trans "Includes variant stock" %}'></span>`; } + if (row.allocated_to_build_orders > 0) { + badges += `<span class='fas fa-bookmark icon-yellow float-right' title='{% trans "Allocated to build orders" %}: ${row.allocated_to_build_orders}'></span>`; + } + + if (row.allocated_to_sales_orders > 0) { + badges += `<span class='fas fa-bookmark icon-yellow float-right' title='{% trans "Allocated to sales orders" %}: ${row.allocated_to_sales_orders}'></span>`; + } + + if (row.units) { + text += ` <small>${row.units}</small>`; + } + text = renderLink(text, `/part/${row.pk}/?display=part-stock`); text += badges; diff --git a/InvenTree/templates/js/translated/stock.js b/InvenTree/templates/js/translated/stock.js index 877644f91e..67dd18fb41 100644 --- a/InvenTree/templates/js/translated/stock.js +++ b/InvenTree/templates/js/translated/stock.js @@ -1757,20 +1757,16 @@ function loadStockTable(table, options) { var val = ''; - var available = Math.max(0, (row.quantity || 0) - (row.allocated || 0)); - 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 = formatDecimal(available); - var tot = formatDecimal(row.quantity); - - val = `${ava} / ${tot}`; } else { // Format floating point numbers with this one weird trick val = formatDecimal(value); + + if (row.part_detail) { + val += ` ${row.part_detail.units}`; + } } var html = renderLink(val, `/stock/item/${row.pk}/`);