diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html
index 71c21dc034..649aaf6705 100644
--- a/InvenTree/part/templates/part/part_base.html
+++ b/InvenTree/part/templates/part/part_base.html
@@ -211,44 +211,18 @@
{% if part.component %}
{% if required_build_order_quantity > 0 %}
- |
- {% trans "Required for Build Orders" %} |
- {% decimal required_build_order_quantity %} |
-
-
- |
+ |
{% trans "Allocated to Build Orders" %} |
-
- {% decimal allocated_build_order_quantity %}
- {% if allocated_build_order_quantity < required_build_order_quantity %}
-
- {% else %}
-
- {% endif %}
- |
+ {% progress_bar allocated_build_order_quantity required_build_order_quantity id='build-order-allocated' max_width='150px' %} |
{% endif %}
{% endif %}
{% if part.salable %}
{% if required_sales_order_quantity > 0 %}
- |
- {% trans "Required for Sales Orders" %} |
-
- {% decimal required_sales_order_quantity %}
- |
-
-
- |
+ |
{% trans "Allocated to Sales Orders" %} |
-
- {% decimal allocated_sales_order_quantity %}
- {% if allocated_sales_order_quantity < required_sales_order_quantity %}
-
- {% else %}
-
- {% endif %}
- |
+ {% progress_bar allocated_sales_order_quantity required_sales_order_quantity id='sales-order-allocated' max_width='150px' %} |
{% endif %}
{% endif %}
diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py
index dc93e00efa..08fa8ce583 100644
--- a/InvenTree/part/templatetags/inventree_extras.py
+++ b/InvenTree/part/templatetags/inventree_extras.py
@@ -352,21 +352,24 @@ def visible_global_settings(*args, **kwargs):
@register.simple_tag()
-def progress_bar(val, max, *args, **kwargs):
+def progress_bar(val, max_val, *args, **kwargs):
"""
Render a progress bar element
"""
item_id = kwargs.get('id', 'progress-bar')
- if val > max:
+ val = InvenTree.helpers.normalize(val)
+ max_val = InvenTree.helpers.normalize(max_val)
+
+ if val > max_val:
style = 'progress-bar-over'
- elif val < max:
+ elif val < max_val:
style = 'progress-bar-under'
else:
style = ''
- percent = float(val / max) * 100
+ percent = float(val / max_val) * 100
if percent > 100:
percent = 100
@@ -383,7 +386,7 @@ def progress_bar(val, max, *args, **kwargs):
html = f"""
-
{val} / {max}
+
{val} / {max_val}
"""
diff --git a/InvenTree/plugin/builtin/integration/mixins.py b/InvenTree/plugin/builtin/integration/mixins.py
index 118f0b775b..18c1afe64a 100644
--- a/InvenTree/plugin/builtin/integration/mixins.py
+++ b/InvenTree/plugin/builtin/integration/mixins.py
@@ -504,10 +504,10 @@ class APICallMixin:
@property
def api_headers(self):
- return {
- self.API_TOKEN: self.get_setting(self.API_TOKEN_SETTING),
- 'Content-Type': 'application/json'
- }
+ headers = {'Content-Type': 'application/json'}
+ if getattr(self, 'API_TOKEN_SETTING'):
+ headers[self.API_TOKEN] = self.get_setting(self.API_TOKEN_SETTING)
+ return headers
def api_build_url_args(self, arguments):
groups = []
@@ -515,16 +515,21 @@ class APICallMixin:
groups.append(f'{key}={",".join([str(a) for a in val])}')
return f'?{"&".join(groups)}'
- def api_call(self, endpoint, method: str = 'GET', url_args=None, data=None, headers=None, simple_response: bool = True):
+ def api_call(self, endpoint, method: str = 'GET', url_args=None, data=None, headers=None, simple_response: bool = True, endpoint_is_url: bool = False):
if url_args:
endpoint += self.api_build_url_args(url_args)
if headers is None:
headers = self.api_headers
+ if endpoint_is_url:
+ url = endpoint
+ else:
+ url = f'{self.api_url}/{endpoint}'
+
# build kwargs for call
kwargs = {
- 'url': f'{self.api_url}/{endpoint}',
+ 'url': url,
'headers': headers,
}
if data:
diff --git a/InvenTree/templates/js/translated/bom.js b/InvenTree/templates/js/translated/bom.js
index 0d27a5e028..2d7796edcd 100644
--- a/InvenTree/templates/js/translated/bom.js
+++ b/InvenTree/templates/js/translated/bom.js
@@ -691,8 +691,24 @@ function loadBomTable(table, options={}) {
setupFilterList('bom', $(table));
- // Construct the table columns
+ function availableQuantity(row) {
+ // Base stock
+ var available = row.available_stock;
+
+ // Substitute stock
+ available += (row.available_substitute_stock || 0);
+
+ // Variant stock
+ if (row.allow_variants) {
+ available += (row.available_variant_stock || 0);
+ }
+
+ return available;
+
+ }
+
+ // Construct the table columns
var cols = [];
if (options.editable) {
@@ -807,11 +823,10 @@ function loadBomTable(table, options={}) {
var url = `/part/${row.sub_part_detail.pk}/?display=part-stock`;
// Calculate total "available" (unallocated) quantity
- var base_stock = row.available_stock;
var substitute_stock = row.available_substitute_stock || 0;
var variant_stock = row.allow_variants ? (row.available_variant_stock || 0) : 0;
- var available_stock = base_stock + substitute_stock + variant_stock;
+ var available_stock = availableQuantity(row);
var text = `${available_stock}`;
@@ -923,7 +938,7 @@ function loadBomTable(table, options={}) {
formatter: function(value, row) {
var can_build = 0;
- var available = row.available_stock + (row.available_substitute_stock || 0) + (row.available_variant_stock || 0);
+ var available = availableQuantity(row);
if (row.quantity > 0) {
can_build = available / row.quantity;
@@ -937,11 +952,11 @@ function loadBomTable(table, options={}) {
var cb_b = 0;
if (rowA.quantity > 0) {
- cb_a = (rowA.available_stock + rowA.available_substitute_stock) / rowA.quantity;
+ cb_a = availableQuantity(rowA) / rowA.quantity;
}
if (rowB.quantity > 0) {
- cb_b = (rowB.available_stock + rowB.available_substitute_stock) / rowB.quantity;
+ cb_b = availableQuantity(rowB) / rowB.quantity;
}
return (cb_a > cb_b) ? 1 : -1;
diff --git a/InvenTree/templates/js/translated/build.js b/InvenTree/templates/js/translated/build.js
index eb955d7ff0..65fc3a4d6c 100644
--- a/InvenTree/templates/js/translated/build.js
+++ b/InvenTree/templates/js/translated/build.js
@@ -1031,6 +1031,23 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
return row.required;
}
+ function availableQuantity(row) {
+
+ // Base stock
+ var available = row.available_stock;
+
+ // Substitute stock
+ available += (row.available_substitute_stock || 0);
+
+ // Variant stock
+ if (row.allow_variants) {
+ available += (row.available_variant_stock || 0);
+ }
+
+ return available;
+
+ }
+
function sumAllocations(row) {
// Calculat total allocations for a given row
if (!row.allocations) {
@@ -1429,16 +1446,27 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
var url = `/part/${row.sub_part_detail.pk}/?display=part-stock`;
// Calculate total "available" (unallocated) quantity
- var base_stock = row.available_stock;
var substitute_stock = row.available_substitute_stock || 0;
var variant_stock = row.allow_variants ? (row.available_variant_stock || 0) : 0;
- var available_stock = base_stock + substitute_stock + variant_stock;
+ var available_stock = availableQuantity(row);
- var text = `${available_stock}`;
+ var required = requiredQuantity(row);
+
+ var text = '';
+
+ if (available_stock > 0) {
+ text += `${available_stock}`;
+ }
+
+ if (available_stock < required) {
+ text += ``;
+ } else {
+ text += ``;
+ }
if (available_stock <= 0) {
- text = `{% trans "No Stock Available" %}`;
+ text += `{% trans "No Stock Available" %}`;
} else {
var extra = '';
if ((substitute_stock > 0) && (variant_stock > 0)) {
@@ -1455,7 +1483,11 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
}
return renderLink(text, url);
- }
+ },
+ sorter: function(valA, valB, rowA, rowB) {
+
+ return availableQuantity(rowA) > availableQuantity(rowB) ? 1 : -1;
+ },
},
{
field: 'allocated',
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 9978460e8f..63535bd83d 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -65,8 +65,8 @@ RUN apk add --no-cache git make bash \
libjpeg-turbo libjpeg-turbo-dev jpeg jpeg-dev \
libffi libffi-dev \
zlib zlib-dev \
- # Cairo deps for WeasyPrint (these will be deprecated once WeasyPrint drops cairo requirement)
- cairo cairo-dev pango pango-dev \
+ # Special deps for WeasyPrint (these will be deprecated once WeasyPrint drops cairo requirement)
+ cairo cairo-dev pango pango-dev gdk-pixbuf \
# Fonts
fontconfig ttf-droid ttf-liberation ttf-dejavu ttf-opensans ttf-ubuntu-font-family font-croscore font-noto \
# Core python