From d535e4fa12f4274396f9dce7071c4cae9e40ba31 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Apr 2022 22:38:31 +1000 Subject: [PATCH 01/60] Add 'available_variant_stock' to BomItem serializer - Note: This is definitely *not* the optimum solution here --- InvenTree/part/models.py | 55 +++++++++++++++++++++++++++++++++++ InvenTree/part/serializers.py | 7 +++++ 2 files changed, 62 insertions(+) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index b7269f3e5e..3635f22587 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -2703,6 +2703,61 @@ class BomItem(models.Model, DataImportMixin): def get_api_url(): return reverse('api-bom-list') + def available_variant_stock(self): + """ + Returns the total quantity of variant stock available for this BomItem. + + Notes: + - If "allow_variants" is False, this will return zero + - This is used for the API serializer, and is very inefficient + - This logic needs to be converted to a queryset annotation + """ + + # Variant stock is not allowed for this BOM item + if not self.allow_variants: + return 0 + + # Extract a flattened list of part variants + variants = self.sub_part.get_descendants(include_self=False) + + # Calculate 'in_stock' quantity - this is the total current stock count + query = StockModels.StockItem.objects.filter(StockModels.StockItem.IN_STOCK_FILTER) + + query = query.filter( + part__in=variants, + ) + + query = query.aggregate( + in_stock=Coalesce(Sum('quantity'), Decimal(0)) + ) + + in_stock = query['in_stock'] or 0 + + # Calculate the quantity allocated to sales orders + query = OrderModels.SalesOrderAllocation.objects.filter( + line__order__status__in=SalesOrderStatus.OPEN, + shipment__shipment_date=None, + item__part__in=variants, + ).aggregate( + allocated=Coalesce(Sum('quantity'), Decimal(0)), + ) + + sales_order_allocations = query['allocated'] or 0 + + # Calculate the quantity allocated to build orders + query = BuildModels.BuildItem.objects.filter( + build__status__in=BuildStatus.ACTIVE_CODES, + stock_item__part__in=variants, + ).aggregate( + allocated=Coalesce(Sum('quantity'), Decimal(0)), + ) + + build_order_allocations = query['allocated'] or 0 + + available = in_stock - sales_order_allocations - build_order_allocations + + return max(available, 0) + def get_valid_parts_for_allocation(self, allow_variants=True, allow_substitutes=True): """ Return a list of valid parts which can be allocated against this BomItem: diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 8bf3d77501..0daac6e630 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -581,6 +581,12 @@ class BomItemSerializer(InvenTreeModelSerializer): available_stock = serializers.FloatField(read_only=True) available_substitute_stock = serializers.FloatField(read_only=True) + # Note: 2022-04-15 + # The 'available_variant_stock' field is calculated per-object, + # which means it is very inefficient! + # TODO: This needs to be converted into a query annotation, if possible! + available_variant_stock = serializers.FloatField(read_only=True) + def __init__(self, *args, **kwargs): # part_detail and sub_part_detail serializers are only included if requested. # This saves a bunch of database requests @@ -790,6 +796,7 @@ class BomItemSerializer(InvenTreeModelSerializer): # Annotated fields describing available quantity 'available_stock', 'available_substitute_stock', + 'available_variant_stock', ] From 7f07c526896bd6329dcc0e8253b48cfc33d798e9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Apr 2022 22:40:24 +1000 Subject: [PATCH 02/60] Incremement APi version --- InvenTree/InvenTree/version.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index 32f359f5f2..160716bba3 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -12,11 +12,14 @@ import common.models INVENTREE_SW_VERSION = "0.7.0 dev" # InvenTree API version -INVENTREE_API_VERSION = 38 +INVENTREE_API_VERSION = 39 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v39 -> 2022-04-15 : https://github.com/inventree/InvenTree/pull/2833 + - Adds 'available_variant_stock' information to the BomItem API + v38 -> 2022-04-14 : https://github.com/inventree/InvenTree/pull/2828 - Adds the ability to include stock test results for "installed items" From 6f5b560fb61d89ff6071da7057be052a3c8fa561 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Apr 2022 22:45:22 +1000 Subject: [PATCH 03/60] Update BOM table to include variant stock information --- InvenTree/templates/js/translated/bom.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/InvenTree/templates/js/translated/bom.js b/InvenTree/templates/js/translated/bom.js index 6591068e9d..7ae922788f 100644 --- a/InvenTree/templates/js/translated/bom.js +++ b/InvenTree/templates/js/translated/bom.js @@ -807,15 +807,27 @@ function loadBomTable(table, options={}) { var url = `/part/${row.sub_part_detail.pk}/?display=part-stock`; // Calculate total "available" (unallocated) quantity - var total = row.available_stock + row.available_substitute_stock; + var total = row.available_stock; + + total += (row.available_substitute_stock || 0); + total += (row.available_variant_stock || 0); var text = `${total}`; if (total <= 0) { text = `{% trans "No Stock Available" %}`; } else { - if (row.available_substitute_stock > 0) { - text += ``; + var extra = ''; + if (row.available_substitute_stock && row.available_variant_stock) { + extra = '{% trans "Includes variant and substitute stock" %}'; + } else if (row.available_variant_stock) { + extra = '{% trans "Includes variant stock" %}'; + } else if (row.available_substitute_stock) { + extra = '{% trans "Includes substitute stock" %}'; + } + + if (extra) { + text += ``; } } @@ -910,7 +922,7 @@ function loadBomTable(table, options={}) { formatter: function(value, row) { var can_build = 0; - var available = row.available_stock + row.available_substitute_stock; + var available = row.available_stock + (row.available_substitute_stock || 0) + (row.available_variant_stock || 0); if (row.quantity > 0) { can_build = available / row.quantity; From 43135036491991c1226da03af5b53ff15b13904f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Apr 2022 22:47:32 +1000 Subject: [PATCH 04/60] PEP fix --- InvenTree/part/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 3635f22587..01ea8c661b 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -2716,7 +2716,7 @@ class BomItem(models.Model, DataImportMixin): # Variant stock is not allowed for this BOM item if not self.allow_variants: return 0 - + # Extract a flattened list of part variants variants = self.sub_part.get_descendants(include_self=False) From 1d73f7c066615a1cf0a7fc03271114a995d61903 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 20:14:46 +1000 Subject: [PATCH 05/60] Update API version info --- InvenTree/InvenTree/api_version.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index 7851efd8dd..3f86d8a669 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -4,11 +4,14 @@ InvenTree API version information # InvenTree API version -INVENTREE_API_VERSION = 40 +INVENTREE_API_VERSION = 41 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v41 -> 2022-04-21 : https://github.com/inventree/InvenTree/pull/2833 + - Adds variant stock information to the Part and BomItem serializers + v40 -> 2022-04-19 - Adds ability to filter StockItem list by "tracked" parameter - This checks the serial number or batch code fields From fa2510c42f284e0c0caa51bbe9890c61b22a01bb Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 23:51:29 +1000 Subject: [PATCH 06/60] Use a proper queryset annotation to calculate the "available_variant_stock" --- InvenTree/part/models.py | 54 ------------------------------ InvenTree/part/serializers.py | 62 ++++++++++++++++++++++++++++++----- 2 files changed, 54 insertions(+), 62 deletions(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 01ea8c661b..d942c68c85 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -2703,60 +2703,6 @@ class BomItem(models.Model, DataImportMixin): def get_api_url(): return reverse('api-bom-list') - def available_variant_stock(self): - """ - Returns the total quantity of variant stock available for this BomItem. - - Notes: - - If "allow_variants" is False, this will return zero - - This is used for the API serializer, and is very inefficient - - This logic needs to be converted to a queryset annotation - """ - - # Variant stock is not allowed for this BOM item - if not self.allow_variants: - return 0 - - # Extract a flattened list of part variants - variants = self.sub_part.get_descendants(include_self=False) - - # Calculate 'in_stock' quantity - this is the total current stock count - query = StockModels.StockItem.objects.filter(StockModels.StockItem.IN_STOCK_FILTER) - - query = query.filter( - part__in=variants, - ) - - query = query.aggregate( - in_stock=Coalesce(Sum('quantity'), Decimal(0)) - ) - - in_stock = query['in_stock'] or 0 - - # Calculate the quantity allocated to sales orders - query = OrderModels.SalesOrderAllocation.objects.filter( - line__order__status__in=SalesOrderStatus.OPEN, - shipment__shipment_date=None, - item__part__in=variants, - ).aggregate( - allocated=Coalesce(Sum('quantity'), Decimal(0)), - ) - - sales_order_allocations = query['allocated'] or 0 - - # Calculate the quantity allocated to build orders - query = BuildModels.BuildItem.objects.filter( - build__status__in=BuildStatus.ACTIVE_CODES, - stock_item__part__in=variants, - ).aggregate( - allocated=Coalesce(Sum('quantity'), Decimal(0)), - ) - - build_order_allocations = query['allocated'] or 0 - - available = in_stock - sales_order_allocations - build_order_allocations - - return max(available, 0) def get_valid_parts_for_allocation(self, allow_variants=True, allow_substitutes=True): """ diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 0daac6e630..6dc502ae85 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -7,7 +7,9 @@ from decimal import Decimal from django.urls import reverse_lazy from django.db import models, transaction -from django.db.models import ExpressionWrapper, F, Q +from django.db.models import ExpressionWrapper, F, Q, Func +from django.db.models import Subquery, OuterRef, IntegerField, FloatField + from django.db.models.functions import Coalesce from django.utils.translation import ugettext_lazy as _ @@ -577,14 +579,9 @@ class BomItemSerializer(InvenTreeModelSerializer): purchase_price_range = serializers.SerializerMethodField() - # Annotated fields + # Annotated fields for available stock available_stock = serializers.FloatField(read_only=True) available_substitute_stock = serializers.FloatField(read_only=True) - - # Note: 2022-04-15 - # The 'available_variant_stock' field is calculated per-object, - # which means it is very inefficient! - # TODO: This needs to be converted into a query annotation, if possible! available_variant_stock = serializers.FloatField(read_only=True) def __init__(self, *args, **kwargs): @@ -619,11 +616,18 @@ class BomItemSerializer(InvenTreeModelSerializer): queryset = queryset.prefetch_related('sub_part') queryset = queryset.prefetch_related('sub_part__category') + queryset = queryset.prefetch_related( 'sub_part__stock_items', 'sub_part__stock_items__allocations', 'sub_part__stock_items__sales_order_allocations', ) + + queryset = queryset.prefetch_related( + 'substitutes', + 'substitutes__part__stock_items', + ) + queryset = queryset.prefetch_related('sub_part__supplier_parts__pricebreaks') return queryset @@ -713,7 +717,7 @@ class BomItemSerializer(InvenTreeModelSerializer): ), ) - # Calculate 'available_variant_stock' field + # Calculate 'available_substitute_stock' field queryset = queryset.annotate( available_substitute_stock=ExpressionWrapper( F('substitute_stock') - F('substitute_build_allocations') - F('substitute_sales_allocations'), @@ -721,6 +725,47 @@ class BomItemSerializer(InvenTreeModelSerializer): ) ) + # Annotate the queryset with 'available variant stock' information + variant_stock_query = StockItem.objects.filter( + part__tree_id=OuterRef('sub_part__tree_id'), + part__lft__gt=OuterRef('sub_part__lft'), + part__rght__lt=OuterRef('sub_part__rght'), + ) + + queryset = queryset.alias( + variant_stock_total=Coalesce( + Subquery( + variant_stock_query.annotate( + total=Func(F('quantity'), function='SUM', output_field=FloatField()) + ).values('total')), + 0, + output_field=FloatField() + ), + variant_stock_build_order_allocations=Coalesce( + Subquery( + variant_stock_query.annotate( + total=Func(F('sales_order_allocations__quantity'), function='SUM', output_field=FloatField()), + ).values('total')), + 0, + output_field=FloatField(), + ), + variant_stock_sales_order_allocations=Coalesce( + Subquery( + variant_stock_query.annotate( + total=Func(F('allocations__quantity'), function='SUM', output_field=FloatField()), + ).values('total')), + 0, + output_field=FloatField(), + ) + ) + + queryset = queryset.annotate( + available_variant_stock=ExpressionWrapper( + F('variant_stock_total') - F('variant_stock_build_order_allocations') - F('variant_stock_sales_order_allocations'), + output_field=FloatField(), + ) + ) + return queryset def get_purchase_price_range(self, obj): @@ -797,6 +842,7 @@ class BomItemSerializer(InvenTreeModelSerializer): 'available_stock', 'available_substitute_stock', 'available_variant_stock', + ] From ec34d23bfc36dbe60a46e6d05435a4a19fc7b5ea Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 23:58:12 +1000 Subject: [PATCH 07/60] Update javascript rendering in BOM table --- InvenTree/templates/js/translated/bom.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/InvenTree/templates/js/translated/bom.js b/InvenTree/templates/js/translated/bom.js index 7ae922788f..0d27a5e028 100644 --- a/InvenTree/templates/js/translated/bom.js +++ b/InvenTree/templates/js/translated/bom.js @@ -807,22 +807,23 @@ function loadBomTable(table, options={}) { var url = `/part/${row.sub_part_detail.pk}/?display=part-stock`; // Calculate total "available" (unallocated) quantity - var total = row.available_stock; + 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; - total += (row.available_substitute_stock || 0); - total += (row.available_variant_stock || 0); + var text = `${available_stock}`; - var text = `${total}`; - - if (total <= 0) { + if (available_stock <= 0) { text = `{% trans "No Stock Available" %}`; } else { var extra = ''; - if (row.available_substitute_stock && row.available_variant_stock) { + if ((substitute_stock > 0) && (variant_stock > 0)) { extra = '{% trans "Includes variant and substitute stock" %}'; - } else if (row.available_variant_stock) { + } else if (variant_stock > 0) { extra = '{% trans "Includes variant stock" %}'; - } else if (row.available_substitute_stock) { + } else if (substitute_stock > 0) { extra = '{% trans "Includes substitute stock" %}'; } From aa20d84cc1f89beabe04b3385be4dfd2a3fdb5e3 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 22 Apr 2022 00:00:50 +1000 Subject: [PATCH 08/60] Update javascript rendering in build table --- InvenTree/templates/js/translated/build.js | 31 +++++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/InvenTree/templates/js/translated/build.js b/InvenTree/templates/js/translated/build.js index ff1f475d5d..eb955d7ff0 100644 --- a/InvenTree/templates/js/translated/build.js +++ b/InvenTree/templates/js/translated/build.js @@ -1425,19 +1425,36 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { title: '{% trans "Available" %}', sortable: true, formatter: function(value, row) { - var total = row.available_stock + row.available_substitute_stock; - var text = `${total}`; + var url = `/part/${row.sub_part_detail.pk}/?display=part-stock`; - if (total <= 0) { + // 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 text = `${available_stock}`; + + if (available_stock <= 0) { text = `{% trans "No Stock Available" %}`; } else { - if (row.available_substitute_stock > 0) { - text += ``; + var extra = ''; + if ((substitute_stock > 0) && (variant_stock > 0)) { + extra = '{% trans "Includes variant and substitute stock" %}'; + } else if (variant_stock > 0) { + extra = '{% trans "Includes variant stock" %}'; + } else if (substitute_stock > 0) { + extra = '{% trans "Includes substitute stock" %}'; + } + + if (extra) { + text += ``; } } - - return text; + + return renderLink(text, url); } }, { From 8b9aa86a0a57889ac8ada9a883364a2e692068de Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 22 Apr 2022 00:14:37 +1000 Subject: [PATCH 09/60] Add 'variant_stock' to Part API serializer --- InvenTree/part/serializers.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 6dc502ae85..387d3df1d5 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -8,7 +8,7 @@ from decimal import Decimal from django.urls import reverse_lazy from django.db import models, transaction from django.db.models import ExpressionWrapper, F, Q, Func -from django.db.models import Subquery, OuterRef, IntegerField, FloatField +from django.db.models import Subquery, OuterRef, FloatField from django.db.models.functions import Coalesce from django.utils.translation import ugettext_lazy as _ @@ -310,9 +310,6 @@ class PartSerializer(InvenTreeModelSerializer): to reduce database trips. """ - # TODO: Update the "in_stock" annotation to include stock for variants of the part - # Ref: https://github.com/inventree/InvenTree/issues/2240 - # Annotate with the total 'in stock' quantity queryset = queryset.annotate( in_stock=Coalesce( @@ -327,6 +324,24 @@ class PartSerializer(InvenTreeModelSerializer): stock_item_count=SubqueryCount('stock_items') ) + # Annotate with the total variant stock quantity + variant_query = StockItem.objects.filter( + part__tree_id=OuterRef('tree_id'), + part__lft__gt=OuterRef('lft'), + part__rght__lt=OuterRef('rght'), + ).filter(StockItem.IN_STOCK_FILTER) + + queryset = queryset.annotate( + variant_stock=Coalesce( + Subquery( + variant_query.annotate( + total=Func(F('quantity'), function='SUM', output_field=FloatField()) + ).values('total')), + 0, + output_field=FloatField(), + ) + ) + # Filter to limit builds to "active" build_filter = Q( status__in=BuildStatus.ACTIVE_CODES @@ -431,6 +446,7 @@ class PartSerializer(InvenTreeModelSerializer): unallocated_stock = serializers.FloatField(read_only=True) building = serializers.FloatField(read_only=True) in_stock = serializers.FloatField(read_only=True) + variant_stock = serializers.FloatField(read_only=True) ordering = serializers.FloatField(read_only=True) stock_item_count = serializers.IntegerField(read_only=True) suppliers = serializers.IntegerField(read_only=True) @@ -465,6 +481,7 @@ class PartSerializer(InvenTreeModelSerializer): 'full_name', 'image', 'in_stock', + 'variant_stock', 'ordering', 'building', 'IPN', @@ -730,7 +747,7 @@ class BomItemSerializer(InvenTreeModelSerializer): part__tree_id=OuterRef('sub_part__tree_id'), part__lft__gt=OuterRef('sub_part__lft'), part__rght__lt=OuterRef('sub_part__rght'), - ) + ).filter(StockItem.IN_STOCK_FILTER) queryset = queryset.alias( variant_stock_total=Coalesce( From f504dfe7972183ebc3e59f5b2b18b2f861dd6b6b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 22 Apr 2022 00:20:32 +1000 Subject: [PATCH 10/60] part variant table now displays information about variant stock quantities --- InvenTree/templates/js/translated/part.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/InvenTree/templates/js/translated/part.js b/InvenTree/templates/js/translated/part.js index 1a8e728040..35d5d0d5a6 100644 --- a/InvenTree/templates/js/translated/part.js +++ b/InvenTree/templates/js/translated/part.js @@ -672,7 +672,20 @@ function loadPartVariantTable(table, partId, options={}) { field: 'in_stock', title: '{% trans "Stock" %}', formatter: function(value, row) { - return renderLink(value, `/part/${row.pk}/?display=part-stock`); + + var base_stock = row.in_stock; + var variant_stock = row.variant_stock || 0; + + var total = base_stock + variant_stock; + + var text = `${total}`; + + if (variant_stock > 0) { + text = `${text}`; + text += ``; + } + + return renderLink(text, `/part/${row.pk}/?display=part-stock`); } } ]; From 6dec8ba1132b0ddafb5c234de5be6f630c9788cd Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 22 Apr 2022 00:24:25 +1000 Subject: [PATCH 11/60] PEP fix --- InvenTree/part/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index d942c68c85..b7269f3e5e 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -2703,7 +2703,6 @@ class BomItem(models.Model, DataImportMixin): def get_api_url(): return reverse('api-bom-list') - def get_valid_parts_for_allocation(self, allow_variants=True, allow_substitutes=True): """ Return a list of valid parts which can be allocated against this BomItem: From 7834171c2a63c41c5a7a55abe954c938d76fbb5f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Apr 2022 23:38:49 +0200 Subject: [PATCH 12/60] [FR] White labeling Fixes #2301 --- InvenTree/InvenTree/settings.py | 7 +++++++ InvenTree/config_template.yaml | 3 +++ InvenTree/part/templatetags/inventree_extras.py | 7 +++++++ InvenTree/templates/account/login.html | 14 ++++++-------- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index e1c584362f..b96705d6dc 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -67,6 +67,13 @@ DEMO_MODE = _is_true(get_setting( CONFIG.get('demo', False) )) +# user interface customization values +CUSTOMIZE = get_setting( + 'INVENTREE_CUSTOMIZE', + CONFIG.get('customize', {}), + {} +) + DOCKER = _is_true(get_setting( 'INVENTREE_DOCKER', False diff --git a/InvenTree/config_template.yaml b/InvenTree/config_template.yaml index 65dd20d3e8..862d062787 100644 --- a/InvenTree/config_template.yaml +++ b/InvenTree/config_template.yaml @@ -186,3 +186,6 @@ static_root: '/home/inventree/data/static' # KEYCLOAK_URL: 'https://keycloak.custom/auth' # KEYCLOAK_REALM: 'master' +# customize: +# login_message: | +# InvenTree demo instance - Click here for login details diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py index dc93e00efa..2d0b0660d6 100644 --- a/InvenTree/part/templatetags/inventree_extras.py +++ b/InvenTree/part/templatetags/inventree_extras.py @@ -509,6 +509,13 @@ def mail_configured(): return bool(settings.EMAIL_HOST) +@register.simple_tag() +def inventree_customize(reference, *args, **kwargs): + """ Return customization values for the user interface """ + + return djangosettings.CUSTOMIZE.get(reference, '') + + class I18nStaticNode(StaticNode): """ custom StaticNode diff --git a/InvenTree/templates/account/login.html b/InvenTree/templates/account/login.html index 6e62560bfa..1a4df286bb 100644 --- a/InvenTree/templates/account/login.html +++ b/InvenTree/templates/account/login.html @@ -1,7 +1,7 @@ {% extends "account/base.html" %} {% load inventree_extras %} -{% load i18n account socialaccount crispy_forms_tags inventree_extras %} +{% load i18n account socialaccount crispy_forms_tags inventree_extras markdownify %} {% block head_title %}{% trans "Sign In" %}{% endblock %} @@ -10,6 +10,7 @@ {% settings_value 'LOGIN_ENABLE_REG' as enable_reg %} {% settings_value 'LOGIN_ENABLE_PWD_FORGOT' as enable_pwd_forgot %} {% settings_value 'LOGIN_ENABLE_SSO' as enable_sso %} +{% inventree_customize 'login_message' as login_message %} {% mail_configured as mail_conf %} {% inventree_demo_mode as demo %} @@ -35,19 +36,16 @@ for a account and sign in below:{% endblocktrans %}

