Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2019-09-15 23:29:36 +10:00
commit f64758eb03
9 changed files with 180 additions and 1 deletions

View File

@ -4,6 +4,10 @@ Contributions to InvenTree are welcomed - please follow the guidelines below.
No pushing to master! New featues must be submitted in a separate branch (one branch per feature). No pushing to master! New featues must be submitted in a separate branch (one branch per feature).
## Include Migration Files
Any required migration files **must** be included in the commit, or the pull-request will be rejected. If you change the underlying database schema, make sure you run `make migrate` and commit the migration files before submitting the PR.
## Testing ## Testing
Any new code should be covered by unit tests - a submitted PR may not be accepted if the code coverage is decreased. Any new code should be covered by unit tests - a submitted PR may not be accepted if the code coverage is decreased.

View File

@ -61,6 +61,7 @@ settings_urls = [
url(r'^user/?', SettingsView.as_view(template_name='InvenTree/settings/user.html'), name='settings-user'), url(r'^user/?', SettingsView.as_view(template_name='InvenTree/settings/user.html'), name='settings-user'),
url(r'^currency/?', SettingsView.as_view(template_name='InvenTree/settings/currency.html'), name='settings-currency'), 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'^part/?', SettingsView.as_view(template_name='InvenTree/settings/part.html'), name='settings-part'),
url(r'^other/?', SettingsView.as_view(template_name='InvenTree/settings/other.html'), name='settings-other'),
# Catch any other urls # Catch any other urls
url(r'^.*$', SettingsView.as_view(template_name='InvenTree/settings/user.html'), name='settings'), url(r'^.*$', SettingsView.as_view(template_name='InvenTree/settings/user.html'), name='settings'),

View File

@ -16,6 +16,7 @@ from django.views.generic import UpdateView, CreateView
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from part.models import Part from part.models import Part
from common.models import InvenTreeSetting
from .forms import DeleteForm, EditUserForm, SetPasswordForm from .forms import DeleteForm, EditUserForm, SetPasswordForm
from .helpers import str2bool from .helpers import str2bool
@ -511,3 +512,11 @@ class SettingsView(TemplateView):
""" """
template_name = "InvenTree/settings.html" template_name = "InvenTree/settings.html"
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs).copy()
ctx['settings'] = InvenTreeSetting.objects.all().order_by('key')
return ctx

View File

@ -5,11 +5,17 @@ from django.contrib import admin
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from .models import Currency from .models import Currency, InvenTreeSetting
class CurrencyAdmin(ImportExportModelAdmin): class CurrencyAdmin(ImportExportModelAdmin):
list_display = ('symbol', 'suffix', 'description', 'value', 'base') list_display = ('symbol', 'suffix', 'description', 'value', 'base')
class SettingsAdmin(ImportExportModelAdmin):
list_display = ('key', 'value', 'description')
admin.site.register(Currency, CurrencyAdmin) admin.site.register(Currency, CurrencyAdmin)
admin.site.register(InvenTreeSetting, SettingsAdmin)

View File

@ -0,0 +1,21 @@
# Generated by Django 2.2.5 on 2019-09-15 12:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('common', '0003_auto_20190902_2310'),
]
operations = [
migrations.CreateModel(
name='InvenTreeSetting',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('key', models.CharField(help_text='Settings key', max_length=50, unique=True)),
('value', models.CharField(blank=True, help_text='Settings value', max_length=200)),
],
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 2.2.5 on 2019-09-15 12:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('common', '0004_inventreesetting'),
]
operations = [
migrations.AddField(
model_name='inventreesetting',
name='description',
field=models.CharField(blank=True, help_text='Settings description', max_length=200),
),
migrations.AlterField(
model_name='inventreesetting',
name='key',
field=models.CharField(help_text='Settings key (must be unique - case insensitive', max_length=50, unique=True),
),
]

View File

@ -9,6 +9,79 @@ from __future__ import unicode_literals
from django.db import models from django.db import models
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.core.validators import MinValueValidator, MaxValueValidator from django.core.validators import MinValueValidator, MaxValueValidator
from django.core.exceptions import ValidationError
class InvenTreeSetting(models.Model):
"""
An InvenTreeSetting object is a key:value pair used for storing
single values (e.g. one-off settings values).
The class provides a way of retrieving the value for a particular key,
even if that key does not exist.
"""
@classmethod
def get_setting(cls, key, backup_value=None):
"""
Get the value of a particular setting.
If it does not exist, return the backup value (default = None)
"""
try:
setting = InvenTreeSetting.objects.get(key__iexact=key)
return setting.value
except InvenTreeSetting.DoesNotExist:
return backup_value
@classmethod
def set_setting(cls, key, value, user, create=True):
"""
Set the value of a particular setting.
If it does not exist, option to create it.
Args:
key: settings key
value: New value
user: User object (must be staff member to update a core setting)
create: If True, create a new setting if the specified key does not exist.
"""
if not user.is_staff:
return
try:
setting = InvenTreeSetting.objects.get(key__iexact=key)
except InvenTreeSetting.DoesNotExist:
if create:
setting = InvenTreeSetting(key=key)
else:
return
setting.value = value
setting.save()
key = models.CharField(max_length=50, blank=False, unique=True, help_text=_('Settings key (must be unique - case insensitive'))
value = models.CharField(max_length=200, blank=True, unique=False, help_text=_('Settings value'))
description = models.CharField(max_length=200, blank=True, unique=False, help_text=_('Settings description'))
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'
is unique, using a case-insensitive comparison.
"""
super().validate_unique(exclude)
try:
setting = InvenTreeSetting.objects.exclude(id=self.id).filter(key__iexact=self.key)
if setting.exists():
raise ValidationError({'key': _('Key string must be unique')})
except InvenTreeSetting.DoesNotExist:
pass
class Currency(models.Model): class Currency(models.Model):

View File

@ -0,0 +1,37 @@
{% extends "InvenTree/settings/settings.html" %}
{% block tabs %}
{% include "InvenTree/settings/tabs.html" with tab='other' %}
{% endblock %}
{% block settings %}
<h4>InvenTree Settings</h4>
<table class='table table-striped table-condensed' id='other-table'>
<thead>
<tr>
<th>Setting</th>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{% for setting in settings %}
<tr>
<td>{{ setting.key }}</td>
<td>{{ setting.value }}</td>
<td>{{ setting.description }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% block js_ready %}
{{ block.super }}
$("#other-table").bootstrapTable();
{% endblock %}

View File

@ -8,4 +8,9 @@
<li{% ifequal tab 'part' %} class='active'{% endifequal %}> <li{% ifequal tab 'part' %} class='active'{% endifequal %}>
<a href="{% url 'settings-part' %}"><span class='glyphicon glyphicon-briefcase'></span> Part</a> <a href="{% url 'settings-part' %}"><span class='glyphicon glyphicon-briefcase'></span> Part</a>
</li> </li>
{% if user.is_staff %}
<li{% ifequal tab 'other' %} class='active'{% endifequal %}>
<a href="{% url 'settings-other' %}"><span class='glyphicon glyphicon-cog'></span>Other</a>
</li>
{% endif %}
</ul> </ul>