From 10758a9626aa4874a48c47b48973348c8b26fc32 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 25 Oct 2020 07:49:38 +1100 Subject: [PATCH] Improvements for global settings - Name and description are defined in models.py - Lookup functions for name / description / units / default - Shortcut template for rending settings - More unit testing --- InvenTree/common/apps.py | 6 +- InvenTree/common/models.py | 146 +++++++++++++++--- InvenTree/common/tests.py | 27 +++- .../part/templatetags/inventree_extras.py | 29 +++- .../templates/InvenTree/settings/build.html | 13 +- .../templates/InvenTree/settings/part.html | 12 +- .../templates/InvenTree/settings/po.html | 6 + .../templates/InvenTree/settings/setting.html | 15 ++ .../templates/InvenTree/settings/so.html | 8 + InvenTree/templates/js/build.html | 2 +- InvenTree/templates/js/order.html | 4 +- 11 files changed, 229 insertions(+), 39 deletions(-) create mode 100644 InvenTree/templates/InvenTree/settings/setting.html diff --git a/InvenTree/common/apps.py b/InvenTree/common/apps.py index 0535709686..06b825c574 100644 --- a/InvenTree/common/apps.py +++ b/InvenTree/common/apps.py @@ -32,7 +32,7 @@ class CommonConfig(AppConfig): return # Default instance name - instance_name = 'InvenTree Server' + instance_name = InvenTreeSetting.get_default_value('INVENTREE_INSTANCE') # Use the old name if it exists if InvenTreeSetting.objects.filter(key='InstanceName').exists(): @@ -59,12 +59,12 @@ class CommonConfig(AppConfig): from .models import InvenTreeSetting - for key in InvenTreeSetting.DEFAULT_VALUES.keys(): + for key in InvenTreeSetting.GLOBAL_SETTINGS.keys(): try: settings = InvenTreeSetting.objects.filter(key__iexact=key) if settings.count() == 0: - value = InvenTreeSetting.DEFAULT_VALUES[key] + value = InvenTreeSetting.get_default_value(key) print(f"Creating default setting for {key} -> '{value}'") diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 31f8e12260..1c460225c8 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -27,34 +27,144 @@ class InvenTreeSetting(models.Model): even if that key does not exist. """ - # Dict of default values for various internal settings - DEFAULT_VALUES = { - # Global inventree settings - 'INVENTREE_INSTANCE': 'InvenTree Server', + """ + Dict of all global settings values: - # Part settings - 'PART_IPN_REGEX': '', - 'PART_COPY_BOM': True, - 'PART_COPY_PARAMETERS': True, - 'PART_COPY_TESTS': True, + The key of each item is the name of the value as it appears in the database. - # Stock settings + Each global setting has the following parameters: + + - name: Translatable string name of the setting (required) + - description: Translatable string description of the setting (required) + - default: Default value (optional) + - units: Units of the particular setting (optional) + - validator: Validation function for the setting (optional) - # Build Order settings - 'BUILDORDER_REFERENCE_PREFIX': 'BO', - 'BUILDORDER_REFERENCE_REGEX': '', + The keys must be upper-case + """ - # Purchase Order Settings - 'PURCHASEORDER_REFERENCE_PREFIX': 'PO', + GLOBAL_SETTINGS = { - # Sales Order Settings - 'SALESORDER_REFERENCE_PREFIX': 'SO', + 'INVENTREE_INSTANCE': { + 'name': _('InvenTree Instance Name'), + 'default': 'InvenTree server', + 'description': _('String descriptor for the server instance'), + }, + + 'PART_IPN_REGEX': { + 'name': _('IPN Regex'), + 'description': _('Regular expression pattern for matching Part IPN') + }, + + 'PART_COPY_BOM': { + 'name': _('Copy Part BOM Data'), + 'description': _('Copy BOM data by default when duplicating a part'), + 'default': True, + }, + + 'PART_COPY_PARAMETERS': { + 'name': _('Copy Part Parameter Data'), + 'description': _('Copy parameter data by default when duplicating a part'), + 'default': True, + }, + + 'PART_COPY_TESTS': { + 'name': _('Copy Part Test Data'), + 'description': _('Copy test data by default when duplicating a part'), + 'default': True, + }, + + 'BUILDORDER_REFERENCE_PREFIX': { + 'name': _('Build Order Reference Prefix'), + 'description': _('Prefix value for build order reference'), + 'default': 'BO', + }, + + 'BUILDORDER_REFERENCE_REGEX': { + 'name': _('Build Order Reference Regex'), + 'description': _('Regular expression pattern for matching build order reference') + }, + + 'SALESORDER_REFERENCE_PREFIX': { + 'name': _('Sales Order Reference Prefix'), + 'description': _('Prefix value for sales order reference'), + }, + + 'PURCHASEORDER_REFERENCE_PREFIX': { + 'name': _('Purchase Order Reference Prefix'), + 'description': _('Prefix value for purchase order reference'), + }, } class Meta: verbose_name = "InvenTree Setting" verbose_name_plural = "InvenTree Settings" + @classmethod + def get_setting_name(cls, key): + """ + Return the name of a particular setting. + + If it does not exist, return an empty string. + """ + + key = str(key).strip().upper() + + if key in cls.GLOBAL_SETTINGS: + setting = cls.GLOBAL_SETTINGS[key] + return setting.get('name', '') + else: + return '' + + @classmethod + def get_setting_description(cls, key): + """ + Return the description for a particular setting. + + If it does not exist, return an empty string. + """ + + key = str(key).strip().upper() + + if key in cls.GLOBAL_SETTINGS: + setting = cls.GLOBAL_SETTINGS[key] + return setting.get('description', '') + else: + return '' + + @classmethod + def get_setting_units(cls, key): + """ + Return the units for a particular setting. + + If it does not exist, return an empty string. + """ + + key = str(key).strip().upper() + + if key in cls.GLOBAL_SETTINGS: + setting = cls.GLOBAL_SETTINGS[key] + return setting.get('units', '') + else: + return '' + + + @classmethod + def get_default_value(cls, key): + """ + Return the default value for a particular setting. + + If it does not exist, return an empty string + """ + + key = str(key).strip().upper() + + if key in cls.GLOBAL_SETTINGS: + setting = cls.GLOBAL_SETTINGS[key] + return setting.get('default', '') + else: + return '' + @classmethod def get_setting(cls, key, backup_value=None): """ @@ -64,7 +174,7 @@ class InvenTreeSetting(models.Model): # If no backup value is specified, atttempt to retrieve a "default" value if backup_value is None: - backup_value = InvenTreeSetting.DEFAULT_VALUES.get(key, None) + backup_value = cls.get_default_value(key) try: settings = InvenTreeSetting.objects.filter(key__iexact=key) diff --git a/InvenTree/common/tests.py b/InvenTree/common/tests.py index a5d32dc3d6..e0b6812f40 100644 --- a/InvenTree/common/tests.py +++ b/InvenTree/common/tests.py @@ -35,14 +35,37 @@ class SettingsTest(TestCase): self.client.login(username='username', password='password') + def test_required_values(self): + """ + - Ensure that every global setting has a name. + - Ensure that every global setting has a description. + """ + + for key in InvenTreeSetting.GLOBAL_SETTINGS.keys(): + + setting = InvenTreeSetting.GLOBAL_SETTINGS[key] + + name = setting.get('name', None) + + if name is None: + raise ValueError(f'Missing GLOBAL_SETTING name for {key}') + + description = setting.get('description', None) + + if description is None: + raise ValueError(f'Missing GLOBAL_SETTING description for {key}') + + if not key == key.upper(): + raise ValueError(f"GLOBAL_SETTINGS key '{key}' is not uppercase") + def test_defaults(self): """ Populate the settings with default values """ - for key in InvenTreeSetting.DEFAULT_VALUES.keys(): + for key in InvenTreeSetting.GLOBAL_SETTINGS.keys(): - value = InvenTreeSetting.DEFAULT_VALUES[key] + value = InvenTreeSetting.get_default_value(key) InvenTreeSetting.set_setting(key, value, self.user) diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py index 2c175003d0..228d530934 100644 --- a/InvenTree/part/templatetags/inventree_extras.py +++ b/InvenTree/part/templatetags/inventree_extras.py @@ -87,7 +87,34 @@ def inventree_docs_url(*args, **kwargs): @register.simple_tag() -def inventree_setting(key, *args, **kwargs): +def settings_name(key, *args, **kwargs): + """ + Returns the name of a GLOBAL_SETTINGS object + """ + + return InvenTreeSetting.get_setting_name(key) + +@register.simple_tag() +def settings_description(key, *args, **kwargs): + """ + Returns the description of a GLOBAL_SETTINGS object + """ + + return InvenTreeSetting.get_setting_description(key) + +@register.simple_tag() +def settings_units(key, *args, **kwargs): + """ + Return the units of a GLOBAL_SETTINGS object + """ + + return InvenTreeSetting.get_setting_units(key) + +@register.simple_tag() +def settings_value(key, *args, **kwargs): + """ + Returns the value of a GLOBAL_SETTINGS object + """ return InvenTreeSetting.get_setting(key, backup_value=kwargs.get('backup', None)) diff --git a/InvenTree/templates/InvenTree/settings/build.html b/InvenTree/templates/InvenTree/settings/build.html index 6d19e21f1a..781402795b 100644 --- a/InvenTree/templates/InvenTree/settings/build.html +++ b/InvenTree/templates/InvenTree/settings/build.html @@ -15,17 +15,8 @@ - - - - - - - - - - - + {% include "InvenTree/settings/setting.html" with key="BUILDORDER_REFERENCE_PREFIX" %} + {% include "InvenTree/settings/setting.html" with key="BUILDORDER_REFERENCE_REGEX" %}
{% trans "Reference Prefix" %}{% inventree_setting 'BUILDORDER_REFERENCE_PREFIX' backup='BO' %}{% trans "Prefix for Build Order reference" %}
{% trans "Reference Regex" %}{% inventree_setting 'BUILDORDER_REFERENCE_REGEX' %}{% trans "Regex validator for Build Order reference" %}
diff --git a/InvenTree/templates/InvenTree/settings/part.html b/InvenTree/templates/InvenTree/settings/part.html index 7c028ca6d6..cac04a60ff 100644 --- a/InvenTree/templates/InvenTree/settings/part.html +++ b/InvenTree/templates/InvenTree/settings/part.html @@ -11,6 +11,16 @@ {% block settings %} + + + + {% include "InvenTree/settings/setting.html" with key="PART_IPN_REGEX" %} + {% include "InvenTree/settings/setting.html" with key="PART_COPY_BOM" %} + {% include "InvenTree/settings/setting.html" with key="PART_COPY_PARAMETERS" %} + {% include "InvenTree/settings/setting.html" with key="PART_COPY_TESTS" %} + +
+