{% endif %}
+ {% if login_message %} + {{ login_message|markdownify }} +
+ {% endif %}
{% if mail_conf and enable_pwd_forgot and not demo %} {% trans "Forgot Password?" %} {% endif %} - {% if demo %} -

-

- {% trans "InvenTree demo instance" %} - {% trans "Click here for login details" %} -
-

- {% endif %} {% if enable_sso %} From 54d8a4e8026eeb01f3a9b5df1c576e9dd4e838e2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Apr 2022 00:21:33 +0200 Subject: [PATCH 13/60] use server title instead of InvenTree --- InvenTree/company/templates/company/manufacturer_part.html | 3 ++- InvenTree/templates/403.html | 3 ++- InvenTree/templates/404.html | 3 ++- InvenTree/templates/500.html | 5 +++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/InvenTree/company/templates/company/manufacturer_part.html b/InvenTree/company/templates/company/manufacturer_part.html index 84e8016a59..fb33128a77 100644 --- a/InvenTree/company/templates/company/manufacturer_part.html +++ b/InvenTree/company/templates/company/manufacturer_part.html @@ -1,9 +1,10 @@ {% extends "page_base.html" %} {% load static %} {% load i18n %} +{% load inventree_extras %} {% block page_title %} -InvenTree | {% trans "Manufacturer Part" %} +{% inventree_title %} | {% trans "Manufacturer Part" %} {% endblock %} {% block sidebar %} diff --git a/InvenTree/templates/403.html b/InvenTree/templates/403.html index 372bd9fe27..4ee8367d9c 100644 --- a/InvenTree/templates/403.html +++ b/InvenTree/templates/403.html @@ -1,8 +1,9 @@ {% extends "base.html" %} {% load i18n %} +{% load inventree_extras %} {% block page_title %} -InvenTree | {% trans "Permission Denied" %} +{% inventree_title %} | {% trans "Permission Denied" %} {% endblock %} {% block content %} diff --git a/InvenTree/templates/404.html b/InvenTree/templates/404.html index 3cb6464d99..aae55031f3 100644 --- a/InvenTree/templates/404.html +++ b/InvenTree/templates/404.html @@ -1,8 +1,9 @@ {% extends "base.html" %} {% load i18n %} +{% load inventree_extras %} {% block page_title %} -InvenTree | {% trans "Page Not Found" %} +{% inventree_title %} | {% trans "Page Not Found" %} {% endblock %} {% block content %} diff --git a/InvenTree/templates/500.html b/InvenTree/templates/500.html index 3fab6c0a17..f50a5ea6fe 100644 --- a/InvenTree/templates/500.html +++ b/InvenTree/templates/500.html @@ -1,8 +1,9 @@ {% extends "base.html" %} {% load i18n %} +{% load inventree_extras %} {% block page_title %} -InvenTree | {% trans "Internal Server Error" %} +{% inventree_title %} | {% trans "Internal Server Error" %} {% endblock %} {% block content %} @@ -11,7 +12,7 @@ InvenTree | {% trans "Internal Server Error" %}

