mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge pull request #1070 from SchrodingersGat/global-settings
Global settings
This commit is contained in:
commit
720579dcd7
@ -120,6 +120,19 @@ def str2bool(text, test=True):
|
||||
return str(text).lower() in ['0', 'n', 'no', 'none', 'f', 'false', 'off', ]
|
||||
|
||||
|
||||
def is_bool(text):
|
||||
"""
|
||||
Determine if a string value 'looks' like a boolean.
|
||||
"""
|
||||
|
||||
if str2bool(text, True):
|
||||
return True
|
||||
elif str2bool(text, False):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def isNull(text):
|
||||
"""
|
||||
Test if a string 'looks' like a null value.
|
||||
|
@ -39,6 +39,8 @@ from .views import IndexView, SearchView, DatabaseStatsView
|
||||
from .views import SettingsView, EditUserView, SetPasswordView, ColorThemeSelectView
|
||||
from .views import DynamicJsView
|
||||
|
||||
from common.views import SettingEdit
|
||||
|
||||
from .api import InfoView
|
||||
from .api import ActionPluginView
|
||||
|
||||
@ -71,6 +73,7 @@ settings_urls = [
|
||||
url(r'^user/?', SettingsView.as_view(template_name='InvenTree/settings/user.html'), name='settings-user'),
|
||||
url(r'^theme/?', ColorThemeSelectView.as_view(), name='settings-theme'),
|
||||
|
||||
url(r'^global/?', SettingsView.as_view(template_name='InvenTree/settings/global.html'), name='settings-global'),
|
||||
url(r'^currency/?', SettingsView.as_view(template_name='InvenTree/settings/currency.html'), name='settings-currency'),
|
||||
url(r'^part/?', SettingsView.as_view(template_name='InvenTree/settings/part.html'), name='settings-part'),
|
||||
url(r'^stock/?', SettingsView.as_view(template_name='InvenTree/settings/stock.html'), name='settings-stock'),
|
||||
@ -78,6 +81,8 @@ settings_urls = [
|
||||
url(r'^purchase-order/?', SettingsView.as_view(template_name='InvenTree/settings/po.html'), name='settings-po'),
|
||||
url(r'^sales-order/?', SettingsView.as_view(template_name='InvenTree/settings/so.html'), name='settings-so'),
|
||||
|
||||
url(r'^(?P<pk>\d+)/edit/?', SettingEdit.as_view(), name='setting-edit'),
|
||||
|
||||
# Catch any other urls
|
||||
url(r'^.*$', SettingsView.as_view(template_name='InvenTree/settings/user.html'), name='settings'),
|
||||
]
|
||||
|
@ -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}'")
|
||||
|
||||
|
@ -33,6 +33,5 @@ class SettingEditForm(HelperForm):
|
||||
model = InvenTreeSetting
|
||||
|
||||
fields = [
|
||||
'key',
|
||||
'value'
|
||||
]
|
||||
|
@ -11,10 +11,12 @@ import decimal
|
||||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
import InvenTree.helpers
|
||||
import InvenTree.fields
|
||||
|
||||
|
||||
@ -27,34 +29,205 @@ 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:
|
||||
|
||||
# Build Order settings
|
||||
'BUILDORDER_REFERENCE_PREFIX': 'BO',
|
||||
'BUILDORDER_REFERENCE_REGEX': '',
|
||||
- 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)
|
||||
|
||||
# Purchase Order Settings
|
||||
'PURCHASEORDER_REFERENCE_PREFIX': 'PO',
|
||||
The keys must be upper-case
|
||||
"""
|
||||
|
||||
# Sales Order Settings
|
||||
'SALESORDER_REFERENCE_PREFIX': 'SO',
|
||||
GLOBAL_SETTINGS = {
|
||||
|
||||
'INVENTREE_INSTANCE': {
|
||||
'name': _('InvenTree Instance Name'),
|
||||
'default': 'InvenTree server',
|
||||
'description': _('String descriptor for the server instance'),
|
||||
},
|
||||
|
||||
'INVENTREE_COMPANY_NAME': {
|
||||
'name': _('Company name'),
|
||||
'description': _('Internal company name'),
|
||||
'default': 'My company name',
|
||||
},
|
||||
|
||||
'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,
|
||||
'validator': bool,
|
||||
},
|
||||
|
||||
'PART_COPY_PARAMETERS': {
|
||||
'name': _('Copy Part Parameter Data'),
|
||||
'description': _('Copy parameter data by default when duplicating a part'),
|
||||
'default': True,
|
||||
'validator': bool,
|
||||
},
|
||||
|
||||
'PART_COPY_TESTS': {
|
||||
'name': _('Copy Part Test Data'),
|
||||
'description': _('Copy test data by default when duplicating a part'),
|
||||
'default': True,
|
||||
'validator': bool
|
||||
},
|
||||
|
||||
'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_setting_validator(cls, key):
|
||||
"""
|
||||
Return the validator for a particular setting.
|
||||
|
||||
If it does not exist, return None
|
||||
"""
|
||||
|
||||
key = str(key).strip().upper()
|
||||
|
||||
if key in cls.GLOBAL_SETTINGS:
|
||||
setting = cls.GLOBAL_SETTINGS[key]
|
||||
return setting.get('validator', None)
|
||||
else:
|
||||
return None
|
||||
|
||||
@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_object(cls, key):
|
||||
"""
|
||||
Return an InvenTreeSetting object matching the given key.
|
||||
|
||||
- Key is case-insensitive
|
||||
- Returns None if no match is made
|
||||
"""
|
||||
|
||||
key = str(key).strip().upper()
|
||||
|
||||
try:
|
||||
setting = InvenTreeSetting.objects.filter(key__iexact=key).first()
|
||||
except (InvenTreeSetting.DoesNotExist):
|
||||
# Create the setting if it does not exist
|
||||
setting = InvenTreeSetting.create(
|
||||
key=key,
|
||||
value=InvenTreeSetting.get_default_value(key)
|
||||
)
|
||||
|
||||
return setting
|
||||
|
||||
@classmethod
|
||||
def get_setting_pk(cls, key):
|
||||
"""
|
||||
Return the primary-key value for a given setting.
|
||||
|
||||
If the setting does not exist, return None
|
||||
"""
|
||||
|
||||
setting = InvenTreeSetting.get_setting_object(cls)
|
||||
|
||||
if setting:
|
||||
return setting.pk
|
||||
else:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_setting(cls, key, backup_value=None):
|
||||
"""
|
||||
@ -64,16 +237,13 @@ 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)
|
||||
setting = InvenTreeSetting.get_setting_object(key)
|
||||
|
||||
if len(settings) > 0:
|
||||
return settings[0].value
|
||||
else:
|
||||
return backup_value
|
||||
except InvenTreeSetting.DoesNotExist:
|
||||
if setting:
|
||||
return setting.value
|
||||
else:
|
||||
return backup_value
|
||||
|
||||
@classmethod
|
||||
@ -108,6 +278,59 @@ class InvenTreeSetting(models.Model):
|
||||
|
||||
value = models.CharField(max_length=200, blank=True, unique=False, help_text=_('Settings value'))
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return InvenTreeSetting.get_setting_name(self.key)
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return InvenTreeSetting.get_setting_description(self.key)
|
||||
|
||||
@property
|
||||
def units(self):
|
||||
return InvenTreeSetting.get_setting_units(self.key)
|
||||
|
||||
def clean(self):
|
||||
"""
|
||||
If a validator (or multiple validators) are defined for a particular setting key,
|
||||
run them against the 'value' field.
|
||||
"""
|
||||
|
||||
super().clean()
|
||||
|
||||
validator = InvenTreeSetting.get_setting_validator(self.key)
|
||||
|
||||
if validator is not None:
|
||||
self.run_validator(validator)
|
||||
|
||||
def run_validator(self, validator):
|
||||
"""
|
||||
Run a validator against the 'value' field for this InvenTreeSetting object.
|
||||
"""
|
||||
|
||||
if validator is None:
|
||||
return
|
||||
|
||||
# If a list of validators is supplied, iterate through each one
|
||||
if type(validator) in [list, tuple]:
|
||||
for v in validator:
|
||||
self.run_validator(v)
|
||||
|
||||
return
|
||||
|
||||
# Check if a 'type' has been specified for this value
|
||||
if type(validator) == type:
|
||||
|
||||
if validator == bool:
|
||||
# Value must "look like" a boolean value
|
||||
if InvenTree.helpers.is_bool(self.value):
|
||||
# Coerce into either "True" or "False"
|
||||
self.value = str(InvenTree.helpers.str2bool(self.value))
|
||||
else:
|
||||
raise ValidationError({
|
||||
'value': _('Value must be a boolean value')
|
||||
})
|
||||
|
||||
def validate_unique(self, exclude=None):
|
||||
""" Ensure that the key:value pair is unique.
|
||||
In addition to the base validators, this ensures that the 'key'
|
||||
@ -123,6 +346,24 @@ class InvenTreeSetting(models.Model):
|
||||
except InvenTreeSetting.DoesNotExist:
|
||||
pass
|
||||
|
||||
def is_bool(self):
|
||||
"""
|
||||
Check if this setting is required to be a boolean value
|
||||
"""
|
||||
|
||||
validator = InvenTreeSetting.get_setting_validator(self.key)
|
||||
|
||||
return validator == bool
|
||||
|
||||
def as_bool(self):
|
||||
"""
|
||||
Return the value of this setting converted to a boolean value.
|
||||
|
||||
Warning: Only use on values where is_bool evaluates to true!
|
||||
"""
|
||||
|
||||
return InvenTree.helpers.str2bool(self.value)
|
||||
|
||||
|
||||
class Currency(models.Model):
|
||||
"""
|
||||
|
14
InvenTree/common/templates/common/edit_setting.html
Normal file
14
InvenTree/common/templates/common/edit_setting.html
Normal file
@ -0,0 +1,14 @@
|
||||
{% extends "modal_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block pre_form_content %}
|
||||
|
||||
{{ block.super }}
|
||||
<!--
|
||||
<p>
|
||||
<b>{{ name }}</b><br>
|
||||
{{ description }}<br>
|
||||
<i>{% trans "Current value" %}: {{ value }}</i>
|
||||
</p>
|
||||
-->
|
||||
{% endblock %}
|
@ -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)
|
||||
|
||||
|
@ -6,8 +6,10 @@ Django views for interacting with common models
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.forms import CheckboxInput
|
||||
|
||||
from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView
|
||||
from InvenTree.helpers import str2bool
|
||||
|
||||
from . import models
|
||||
from . import forms
|
||||
@ -46,3 +48,47 @@ class SettingEdit(AjaxUpdateView):
|
||||
model = models.InvenTreeSetting
|
||||
ajax_form_title = _('Change Setting')
|
||||
form_class = forms.SettingEditForm
|
||||
ajax_template_name = "common/edit_setting.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""
|
||||
Add extra context information about the particular setting object.
|
||||
"""
|
||||
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
|
||||
setting = self.get_object()
|
||||
|
||||
ctx['key'] = setting.key
|
||||
ctx['value'] = setting.value
|
||||
ctx['name'] = models.InvenTreeSetting.get_setting_name(setting.key)
|
||||
ctx['description'] = models.InvenTreeSetting.get_setting_description(setting.key)
|
||||
|
||||
return ctx
|
||||
|
||||
def get_form(self):
|
||||
"""
|
||||
Override default get_form behaviour
|
||||
"""
|
||||
|
||||
form = super().get_form()
|
||||
|
||||
setting = self.get_object()
|
||||
|
||||
if setting.is_bool():
|
||||
form.fields['value'].widget = CheckboxInput()
|
||||
|
||||
self.object.value = str2bool(setting.value)
|
||||
form.fields['value'].value = str2bool(setting.value)
|
||||
|
||||
name = models.InvenTreeSetting.get_setting_name(setting.key)
|
||||
|
||||
if name:
|
||||
form.fields['value'].label = name
|
||||
|
||||
description = models.InvenTreeSetting.get_setting_description(setting.key)
|
||||
|
||||
if description:
|
||||
form.fields['value'].help_text = description
|
||||
|
||||
return form
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,8 @@ import os
|
||||
|
||||
from django import template
|
||||
from InvenTree import version, settings
|
||||
from InvenTree.helpers import decimal2string
|
||||
|
||||
import InvenTree.helpers
|
||||
|
||||
from common.models import InvenTreeSetting, ColorTheme
|
||||
|
||||
@ -16,7 +17,14 @@ register = template.Library()
|
||||
def decimal(x, *args, **kwargs):
|
||||
""" Simplified rendering of a decimal number """
|
||||
|
||||
return decimal2string(x)
|
||||
return InvenTree.helpers.decimal2string(x)
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def str2bool(x, *args, **kwargs):
|
||||
""" Convert a string to a boolean value """
|
||||
|
||||
return InvenTree.helpers.str2bool(x)
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
@ -28,7 +36,7 @@ def inrange(n, *args, **kwargs):
|
||||
@register.simple_tag()
|
||||
def multiply(x, y, *args, **kwargs):
|
||||
""" Multiply two numbers together """
|
||||
return decimal2string(x * y)
|
||||
return InvenTree.helpers.decimal2string(x * y)
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
@ -41,7 +49,7 @@ def add(x, y, *args, **kwargs):
|
||||
def part_allocation_count(build, part, *args, **kwargs):
|
||||
""" Return the total number of <part> allocated to <build> """
|
||||
|
||||
return decimal2string(build.getAllocatedQuantity(part))
|
||||
return InvenTree.helpers.decimal2string(build.getAllocatedQuantity(part))
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
@ -87,8 +95,15 @@ def inventree_docs_url(*args, **kwargs):
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def inventree_setting(key, *args, **kwargs):
|
||||
return InvenTreeSetting.get_setting(key, backup_value=kwargs.get('backup', None))
|
||||
def setting_object(key, *args, **kwargs):
|
||||
"""
|
||||
Return a setting object speciifed by the given key
|
||||
(Or return None if the setting does not exist)
|
||||
"""
|
||||
|
||||
setting = InvenTreeSetting.get_setting_object(key)
|
||||
|
||||
return setting
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
|
@ -15,17 +15,8 @@
|
||||
<table class='table table-striped table-condensed'>
|
||||
<thead></thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{% trans "Reference Prefix" %}</th>
|
||||
<th>{% inventree_setting 'BUILDORDER_REFERENCE_PREFIX' backup='BO' %}</th>
|
||||
<td>{% trans "Prefix for Build Order reference" %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{% trans "Reference Regex" %}</th>
|
||||
<th>{% inventree_setting 'BUILDORDER_REFERENCE_REGEX' %}</th>
|
||||
<td>{% trans "Regex validator for Build Order reference" %}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REFERENCE_PREFIX" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REFERENCE_REGEX" %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
23
InvenTree/templates/InvenTree/settings/global.html
Normal file
23
InvenTree/templates/InvenTree/settings/global.html
Normal file
@ -0,0 +1,23 @@
|
||||
{% extends "InvenTree/settings/settings.html" %}
|
||||
{% load i18n %}
|
||||
{% load inventree_extras %}
|
||||
|
||||
{% block tabs %}
|
||||
{% include "InvenTree/settings/tabs.html" with tab='global' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block subtitle %}
|
||||
{% trans "Global InvenTree Settings" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block settings %}
|
||||
|
||||
<table class='table table-striped table-condensed'>
|
||||
<thead></thead>
|
||||
<tbody>
|
||||
{% include "InvenTree/settings/setting.html" with key="INVENTREE_INSTANCE" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="INVENTREE_COMPANY_NAME" %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
@ -11,6 +11,16 @@
|
||||
|
||||
{% block settings %}
|
||||
|
||||
<table class='table table-striped table-condensed'>
|
||||
<thead></thead>
|
||||
<tbody>
|
||||
{% 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" %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4>{% trans "Part Parameter Templates" %}</h4>
|
||||
|
||||
<div id='param-buttons'>
|
||||
@ -53,7 +63,7 @@
|
||||
var bEdit = "<button title='{% trans "Edit Template" %}' class='template-edit btn btn-default btn-glyph' type='button' pk='" + row.pk + "'><span class='fas fa-edit'></span></button>";
|
||||
var bDel = "<button title='{% trans "Delete Template" %}' class='template-delete btn btn-default btn-glyph' type='button' pk='" + row.pk + "'><span class='fas fa-trash-alt icon-red'></span></button>";
|
||||
|
||||
var html = "<div class='btn-group' role='group'>" + bEdit + bDel + "</div>";
|
||||
var html = "<div class='btn-group float-right' role='group'>" + bEdit + bDel + "</div>";
|
||||
|
||||
return html;
|
||||
}
|
||||
|
@ -10,4 +10,10 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block settings %}
|
||||
<table class='table table-striped table-condensed'>
|
||||
<thead></thead>
|
||||
<tbody>
|
||||
{% include "InvenTree/settings/setting.html" with key="PURCHASEORDER_REFERENCE_PREFIX" %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
29
InvenTree/templates/InvenTree/settings/setting.html
Normal file
29
InvenTree/templates/InvenTree/settings/setting.html
Normal file
@ -0,0 +1,29 @@
|
||||
{% load inventree_extras %}
|
||||
{% load i18n %}
|
||||
|
||||
{% setting_object key as setting %}
|
||||
<tr>
|
||||
<td><b>{{ setting.name }}</b></td>
|
||||
<td>
|
||||
{% if setting.is_bool %}
|
||||
<div>
|
||||
<input fieldname='{{ setting.key }}' class='slidey' type='checkbox' data-offstyle='warning' data-onstyle='success' data-size='small' data-toggle='toggle' disabled autocomplete='off' {% if setting.as_bool %}checked=''{% endif %}>
|
||||
</div>
|
||||
{% else %}
|
||||
{% if setting.value %}
|
||||
<b>{{ setting.value }}</b>{{ setting.units }}</td>
|
||||
{% else %}
|
||||
<i>{% trans "No value set" %}</i>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<td>
|
||||
{{ setting.description }}
|
||||
</td>
|
||||
<td>
|
||||
<div class='btn-group float-right'>
|
||||
<button class='btn btn-default btn-glyph btn-edit-setting' pk='{{ setting.pk }}' setting='{{ key }}' title='{% trans "Edit setting" %}'>
|
||||
<span class='fas fa-edit icon-green'></span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
@ -37,3 +37,20 @@ InvenTree | {% trans "Settings" %}
|
||||
{% block js_load %}
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
|
||||
{% block js_ready %}
|
||||
{{ block.super }}
|
||||
|
||||
$('table').find('.btn-edit-setting').click(function() {
|
||||
var setting = $(this).attr('setting');
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
launchModalForm(
|
||||
`/settings/${pk}/edit/`,
|
||||
{
|
||||
reload: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
{% endblock %}
|
||||
|
@ -10,4 +10,12 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block settings %}
|
||||
|
||||
<table class='table table-striped table-condensed'>
|
||||
<thead></thead>
|
||||
<tbody>
|
||||
{% include "InvenTree/settings/setting.html" with key="SALESORDER_REFERENCE_PREFIX" %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
@ -9,8 +9,12 @@
|
||||
<a href="{% url 'settings-theme' %}"><span class='fas fa-fill'></span> {% trans "Theme" %}</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% if user.is_staff %}
|
||||
<h4><span class='fas fa-cogs'></span> {% trans "InvenTree Settings" %}</h4>
|
||||
<ul class='nav nav-pills nav-stacked'>
|
||||
<li {% if tab == 'global' %} class='active' {% endif %}>
|
||||
<a href='{% url "settings-global" %}'><span class='fas fa-globe'></span> {% trans "Global" %}</a>
|
||||
</li>
|
||||
<li{% ifequal tab 'currency' %} class='active'{% endifequal %}>
|
||||
<a href="{% url 'settings-currency' %}"><span class='fas fa-dollar-sign'></span> {% trans "Currency" %}</a>
|
||||
</li>
|
||||
@ -30,3 +34,4 @@
|
||||
<a href="{% url 'settings-so' %}"><span class='fas fa-truck'></span> {% trans "Sales Orders" %}</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
@ -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}`;
|
||||
|
@ -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}`;
|
||||
|
Loading…
Reference in New Issue
Block a user