{% trans "Part Parameter Templates" %}

@@ -53,7 +63,7 @@ var bEdit = ""; var bDel = ""; - var html = "
" + bEdit + bDel + "
"; + var html = "
" + bEdit + bDel + "
"; return html; } diff --git a/InvenTree/templates/InvenTree/settings/po.html b/InvenTree/templates/InvenTree/settings/po.html index 7d32611404..a709d40dd3 100644 --- a/InvenTree/templates/InvenTree/settings/po.html +++ b/InvenTree/templates/InvenTree/settings/po.html @@ -10,4 +10,10 @@ {% endblock %} {% block settings %} + + + + {% include "InvenTree/settings/setting.html" with key="PURCHASEORDER_REFERENCE_PREFIX" %} + +
{% endblock %} \ No newline at end of file diff --git a/InvenTree/templates/InvenTree/settings/setting.html b/InvenTree/templates/InvenTree/settings/setting.html new file mode 100644 index 0000000000..347b93553d --- /dev/null +++ b/InvenTree/templates/InvenTree/settings/setting.html @@ -0,0 +1,15 @@ +{% load inventree_extras %} +{% load i18n %} + + + {% settings_name key %} + {% settings_value key %}{% settings_units key %} + {% settings_description key %} + +
+ +
+ + \ No newline at end of file diff --git a/InvenTree/templates/InvenTree/settings/so.html b/InvenTree/templates/InvenTree/settings/so.html index e66fd85148..368374532f 100644 --- a/InvenTree/templates/InvenTree/settings/so.html +++ b/InvenTree/templates/InvenTree/settings/so.html @@ -10,4 +10,12 @@ {% endblock %} {% block settings %} + + + + + {% include "InvenTree/settings/setting.html" with key="SALESORDER_REFERENCE_PREFIX" %} + +
+ {% endblock %} \ No newline at end of file diff --git a/InvenTree/templates/js/build.html b/InvenTree/templates/js/build.html index 6a12b97bfd..1f577802b2 100644 --- a/InvenTree/templates/js/build.html +++ b/InvenTree/templates/js/build.html @@ -42,7 +42,7 @@ function loadBuildTable(table, options) { switchable: false, formatter: function(value, row, index, field) { - var prefix = "{% inventree_setting 'BUILDORDER_REFERENCE_PREFIX' %}"; + var prefix = "{% settings_value 'BUILDORDER_REFERENCE_PREFIX' %}"; if (prefix) { value = `${prefix}${value}`; diff --git a/InvenTree/templates/js/order.html b/InvenTree/templates/js/order.html index 4dbfbefa13..0c958c65a2 100644 --- a/InvenTree/templates/js/order.html +++ b/InvenTree/templates/js/order.html @@ -139,7 +139,7 @@ function loadPurchaseOrderTable(table, options) { title: '{% trans "Purchase Order" %}', formatter: function(value, row, index, field) { - var prefix = "{% inventree_setting 'PURCHASEORDER_REFERENCE_PREFIX' %}"; + var prefix = "{% settings_value 'PURCHASEORDER_REFERENCE_PREFIX' %}"; if (prefix) { value = `${prefix}${value}`; @@ -221,7 +221,7 @@ function loadSalesOrderTable(table, options) { title: '{% trans "Sales Order" %}', formatter: function(value, row, index, field) { - var prefix = "{% inventree_setting 'SALESORDER_REFERENCE_PREFIX' %}"; + var prefix = "{% settings_value 'SALESORDER_REFERENCE_PREFIX' %}"; if (prefix) { value = `${prefix}${value}`;