{% trans "Internal Server Error" %}

- {% trans "The InvenTree server raised an internal error" %}
+ {% blocktrans %}The {{ inventree_title }} server raised an internal error{% endblocktrans %}
{% trans "Refer to the error log in the admin interface for further details" %}
From 9673d810145a44031ebb7efcab2c1f0f0cd8397f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Apr 2022 00:23:26 +0200 Subject: [PATCH 14/60] remove InvenTree name where not needed --- InvenTree/templates/InvenTree/settings/plugin.html | 2 +- InvenTree/templates/InvenTree/settings/plugin_settings.html | 2 +- InvenTree/templates/InvenTree/settings/user_display.html | 2 +- InvenTree/templates/account/base.html | 2 +- InvenTree/templates/base.html | 2 +- InvenTree/templates/skeleton.html | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/InvenTree/templates/InvenTree/settings/plugin.html b/InvenTree/templates/InvenTree/settings/plugin.html index 2366096b87..94a166c84a 100644 --- a/InvenTree/templates/InvenTree/settings/plugin.html +++ b/InvenTree/templates/InvenTree/settings/plugin.html @@ -13,7 +13,7 @@ {% block content %}
- {% trans "Changing the settings below require you to immediatly restart InvenTree. Do not change this while under active usage." %} + {% trans "Changing the settings below require you to immediatly restart the server. Do not change this while under active usage." %}
diff --git a/InvenTree/templates/InvenTree/settings/plugin_settings.html b/InvenTree/templates/InvenTree/settings/plugin_settings.html index 9c5fa2d7c0..79150ec879 100644 --- a/InvenTree/templates/InvenTree/settings/plugin_settings.html +++ b/InvenTree/templates/InvenTree/settings/plugin_settings.html @@ -85,7 +85,7 @@ {% if plugin.is_package %} {% trans "This plugin was installed as a package" %} {% else %} - {% trans "This plugin was found in a local InvenTree path" %} + {% trans "This plugin was found in a local server path" %} {% endif %} diff --git a/InvenTree/templates/InvenTree/settings/user_display.html b/InvenTree/templates/InvenTree/settings/user_display.html index f5e74b04c1..1f52c095ac 100644 --- a/InvenTree/templates/InvenTree/settings/user_display.html +++ b/InvenTree/templates/InvenTree/settings/user_display.html @@ -101,7 +101,7 @@

{% trans "Help the translation efforts!" %}

-

{% blocktrans with link="https://crowdin.com/project/inventree" %}Native language translation of the InvenTree web application is community contributed via crowdin. Contributions are welcomed and encouraged.{% endblocktrans %}

+

{% blocktrans with link="https://crowdin.com/project/inventree" %}Native language translation of the web application is community contributed via crowdin. Contributions are welcomed and encouraged.{% endblocktrans %}

diff --git a/InvenTree/templates/account/base.html b/InvenTree/templates/account/base.html index 6c54faac67..06c9485fb5 100644 --- a/InvenTree/templates/account/base.html +++ b/InvenTree/templates/account/base.html @@ -89,7 +89,7 @@ - + diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html index 0739b42b6e..0bca5cc0f1 100644 --- a/InvenTree/templates/base.html +++ b/InvenTree/templates/base.html @@ -166,7 +166,7 @@ - + diff --git a/InvenTree/templates/skeleton.html b/InvenTree/templates/skeleton.html index 9b78a9a329..1c4775372e 100644 --- a/InvenTree/templates/skeleton.html +++ b/InvenTree/templates/skeleton.html @@ -75,7 +75,7 @@ - + {% block body_scripts_inventree %} From ff9d8e7b6ba458d0499d2c4b8a0d0bb7823e6cb8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Apr 2022 00:28:27 +0200 Subject: [PATCH 15/60] use instance title in version string --- InvenTree/part/templatetags/inventree_extras.py | 7 ++++++- InvenTree/report/templates/report/inventree_po_report.html | 2 +- InvenTree/report/templates/report/inventree_so_report.html | 2 +- .../templates/report/inventree_test_report_base.html | 2 +- InvenTree/templates/email/email.html | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py index 2d0b0660d6..0400b54ebd 100644 --- a/InvenTree/part/templatetags/inventree_extras.py +++ b/InvenTree/part/templatetags/inventree_extras.py @@ -220,8 +220,13 @@ def python_version(*args, **kwargs): @register.simple_tag() -def inventree_version(*args, **kwargs): +def inventree_version(shortstring=False, *args, **kwargs): """ Return InvenTree version string """ + if shortstring: + return _("{title} v{version}".format( + title=version.inventreeInstanceTitle(), + version=version.inventreeVersion() + )) return version.inventreeVersion() diff --git a/InvenTree/report/templates/report/inventree_po_report.html b/InvenTree/report/templates/report/inventree_po_report.html index f999644c2e..d1cae75c3b 100644 --- a/InvenTree/report/templates/report/inventree_po_report.html +++ b/InvenTree/report/templates/report/inventree_po_report.html @@ -15,7 +15,7 @@ content: "v{{report_revision}} - {{ date.isoformat }}"; {% endblock %} {% block bottom_center %} -content: "InvenTree v{% inventree_version %}"; +content: "{% inventree_version shortstring=True %}"; {% endblock %} {% block style %} diff --git a/InvenTree/report/templates/report/inventree_so_report.html b/InvenTree/report/templates/report/inventree_so_report.html index 255f0c6a50..5cb4900719 100644 --- a/InvenTree/report/templates/report/inventree_so_report.html +++ b/InvenTree/report/templates/report/inventree_so_report.html @@ -16,7 +16,7 @@ content: "v{{report_revision}} - {{ date.isoformat }}"; {% endblock %} {% block bottom_center %} -content: "InvenTree v{% inventree_version %}"; +content: "{% inventree_version shortstring=True %}"; {% endblock %} {% block style %} diff --git a/InvenTree/report/templates/report/inventree_test_report_base.html b/InvenTree/report/templates/report/inventree_test_report_base.html index d702973c30..73ee55c680 100644 --- a/InvenTree/report/templates/report/inventree_test_report_base.html +++ b/InvenTree/report/templates/report/inventree_test_report_base.html @@ -14,7 +14,7 @@ content: "{{ date.isoformat }}"; {% endblock %} {% block bottom_center %} -content: "InvenTree v{% inventree_version %}"; +content: "{% inventree_version shortstring=True %}"; {% endblock %} {% block top_center %} diff --git a/InvenTree/templates/email/email.html b/InvenTree/templates/email/email.html index 97e9a40f37..0b3c944da4 100644 --- a/InvenTree/templates/email/email.html +++ b/InvenTree/templates/email/email.html @@ -32,7 +32,7 @@ {% block footer_prefix %} {% endblock %} -

{% trans "InvenTree version" %}: {% inventree_version %} - inventree.readthedocs.io

+

{% inventree_version shortstring=True %} - readthedocs.io

{% block footer_suffix %} {% endblock %} From 1127bf2497f95c9ad3937438d84cd1a621be7f67 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Apr 2022 01:02:41 +0200 Subject: [PATCH 16/60] make it possible to resitrict the about modal --- InvenTree/common/models.py | 7 +++++++ InvenTree/part/templatetags/inventree_extras.py | 8 ++++++++ InvenTree/templates/InvenTree/settings/global.html | 1 + InvenTree/templates/base.html | 3 ++- InvenTree/templates/navbar.html | 3 +++ 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index bb7de56e99..d0ca4636a0 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -696,6 +696,13 @@ class InvenTreeSetting(BaseInvenTreeSetting): 'default': False, }, + 'INVENTREE_RESTRICT_ABOUT': { + 'name': _('Restrict showing `about`'), + 'description': _('Show the `about` modal only to superusers'), + 'validator': bool, + 'default': False, + }, + 'INVENTREE_COMPANY_NAME': { 'name': _('Company name'), 'description': _('Internal company name'), diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py index 0400b54ebd..ad23487a83 100644 --- a/InvenTree/part/templatetags/inventree_extras.py +++ b/InvenTree/part/templatetags/inventree_extras.py @@ -166,6 +166,14 @@ def inventree_demo_mode(*args, **kwargs): return djangosettings.DEMO_MODE +@register.simple_tag() +def inventree_show_about(user, *args, **kwargs): + """ Return True if the about modal should be shown """ + if InvenTreeSetting.get_setting('INVENTREE_RESTRICT_ABOUT') and not user.is_superuser: + return False + return True + + @register.simple_tag() def inventree_docker_mode(*args, **kwargs): """ Return True if the server is running as a Docker image """ diff --git a/InvenTree/templates/InvenTree/settings/global.html b/InvenTree/templates/InvenTree/settings/global.html index 60ae84f001..4d36d59369 100644 --- a/InvenTree/templates/InvenTree/settings/global.html +++ b/InvenTree/templates/InvenTree/settings/global.html @@ -15,6 +15,7 @@ {% include "InvenTree/settings/setting.html" with key="INVENTREE_INSTANCE" icon="fa-info-circle" %} {% include "InvenTree/settings/setting.html" with key="INVENTREE_INSTANCE_TITLE" icon="fa-info-circle" %} + {% include "InvenTree/settings/setting.html" with key="INVENTREE_RESTRICT_ABOUT" icon="fa-info-circle" %} {% include "InvenTree/settings/setting.html" with key="INVENTREE_BASE_URL" icon="fa-globe" %} {% include "InvenTree/settings/setting.html" with key="INVENTREE_COMPANY_NAME" icon="fa-building" %} {% include "InvenTree/settings/setting.html" with key="INVENTREE_DOWNLOAD_FROM_URL" icon="fa-cloud-download-alt" %} diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html index 0bca5cc0f1..0188ecefa5 100644 --- a/InvenTree/templates/base.html +++ b/InvenTree/templates/base.html @@ -7,6 +7,7 @@ {% settings_value "REPORT_ENABLE" as report_enabled %} {% settings_value "SERVER_RESTART_REQUIRED" as server_restart_required %} {% settings_value "LABEL_ENABLE" with user=user as labels_enabled %} +{% inventree_show_about user as show_about %} {% inventree_demo_mode as demo_mode %} @@ -130,7 +131,7 @@ {% include 'modals.html' %} - {% include 'about.html' %} + {% if show_about %}{% include 'about.html' %}{% endif %} {% include "notifications.html" %} {% include "search.html" %} diff --git a/InvenTree/templates/navbar.html b/InvenTree/templates/navbar.html index d687300eb4..3af7fe481f 100644 --- a/InvenTree/templates/navbar.html +++ b/InvenTree/templates/navbar.html @@ -7,6 +7,7 @@ {% settings_value 'STICKY_HEADER' user=request.user as sticky %} {% navigation_enabled as plugin_nav %} {% inventree_demo_mode as demo %} +{% inventree_show_about user as show_about %}