mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-30 20:46:47 +00:00
Merge branch 'master' of github.com:inventree/InvenTree into part_main_details
This commit is contained in:
commit
20b21a2b71
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -7,5 +7,5 @@
|
|||||||
*.yml text
|
*.yml text
|
||||||
*.yaml text
|
*.yaml text
|
||||||
*.conf text
|
*.conf text
|
||||||
*.sh text
|
*.sh text eol=lf
|
||||||
*.js text
|
*.js text
|
28
.github/workflows/javascript.yaml
vendored
Normal file
28
.github/workflows/javascript.yaml
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Check javascript template files
|
||||||
|
|
||||||
|
name: Javascript Templates
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
branches-ignore:
|
||||||
|
- l10*
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
javascript:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Check Files
|
||||||
|
run: |
|
||||||
|
cd ci
|
||||||
|
python check_js_templates.py
|
||||||
|
|
@ -13,7 +13,6 @@ from crispy_forms.helper import FormHelper
|
|||||||
from crispy_forms.layout import Layout, Field
|
from crispy_forms.layout import Layout, Field
|
||||||
from crispy_forms.bootstrap import PrependedText, AppendedText, PrependedAppendedText, StrictButton, Div
|
from crispy_forms.bootstrap import PrependedText, AppendedText, PrependedAppendedText, StrictButton, Div
|
||||||
|
|
||||||
from common.models import ColorTheme
|
|
||||||
from part.models import PartCategory
|
from part.models import PartCategory
|
||||||
|
|
||||||
|
|
||||||
@ -177,39 +176,6 @@ class SetPasswordForm(HelperForm):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ColorThemeSelectForm(forms.ModelForm):
|
|
||||||
""" Form for setting color theme """
|
|
||||||
|
|
||||||
name = forms.ChoiceField(choices=(), required=False)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = ColorTheme
|
|
||||||
fields = [
|
|
||||||
'name'
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(ColorThemeSelectForm, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
# Populate color themes choices
|
|
||||||
self.fields['name'].choices = ColorTheme.get_color_themes_choices()
|
|
||||||
|
|
||||||
self.helper = FormHelper()
|
|
||||||
# Form rendering
|
|
||||||
self.helper.form_show_labels = False
|
|
||||||
self.helper.layout = Layout(
|
|
||||||
Div(
|
|
||||||
Div(Field('name'),
|
|
||||||
css_class='col-sm-6',
|
|
||||||
style='width: 200px;'),
|
|
||||||
Div(StrictButton(_('Apply Theme'), css_class='btn btn-primary', type='submit'),
|
|
||||||
css_class='col-sm-6',
|
|
||||||
style='width: auto;'),
|
|
||||||
css_class='row',
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SettingCategorySelectForm(forms.ModelForm):
|
class SettingCategorySelectForm(forms.ModelForm):
|
||||||
""" Form for setting category settings """
|
""" Form for setting category settings """
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ database setup in this file.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
@ -202,7 +203,7 @@ STATICFILES_DIRS = [
|
|||||||
|
|
||||||
# Translated Template settings
|
# Translated Template settings
|
||||||
STATICFILES_I18_PREFIX = 'i18n'
|
STATICFILES_I18_PREFIX = 'i18n'
|
||||||
STATICFILES_I18_SRC = os.path.join(BASE_DIR, 'templates', 'js')
|
STATICFILES_I18_SRC = os.path.join(BASE_DIR, 'templates', 'js', 'translated')
|
||||||
STATICFILES_I18_TRG = STATICFILES_DIRS[0] + '_' + STATICFILES_I18_PREFIX
|
STATICFILES_I18_TRG = STATICFILES_DIRS[0] + '_' + STATICFILES_I18_PREFIX
|
||||||
STATICFILES_DIRS.append(STATICFILES_I18_TRG)
|
STATICFILES_DIRS.append(STATICFILES_I18_TRG)
|
||||||
STATICFILES_I18_TRG = os.path.join(STATICFILES_I18_TRG, STATICFILES_I18_PREFIX)
|
STATICFILES_I18_TRG = os.path.join(STATICFILES_I18_TRG, STATICFILES_I18_PREFIX)
|
||||||
@ -347,10 +348,22 @@ REST_FRAMEWORK = {
|
|||||||
|
|
||||||
WSGI_APPLICATION = 'InvenTree.wsgi.application'
|
WSGI_APPLICATION = 'InvenTree.wsgi.application'
|
||||||
|
|
||||||
|
background_workers = os.environ.get('INVENTREE_BACKGROUND_WORKERS', None)
|
||||||
|
|
||||||
|
if background_workers is not None:
|
||||||
|
try:
|
||||||
|
background_workers = int(background_workers)
|
||||||
|
except ValueError:
|
||||||
|
background_workers = None
|
||||||
|
|
||||||
|
if background_workers is None:
|
||||||
|
# Sensible default?
|
||||||
|
background_workers = 4
|
||||||
|
|
||||||
# django-q configuration
|
# django-q configuration
|
||||||
Q_CLUSTER = {
|
Q_CLUSTER = {
|
||||||
'name': 'InvenTree',
|
'name': 'InvenTree',
|
||||||
'workers': 4,
|
'workers': background_workers,
|
||||||
'timeout': 90,
|
'timeout': 90,
|
||||||
'retry': 120,
|
'retry': 120,
|
||||||
'queue_limit': 50,
|
'queue_limit': 50,
|
||||||
@ -502,11 +515,24 @@ LANGUAGE_CODE = CONFIG.get('language', 'en-us')
|
|||||||
|
|
||||||
# If a new language translation is supported, it must be added here
|
# If a new language translation is supported, it must be added here
|
||||||
LANGUAGES = [
|
LANGUAGES = [
|
||||||
('en', _('English')),
|
|
||||||
('fr', _('French')),
|
|
||||||
('de', _('German')),
|
('de', _('German')),
|
||||||
|
('el', _('Greek')),
|
||||||
|
('en', _('English')),
|
||||||
|
('es', _('Spanish')),
|
||||||
|
('fr', _('French')),
|
||||||
|
('he', _('Hebrew')),
|
||||||
|
('it', _('Italian')),
|
||||||
|
('ja', _('Japanese')),
|
||||||
|
('ko', _('Korean')),
|
||||||
|
('nl', _('Dutch')),
|
||||||
|
('no', _('Norwegian')),
|
||||||
('pl', _('Polish')),
|
('pl', _('Polish')),
|
||||||
|
('ru', _('Russian')),
|
||||||
|
('sv', _('Swedish')),
|
||||||
|
('th', _('Thai')),
|
||||||
('tr', _('Turkish')),
|
('tr', _('Turkish')),
|
||||||
|
('vi', _('Vietnamese')),
|
||||||
|
('zh-cn', _('Chinese')),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Currencies available for use
|
# Currencies available for use
|
||||||
|
@ -39,7 +39,7 @@ from rest_framework.documentation import include_docs_urls
|
|||||||
from .views import auth_request
|
from .views import auth_request
|
||||||
from .views import IndexView, SearchView, DatabaseStatsView
|
from .views import IndexView, SearchView, DatabaseStatsView
|
||||||
from .views import SettingsView, EditUserView, SetPasswordView
|
from .views import SettingsView, EditUserView, SetPasswordView
|
||||||
from .views import CurrencySettingsView, CurrencyRefreshView
|
from .views import CurrencyRefreshView
|
||||||
from .views import AppearanceSelectView, SettingCategorySelectView
|
from .views import AppearanceSelectView, SettingCategorySelectView
|
||||||
from .views import DynamicJsView
|
from .views import DynamicJsView
|
||||||
|
|
||||||
@ -79,51 +79,47 @@ apipatterns = [
|
|||||||
|
|
||||||
settings_urls = [
|
settings_urls = [
|
||||||
|
|
||||||
url(r'^usersettings/', SettingsView.as_view(template_name='InvenTree/settings/user_settings.html'), name='settings-user-settings'),
|
|
||||||
url(r'^user/?', SettingsView.as_view(template_name='InvenTree/settings/user.html'), name='settings-user'),
|
|
||||||
url(r'^appearance/?', AppearanceSelectView.as_view(), name='settings-appearance'),
|
|
||||||
url(r'^i18n/?', include('django.conf.urls.i18n')),
|
url(r'^i18n/?', include('django.conf.urls.i18n')),
|
||||||
|
|
||||||
url(r'^global/', SettingsView.as_view(template_name='InvenTree/settings/global.html'), name='settings-global'),
|
url(r'^appearance/?', AppearanceSelectView.as_view(), name='settings-appearance'),
|
||||||
url(r'^report/', SettingsView.as_view(template_name='InvenTree/settings/report.html'), name='settings-report'),
|
|
||||||
url(r'^category/', SettingCategorySelectView.as_view(), name='settings-category'),
|
|
||||||
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'),
|
|
||||||
url(r'^build/', SettingsView.as_view(template_name='InvenTree/settings/build.html'), name='settings-build'),
|
|
||||||
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'^currencies/', CurrencySettingsView.as_view(), name='settings-currencies'),
|
|
||||||
url(r'^currencies-refresh/', CurrencyRefreshView.as_view(), name='settings-currencies-refresh'),
|
url(r'^currencies-refresh/', CurrencyRefreshView.as_view(), name='settings-currencies-refresh'),
|
||||||
|
|
||||||
|
url(r'^category/', SettingCategorySelectView.as_view(), name='settings-category'),
|
||||||
|
|
||||||
url(r'^(?P<pk>\d+)/edit/user', UserSettingEdit.as_view(), name='user-setting-edit'),
|
url(r'^(?P<pk>\d+)/edit/user', UserSettingEdit.as_view(), name='user-setting-edit'),
|
||||||
url(r'^(?P<pk>\d+)/edit/', SettingEdit.as_view(), name='setting-edit'),
|
url(r'^(?P<pk>\d+)/edit/', SettingEdit.as_view(), name='setting-edit'),
|
||||||
|
|
||||||
# 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/settings.html'), name='settings'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Some javascript files are served 'dynamically', allowing them to pass through the Django translation layer
|
# These javascript files are served "dynamically" - i.e. rendered on demand
|
||||||
dynamic_javascript_urls = [
|
dynamic_javascript_urls = [
|
||||||
url(r'^api.js', DynamicJsView.as_view(template_name='js/api.js'), name='api.js'),
|
url(r'^inventree.js', DynamicJsView.as_view(template_name='js/dynamic/inventree.js'), name='inventree.js'),
|
||||||
url(r'^attachment.js', DynamicJsView.as_view(template_name='js/attachment.js'), name='attachment.js'),
|
url(r'^calendar.js', DynamicJsView.as_view(template_name='js/dynamic/calendar.js'), name='calendar.js'),
|
||||||
url(r'^barcode.js', DynamicJsView.as_view(template_name='js/barcode.js'), name='barcode.js'),
|
url(r'^nav.js', DynamicJsView.as_view(template_name='js/dynamic/nav.js'), name='nav.js'),
|
||||||
url(r'^bom.js', DynamicJsView.as_view(template_name='js/bom.js'), name='bom.js'),
|
url(r'^settings.js', DynamicJsView.as_view(template_name='js/dynamic/settings.js'), name='settings.js'),
|
||||||
url(r'^build.js', DynamicJsView.as_view(template_name='js/build.js'), name='build.js'),
|
]
|
||||||
url(r'^calendar.js', DynamicJsView.as_view(template_name='js/calendar.js'), name='calendar.js'),
|
|
||||||
url(r'^company.js', DynamicJsView.as_view(template_name='js/company.js'), name='company.js'),
|
# These javascript files are pased through the Django translation layer
|
||||||
url(r'^filters.js', DynamicJsView.as_view(template_name='js/filters.js'), name='filters.js'),
|
translated_javascript_urls = [
|
||||||
url(r'^forms.js', DynamicJsView.as_view(template_name='js/forms.js'), name='forms.js'),
|
url(r'^api.js', DynamicJsView.as_view(template_name='js/translated/api.js'), name='api.js'),
|
||||||
url(r'^inventree.js', DynamicJsView.as_view(template_name='js/inventree.js'), name='inventree.js'),
|
url(r'^attachment.js', DynamicJsView.as_view(template_name='js/translated/attachment.js'), name='attachment.js'),
|
||||||
url(r'^label.js', DynamicJsView.as_view(template_name='js/label.js'), name='label.js'),
|
url(r'^barcode.js', DynamicJsView.as_view(template_name='js/translated/barcode.js'), name='barcode.js'),
|
||||||
url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/model_renderers.js'), name='model_renderers.js'),
|
url(r'^bom.js', DynamicJsView.as_view(template_name='js/translated/bom.js'), name='bom.js'),
|
||||||
url(r'^modals.js', DynamicJsView.as_view(template_name='js/modals.js'), name='modals.js'),
|
url(r'^build.js', DynamicJsView.as_view(template_name='js/translated/build.js'), name='build.js'),
|
||||||
url(r'^nav.js', DynamicJsView.as_view(template_name='js/nav.js'), name='nav.js'),
|
url(r'^company.js', DynamicJsView.as_view(template_name='js/translated/company.js'), name='company.js'),
|
||||||
url(r'^order.js', DynamicJsView.as_view(template_name='js/order.js'), name='order.js'),
|
url(r'^filters.js', DynamicJsView.as_view(template_name='js/translated/filters.js'), name='filters.js'),
|
||||||
url(r'^part.js', DynamicJsView.as_view(template_name='js/part.js'), name='part.js'),
|
url(r'^forms.js', DynamicJsView.as_view(template_name='js/translated/forms.js'), name='forms.js'),
|
||||||
url(r'^report.js', DynamicJsView.as_view(template_name='js/report.js'), name='report.js'),
|
url(r'^label.js', DynamicJsView.as_view(template_name='js/translated/label.js'), name='label.js'),
|
||||||
url(r'^stock.js', DynamicJsView.as_view(template_name='js/stock.js'), name='stock.js'),
|
url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/translated/model_renderers.js'), name='model_renderers.js'),
|
||||||
url(r'^tables.js', DynamicJsView.as_view(template_name='js/tables.js'), name='tables.js'),
|
url(r'^modals.js', DynamicJsView.as_view(template_name='js/translated/modals.js'), name='modals.js'),
|
||||||
url(r'^table_filters.js', DynamicJsView.as_view(template_name='js/table_filters.js'), name='table_filters.js'),
|
url(r'^order.js', DynamicJsView.as_view(template_name='js/translated/order.js'), name='order.js'),
|
||||||
|
url(r'^part.js', DynamicJsView.as_view(template_name='js/translated/part.js'), name='part.js'),
|
||||||
|
url(r'^report.js', DynamicJsView.as_view(template_name='js/translated/report.js'), name='report.js'),
|
||||||
|
url(r'^stock.js', DynamicJsView.as_view(template_name='js/translated/stock.js'), name='stock.js'),
|
||||||
|
url(r'^tables.js', DynamicJsView.as_view(template_name='js/translated/tables.js'), name='tables.js'),
|
||||||
|
url(r'^table_filters.js', DynamicJsView.as_view(template_name='js/translated/table_filters.js'), name='table_filters.js'),
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@ -132,7 +128,8 @@ urlpatterns = [
|
|||||||
url(r'^supplier-part/', include(supplier_part_urls)),
|
url(r'^supplier-part/', include(supplier_part_urls)),
|
||||||
|
|
||||||
# "Dynamic" javascript files which are rendered using InvenTree templating.
|
# "Dynamic" javascript files which are rendered using InvenTree templating.
|
||||||
url(r'^dynamic/', include(dynamic_javascript_urls)),
|
url(r'^js/dynamic/', include(dynamic_javascript_urls)),
|
||||||
|
url(r'^js/i18n/', include(translated_javascript_urls)),
|
||||||
|
|
||||||
url(r'^common/', include(common_urls)),
|
url(r'^common/', include(common_urls)),
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import re
|
|||||||
|
|
||||||
import common.models
|
import common.models
|
||||||
|
|
||||||
INVENTREE_SW_VERSION = "0.3.1"
|
INVENTREE_SW_VERSION = "0.5.0 pre"
|
||||||
|
|
||||||
INVENTREE_API_VERSION = 8
|
INVENTREE_API_VERSION = 8
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
|
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
|
||||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ from users.models import check_user_role, RuleSet
|
|||||||
import InvenTree.tasks
|
import InvenTree.tasks
|
||||||
|
|
||||||
from .forms import DeleteForm, EditUserForm, SetPasswordForm
|
from .forms import DeleteForm, EditUserForm, SetPasswordForm
|
||||||
from .forms import ColorThemeSelectForm, SettingCategorySelectForm
|
from .forms import SettingCategorySelectForm
|
||||||
from .helpers import str2bool
|
from .helpers import str2bool
|
||||||
|
|
||||||
from rest_framework import views
|
from rest_framework import views
|
||||||
@ -779,7 +780,7 @@ class SettingsView(TemplateView):
|
|||||||
""" View for configuring User settings
|
""" View for configuring User settings
|
||||||
"""
|
"""
|
||||||
|
|
||||||
template_name = "InvenTree/settings.html"
|
template_name = "InvenTree/settings/settings.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
|
||||||
@ -787,6 +788,20 @@ class SettingsView(TemplateView):
|
|||||||
|
|
||||||
ctx['settings'] = InvenTreeSetting.objects.all().order_by('key')
|
ctx['settings'] = InvenTreeSetting.objects.all().order_by('key')
|
||||||
|
|
||||||
|
ctx["base_currency"] = currency_code_default()
|
||||||
|
ctx["currencies"] = currency_codes
|
||||||
|
|
||||||
|
ctx["rates"] = Rate.objects.filter(backend="InvenTreeExchange")
|
||||||
|
|
||||||
|
ctx["categories"] = PartCategory.objects.all().order_by('tree_id', 'lft', 'name')
|
||||||
|
|
||||||
|
# When were the rates last updated?
|
||||||
|
try:
|
||||||
|
backend = ExchangeBackend.objects.get(name='InvenTreeExchange')
|
||||||
|
ctx["rates_updated"] = backend.last_update
|
||||||
|
except:
|
||||||
|
ctx["rates_updated"] = None
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
@ -805,43 +820,12 @@ class CurrencyRefreshView(RedirectView):
|
|||||||
# Will block for a little bit
|
# Will block for a little bit
|
||||||
InvenTree.tasks.update_exchange_rates()
|
InvenTree.tasks.update_exchange_rates()
|
||||||
|
|
||||||
return self.get(request, *args, **kwargs)
|
return redirect(reverse_lazy('settings'))
|
||||||
|
|
||||||
|
|
||||||
class CurrencySettingsView(TemplateView):
|
class AppearanceSelectView(RedirectView):
|
||||||
"""
|
|
||||||
View for configuring currency settings
|
|
||||||
"""
|
|
||||||
|
|
||||||
template_name = "InvenTree/settings/currencies.html"
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
|
|
||||||
ctx = super().get_context_data(**kwargs).copy()
|
|
||||||
|
|
||||||
ctx['settings'] = InvenTreeSetting.objects.all().order_by('key')
|
|
||||||
ctx["base_currency"] = currency_code_default()
|
|
||||||
ctx["currencies"] = currency_codes
|
|
||||||
|
|
||||||
ctx["rates"] = Rate.objects.filter(backend="InvenTreeExchange")
|
|
||||||
|
|
||||||
# When were the rates last updated?
|
|
||||||
try:
|
|
||||||
backend = ExchangeBackend.objects.get(name='InvenTreeExchange')
|
|
||||||
ctx["rates_updated"] = backend.last_update
|
|
||||||
except:
|
|
||||||
ctx["rates_updated"] = None
|
|
||||||
|
|
||||||
return ctx
|
|
||||||
|
|
||||||
|
|
||||||
class AppearanceSelectView(FormView):
|
|
||||||
""" View for selecting a color theme """
|
""" View for selecting a color theme """
|
||||||
|
|
||||||
form_class = ColorThemeSelectForm
|
|
||||||
success_url = reverse_lazy('settings-appearance')
|
|
||||||
template_name = "InvenTree/settings/appearance.html"
|
|
||||||
|
|
||||||
def get_user_theme(self):
|
def get_user_theme(self):
|
||||||
""" Get current user color theme """
|
""" Get current user color theme """
|
||||||
try:
|
try:
|
||||||
@ -851,40 +835,10 @@ class AppearanceSelectView(FormView):
|
|||||||
|
|
||||||
return user_theme
|
return user_theme
|
||||||
|
|
||||||
def get_initial(self):
|
|
||||||
""" Select current user color theme as initial choice """
|
|
||||||
|
|
||||||
initial = super(AppearanceSelectView, self).get_initial()
|
|
||||||
|
|
||||||
user_theme = self.get_user_theme()
|
|
||||||
if user_theme:
|
|
||||||
initial['name'] = user_theme.name
|
|
||||||
return initial
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
""" Check if current color theme exists, else display alert box """
|
|
||||||
|
|
||||||
context = {}
|
|
||||||
|
|
||||||
form = self.get_form()
|
|
||||||
context['form'] = form
|
|
||||||
|
|
||||||
user_theme = self.get_user_theme()
|
|
||||||
if user_theme:
|
|
||||||
# Check color theme is a valid choice
|
|
||||||
if not ColorTheme.is_valid_choice(user_theme):
|
|
||||||
user_color_theme_name = user_theme.name
|
|
||||||
if not user_color_theme_name:
|
|
||||||
user_color_theme_name = 'default'
|
|
||||||
|
|
||||||
context['invalid_color_theme'] = user_color_theme_name
|
|
||||||
|
|
||||||
return self.render_to_response(context)
|
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
""" Save user color theme selection """
|
""" Save user color theme selection """
|
||||||
|
|
||||||
form = self.get_form()
|
theme = request.POST.get('theme', None)
|
||||||
|
|
||||||
# Get current user theme
|
# Get current user theme
|
||||||
user_theme = self.get_user_theme()
|
user_theme = self.get_user_theme()
|
||||||
@ -894,20 +848,10 @@ class AppearanceSelectView(FormView):
|
|||||||
user_theme = ColorTheme()
|
user_theme = ColorTheme()
|
||||||
user_theme.user = request.user
|
user_theme.user = request.user
|
||||||
|
|
||||||
if form.is_valid():
|
user_theme.name = theme
|
||||||
theme_selected = form.cleaned_data['name']
|
user_theme.save()
|
||||||
|
|
||||||
# Set color theme to form selection
|
return redirect(reverse_lazy('settings'))
|
||||||
user_theme.name = theme_selected
|
|
||||||
user_theme.save()
|
|
||||||
|
|
||||||
return self.form_valid(form)
|
|
||||||
else:
|
|
||||||
# Set color theme to default
|
|
||||||
user_theme.name = ColorTheme.default_color_theme[0]
|
|
||||||
user_theme.save()
|
|
||||||
|
|
||||||
return self.form_invalid(form)
|
|
||||||
|
|
||||||
|
|
||||||
class SettingCategorySelectView(FormView):
|
class SettingCategorySelectView(FormView):
|
||||||
|
@ -82,7 +82,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
var prefix = '{% settings_value "BUILDORDER_REFERENCE_PREFIX" %}';
|
var prefix = global_settings.BUILDORDER_REFERENCE_PREFIX;
|
||||||
|
|
||||||
for (var idx = 0; idx < response.length; idx++) {
|
for (var idx = 0; idx < response.length; idx++) {
|
||||||
|
|
||||||
|
@ -38,6 +38,67 @@ class BaseInvenTreeSetting(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def allValues(cls, user=None):
|
||||||
|
"""
|
||||||
|
Return a dict of "all" defined global settings.
|
||||||
|
|
||||||
|
This performs a single database lookup,
|
||||||
|
and then any settings which are not *in* the database
|
||||||
|
are assigned their default values
|
||||||
|
"""
|
||||||
|
|
||||||
|
keys = set()
|
||||||
|
settings = []
|
||||||
|
|
||||||
|
results = cls.objects.all()
|
||||||
|
|
||||||
|
if user is not None:
|
||||||
|
results = results.filter(user=user)
|
||||||
|
|
||||||
|
# Query the database
|
||||||
|
for setting in results:
|
||||||
|
settings.append({
|
||||||
|
"key": setting.key.upper(),
|
||||||
|
"value": setting.value
|
||||||
|
})
|
||||||
|
|
||||||
|
keys.add(setting.key.upper())
|
||||||
|
|
||||||
|
# Specify any "default" values which are not in the database
|
||||||
|
for key in cls.GLOBAL_SETTINGS.keys():
|
||||||
|
|
||||||
|
if key.upper() not in keys:
|
||||||
|
|
||||||
|
settings.append({
|
||||||
|
"key": key.upper(),
|
||||||
|
"value": cls.get_setting_default(key)
|
||||||
|
})
|
||||||
|
|
||||||
|
# Enforce javascript formatting
|
||||||
|
for idx, setting in enumerate(settings):
|
||||||
|
|
||||||
|
key = setting['key']
|
||||||
|
value = setting['value']
|
||||||
|
|
||||||
|
validator = cls.get_setting_validator(key)
|
||||||
|
|
||||||
|
# Convert to javascript compatible booleans
|
||||||
|
if cls.validator_is_bool(validator):
|
||||||
|
value = str(value).lower()
|
||||||
|
|
||||||
|
# Numerical values remain the same
|
||||||
|
elif cls.validator_is_int(validator):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Wrap strings with quotes
|
||||||
|
else:
|
||||||
|
value = f"'{value}'"
|
||||||
|
|
||||||
|
setting["value"] = value
|
||||||
|
|
||||||
|
return settings
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_setting_name(cls, key):
|
def get_setting_name(cls, key):
|
||||||
"""
|
"""
|
||||||
@ -368,13 +429,7 @@ class BaseInvenTreeSetting(models.Model):
|
|||||||
|
|
||||||
validator = self.__class__.get_setting_validator(self.key)
|
validator = self.__class__.get_setting_validator(self.key)
|
||||||
|
|
||||||
if validator == bool:
|
return self.__class__.validator_is_bool(validator)
|
||||||
return True
|
|
||||||
|
|
||||||
if type(validator) in [list, tuple]:
|
|
||||||
for v in validator:
|
|
||||||
if v == bool:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def as_bool(self):
|
def as_bool(self):
|
||||||
"""
|
"""
|
||||||
@ -385,6 +440,19 @@ class BaseInvenTreeSetting(models.Model):
|
|||||||
|
|
||||||
return InvenTree.helpers.str2bool(self.value)
|
return InvenTree.helpers.str2bool(self.value)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validator_is_bool(cls, validator):
|
||||||
|
|
||||||
|
if validator == bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if type(validator) in [list, tuple]:
|
||||||
|
for v in validator:
|
||||||
|
if v == bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def is_int(self):
|
def is_int(self):
|
||||||
"""
|
"""
|
||||||
Check if the setting is required to be an integer value:
|
Check if the setting is required to be an integer value:
|
||||||
@ -392,6 +460,11 @@ class BaseInvenTreeSetting(models.Model):
|
|||||||
|
|
||||||
validator = self.__class__.get_setting_validator(self.key)
|
validator = self.__class__.get_setting_validator(self.key)
|
||||||
|
|
||||||
|
return self.__class__.validator_is_int(validator)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validator_is_int(cls, validator):
|
||||||
|
|
||||||
if validator == int:
|
if validator == int:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -538,13 +611,6 @@ class InvenTreeSetting(BaseInvenTreeSetting):
|
|||||||
'validator': bool
|
'validator': bool
|
||||||
},
|
},
|
||||||
|
|
||||||
'PART_RECENT_COUNT': {
|
|
||||||
'name': _('Recent Part Count'),
|
|
||||||
'description': _('Number of recent parts to display on index page'),
|
|
||||||
'default': 10,
|
|
||||||
'validator': [int, MinValueValidator(1)]
|
|
||||||
},
|
|
||||||
|
|
||||||
'PART_TEMPLATE': {
|
'PART_TEMPLATE': {
|
||||||
'name': _('Template'),
|
'name': _('Template'),
|
||||||
'description': _('Parts are templates by default'),
|
'description': _('Parts are templates by default'),
|
||||||
@ -668,13 +734,6 @@ class InvenTreeSetting(BaseInvenTreeSetting):
|
|||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
'SEARCH_PREVIEW_RESULTS': {
|
|
||||||
'name': _('Search Preview Results'),
|
|
||||||
'description': _('Number of results to show in search preview window'),
|
|
||||||
'default': 10,
|
|
||||||
'validator': [int, MinValueValidator(1)]
|
|
||||||
},
|
|
||||||
|
|
||||||
'STOCK_ENABLE_EXPIRY': {
|
'STOCK_ENABLE_EXPIRY': {
|
||||||
'name': _('Stock Expiry'),
|
'name': _('Stock Expiry'),
|
||||||
'description': _('Enable stock expiry functionality'),
|
'description': _('Enable stock expiry functionality'),
|
||||||
@ -718,13 +777,6 @@ class InvenTreeSetting(BaseInvenTreeSetting):
|
|||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
'STOCK_RECENT_COUNT': {
|
|
||||||
'name': _('Recent Stock Count'),
|
|
||||||
'description': _('Number of recent stock items to display on index page'),
|
|
||||||
'default': 10,
|
|
||||||
'validator': [int, MinValueValidator(1)]
|
|
||||||
},
|
|
||||||
|
|
||||||
'BUILDORDER_REFERENCE_PREFIX': {
|
'BUILDORDER_REFERENCE_PREFIX': {
|
||||||
'name': _('Build Order Reference Prefix'),
|
'name': _('Build Order Reference Prefix'),
|
||||||
'description': _('Prefix value for build order reference'),
|
'description': _('Prefix value for build order reference'),
|
||||||
@ -779,6 +831,13 @@ class InvenTreeUserSetting(BaseInvenTreeSetting):
|
|||||||
'default': True,
|
'default': True,
|
||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
'PART_RECENT_COUNT': {
|
||||||
|
'name': _('Recent Part Count'),
|
||||||
|
'description': _('Number of recent parts to display on index page'),
|
||||||
|
'default': 10,
|
||||||
|
'validator': [int, MinValueValidator(1)]
|
||||||
|
},
|
||||||
|
|
||||||
'HOMEPAGE_BOM_VALIDATION': {
|
'HOMEPAGE_BOM_VALIDATION': {
|
||||||
'name': _('Show unvalidated BOMs'),
|
'name': _('Show unvalidated BOMs'),
|
||||||
'description': _('Show BOMs that await validation on the homepage'),
|
'description': _('Show BOMs that await validation on the homepage'),
|
||||||
@ -791,6 +850,12 @@ class InvenTreeUserSetting(BaseInvenTreeSetting):
|
|||||||
'default': True,
|
'default': True,
|
||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
'STOCK_RECENT_COUNT': {
|
||||||
|
'name': _('Recent Stock Count'),
|
||||||
|
'description': _('Number of recent stock items to display on index page'),
|
||||||
|
'default': 10,
|
||||||
|
'validator': [int, MinValueValidator(1)]
|
||||||
|
},
|
||||||
'HOMEPAGE_STOCK_LOW': {
|
'HOMEPAGE_STOCK_LOW': {
|
||||||
'name': _('Show low stock'),
|
'name': _('Show low stock'),
|
||||||
'description': _('Show low stock items on the homepage'),
|
'description': _('Show low stock items on the homepage'),
|
||||||
@ -857,6 +922,13 @@ class InvenTreeUserSetting(BaseInvenTreeSetting):
|
|||||||
'default': True,
|
'default': True,
|
||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'SEARCH_PREVIEW_RESULTS': {
|
||||||
|
'name': _('Search Preview Results'),
|
||||||
|
'description': _('Number of results to show in search preview window'),
|
||||||
|
'default': 10,
|
||||||
|
'validator': [int, MinValueValidator(1)]
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -890,7 +962,7 @@ class InvenTreeUserSetting(BaseInvenTreeSetting):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_filters(cls, key, **kwargs):
|
def get_filters(cls, key, **kwargs):
|
||||||
return {'key__iexact': key, 'user__id__iexact': kwargs['user'].id}
|
return {'key__iexact': key, 'user__id': kwargs['user'].id}
|
||||||
|
|
||||||
|
|
||||||
class PriceBreak(models.Model):
|
class PriceBreak(models.Model):
|
||||||
|
@ -50,6 +50,23 @@ class SettingEdit(AjaxUpdateView):
|
|||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
"""
|
||||||
|
Custom data to return to the client after POST success
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
setting = self.get_object()
|
||||||
|
|
||||||
|
data['pk'] = setting.pk
|
||||||
|
data['key'] = setting.key
|
||||||
|
data['value'] = setting.value
|
||||||
|
data['is_bool'] = setting.is_bool()
|
||||||
|
data['is_int'] = setting.is_int()
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
def get_form(self):
|
def get_form(self):
|
||||||
"""
|
"""
|
||||||
Override default get_form behaviour
|
Override default get_form behaviour
|
||||||
|
@ -6,6 +6,8 @@ Provides a JSON API for the Company app
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django_filters.rest_framework import DjangoFilterBackend
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
|
from django_filters import rest_framework as rest_filters
|
||||||
|
|
||||||
from rest_framework import filters
|
from rest_framework import filters
|
||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
|
|
||||||
@ -84,6 +86,23 @@ class CompanyDetail(generics.RetrieveUpdateDestroyAPIView):
|
|||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
class ManufacturerPartFilter(rest_filters.FilterSet):
|
||||||
|
"""
|
||||||
|
Custom API filters for the ManufacturerPart list endpoint.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = ManufacturerPart
|
||||||
|
fields = [
|
||||||
|
'manufacturer',
|
||||||
|
'MPN',
|
||||||
|
'part',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Filter by 'active' status of linked part
|
||||||
|
active = rest_filters.BooleanFilter(field_name='part__active')
|
||||||
|
|
||||||
|
|
||||||
class ManufacturerPartList(generics.ListCreateAPIView):
|
class ManufacturerPartList(generics.ListCreateAPIView):
|
||||||
""" API endpoint for list view of ManufacturerPart object
|
""" API endpoint for list view of ManufacturerPart object
|
||||||
|
|
||||||
@ -98,6 +117,7 @@ class ManufacturerPartList(generics.ListCreateAPIView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
serializer_class = ManufacturerPartSerializer
|
serializer_class = ManufacturerPartSerializer
|
||||||
|
filterset_class = ManufacturerPartFilter
|
||||||
|
|
||||||
def get_serializer(self, *args, **kwargs):
|
def get_serializer(self, *args, **kwargs):
|
||||||
|
|
||||||
@ -115,45 +135,12 @@ class ManufacturerPartList(generics.ListCreateAPIView):
|
|||||||
|
|
||||||
return self.serializer_class(*args, **kwargs)
|
return self.serializer_class(*args, **kwargs)
|
||||||
|
|
||||||
def filter_queryset(self, queryset):
|
|
||||||
"""
|
|
||||||
Custom filtering for the queryset.
|
|
||||||
"""
|
|
||||||
|
|
||||||
queryset = super().filter_queryset(queryset)
|
|
||||||
|
|
||||||
params = self.request.query_params
|
|
||||||
|
|
||||||
# Filter by manufacturer
|
|
||||||
manufacturer = params.get('manufacturer', None)
|
|
||||||
|
|
||||||
if manufacturer is not None:
|
|
||||||
queryset = queryset.filter(manufacturer=manufacturer)
|
|
||||||
|
|
||||||
# Filter by parent part?
|
|
||||||
part = params.get('part', None)
|
|
||||||
|
|
||||||
if part is not None:
|
|
||||||
queryset = queryset.filter(part=part)
|
|
||||||
|
|
||||||
# Filter by 'active' status of the part?
|
|
||||||
active = params.get('active', None)
|
|
||||||
|
|
||||||
if active is not None:
|
|
||||||
active = str2bool(active)
|
|
||||||
queryset = queryset.filter(part__active=active)
|
|
||||||
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
filter_backends = [
|
filter_backends = [
|
||||||
DjangoFilterBackend,
|
DjangoFilterBackend,
|
||||||
filters.SearchFilter,
|
filters.SearchFilter,
|
||||||
filters.OrderingFilter,
|
filters.OrderingFilter,
|
||||||
]
|
]
|
||||||
|
|
||||||
filter_fields = [
|
|
||||||
]
|
|
||||||
|
|
||||||
search_fields = [
|
search_fields = [
|
||||||
'manufacturer__name',
|
'manufacturer__name',
|
||||||
'description',
|
'description',
|
||||||
|
@ -198,17 +198,16 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
{% settings_value "INVENTREE_DOWNLOAD_FROM_URL" as allow_download %}
|
if (global_settings.INVENTREE_DOWNLOAD_FROM_URL) {
|
||||||
|
|
||||||
{% if allow_download %}
|
$('#company-image-url').click(function() {
|
||||||
$('#company-image-url').click(function() {
|
launchModalForm(
|
||||||
launchModalForm(
|
'{% url "company-image-download" company.id %}',
|
||||||
'{% url "company-image-download" company.id %}',
|
{
|
||||||
{
|
reload: true,
|
||||||
reload: true,
|
}
|
||||||
}
|
)
|
||||||
)
|
});
|
||||||
});
|
}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -371,7 +371,7 @@
|
|||||||
requests.push(inventreeDelete(url));
|
requests.push(inventreeDelete(url));
|
||||||
});
|
});
|
||||||
|
|
||||||
$.when.apply($, requests).then(function() {
|
$.when.apply($, requests).done(function() {
|
||||||
$('#supplier-part-table').bootstrapTable('refresh');
|
$('#supplier-part-table').bootstrapTable('refresh');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -207,7 +207,7 @@ $("#supplier-part-delete").click(function() {
|
|||||||
requests.push(inventreeDelete(url));
|
requests.push(inventreeDelete(url));
|
||||||
});
|
});
|
||||||
|
|
||||||
$.when.apply($, requests).then(function() {
|
$.when.apply($, requests).done(function() {
|
||||||
reloadSupplierPartTable();
|
reloadSupplierPartTable();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -247,7 +247,7 @@ $("#multi-parameter-delete").click(function() {
|
|||||||
requests.push(inventreeDelete(url));
|
requests.push(inventreeDelete(url));
|
||||||
});
|
});
|
||||||
|
|
||||||
$.when.apply($, requests).then(function() {
|
$.when.apply($, requests).done(function() {
|
||||||
$('#parameter-table').bootstrapTable('refresh');
|
$('#parameter-table').bootstrapTable('refresh');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
7946
InvenTree/locale/el/LC_MESSAGES/django.po
Normal file
7946
InvenTree/locale/el/LC_MESSAGES/django.po
Normal file
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
File diff suppressed because it is too large
Load Diff
7946
InvenTree/locale/he/LC_MESSAGES/django.po
Normal file
7946
InvenTree/locale/he/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
7946
InvenTree/locale/id/LC_MESSAGES/django.po
Normal file
7946
InvenTree/locale/id/LC_MESSAGES/django.po
Normal file
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
7946
InvenTree/locale/ko/LC_MESSAGES/django.po
Normal file
7946
InvenTree/locale/ko/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
7946
InvenTree/locale/nl/LC_MESSAGES/django.po
Normal file
7946
InvenTree/locale/nl/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
7946
InvenTree/locale/no/LC_MESSAGES/django.po
Normal file
7946
InvenTree/locale/no/LC_MESSAGES/django.po
Normal file
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
7946
InvenTree/locale/sv/LC_MESSAGES/django.po
Normal file
7946
InvenTree/locale/sv/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
7946
InvenTree/locale/th/LC_MESSAGES/django.po
Normal file
7946
InvenTree/locale/th/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
7946
InvenTree/locale/vi/LC_MESSAGES/django.po
Normal file
7946
InvenTree/locale/vi/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -164,7 +164,7 @@ $("#edit-order").click(function() {
|
|||||||
constructForm('{% url "api-po-detail" order.pk %}', {
|
constructForm('{% url "api-po-detail" order.pk %}', {
|
||||||
fields: {
|
fields: {
|
||||||
reference: {
|
reference: {
|
||||||
prefix: "{% settings_value 'PURCHASEORDER_REFERENCE_PREFIX' %}",
|
prefix: global_settings.PURCHASEORDER_REFERENCE_PREFIX,
|
||||||
},
|
},
|
||||||
{% if order.lines.count == 0 and order.status == PurchaseOrderStatus.PENDING %}
|
{% if order.lines.count == 0 and order.status == PurchaseOrderStatus.PENDING %}
|
||||||
supplier: {
|
supplier: {
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
var prefix = '{% settings_value "PURCHASEORDER_REFERENCE_PREFIX" %}';
|
var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
|
||||||
|
|
||||||
for (var idx = 0; idx < response.length; idx++) {
|
for (var idx = 0; idx < response.length; idx++) {
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ $("#edit-order").click(function() {
|
|||||||
constructForm('{% url "api-so-detail" order.pk %}', {
|
constructForm('{% url "api-so-detail" order.pk %}', {
|
||||||
fields: {
|
fields: {
|
||||||
reference: {
|
reference: {
|
||||||
prefix: "{% settings_value 'SALESORDER_REFERENCE_PREFIX' %}",
|
prefix: global_settings.SALESORDER_REFERENCE_PREFIX,
|
||||||
},
|
},
|
||||||
{% if order.lines.count == 0 and order.status == SalesOrderStatus.PENDING %}
|
{% if order.lines.count == 0 and order.status == SalesOrderStatus.PENDING %}
|
||||||
customer: {
|
customer: {
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
{
|
{
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
|
|
||||||
var prefix = '{% settings_value "SALESORDER_REFERENCE_PREFIX" %}';
|
var prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
|
||||||
|
|
||||||
for (var idx = 0; idx < response.length; idx++) {
|
for (var idx = 0; idx < response.length; idx++) {
|
||||||
var order = response[idx];
|
var order = response[idx];
|
||||||
|
@ -159,7 +159,7 @@ class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
|
|||||||
queryset = PartCategory.objects.all()
|
queryset = PartCategory.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class CategoryParameters(generics.ListAPIView):
|
class CategoryParameterList(generics.ListAPIView):
|
||||||
""" API endpoint for accessing a list of PartCategoryParameterTemplate objects.
|
""" API endpoint for accessing a list of PartCategoryParameterTemplate objects.
|
||||||
|
|
||||||
- GET: Return a list of PartCategoryParameterTemplate objects
|
- GET: Return a list of PartCategoryParameterTemplate objects
|
||||||
@ -176,30 +176,27 @@ class CategoryParameters(generics.ListAPIView):
|
|||||||
- Allow traversing all parent categories
|
- Allow traversing all parent categories
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
|
||||||
cat_id = int(self.kwargs.get('pk', None))
|
|
||||||
except TypeError:
|
|
||||||
cat_id = None
|
|
||||||
fetch_parent = str2bool(self.request.query_params.get('fetch_parent', 'true'))
|
|
||||||
|
|
||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset()
|
||||||
|
|
||||||
if isinstance(cat_id, int):
|
params = self.request.query_params
|
||||||
|
|
||||||
|
category = params.get('category', None)
|
||||||
|
|
||||||
|
if category is not None:
|
||||||
try:
|
try:
|
||||||
category = PartCategory.objects.get(pk=cat_id)
|
|
||||||
except PartCategory.DoesNotExist:
|
category = PartCategory.objects.get(pk=category)
|
||||||
# Return empty queryset
|
|
||||||
return PartCategoryParameterTemplate.objects.none()
|
|
||||||
|
|
||||||
category_list = [cat_id]
|
fetch_parent = str2bool(params.get('fetch_parent', True))
|
||||||
|
|
||||||
if fetch_parent:
|
if fetch_parent:
|
||||||
parent_categories = category.get_ancestors()
|
parents = category.get_ancestors(include_self=True)
|
||||||
for parent in parent_categories:
|
queryset = queryset.filter(category__in=[cat.pk for cat in parents])
|
||||||
category_list.append(parent.pk)
|
else:
|
||||||
|
queryset = queryset.filter(category=category)
|
||||||
|
|
||||||
queryset = queryset.filter(category__in=category_list)
|
except (ValueError, PartCategory.DoesNotExist):
|
||||||
|
pass
|
||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
@ -995,8 +992,9 @@ class BomList(generics.ListCreateAPIView):
|
|||||||
|
|
||||||
# Get values for currencies
|
# Get values for currencies
|
||||||
currencies = queryset.annotate(
|
currencies = queryset.annotate(
|
||||||
|
purchase_price=F('sub_part__stock_items__purchase_price'),
|
||||||
purchase_price_currency=F('sub_part__stock_items__purchase_price_currency'),
|
purchase_price_currency=F('sub_part__stock_items__purchase_price_currency'),
|
||||||
).values('pk', 'sub_part', 'purchase_price_currency')
|
).values('pk', 'sub_part', 'purchase_price', 'purchase_price_currency')
|
||||||
|
|
||||||
def convert_price(price, currency, decimal_places=4):
|
def convert_price(price, currency, decimal_places=4):
|
||||||
""" Convert price field, returns Money field """
|
""" Convert price field, returns Money field """
|
||||||
@ -1032,7 +1030,7 @@ class BomList(generics.ListCreateAPIView):
|
|||||||
# Find associated currency (select first found)
|
# Find associated currency (select first found)
|
||||||
purchase_price_currency = None
|
purchase_price_currency = None
|
||||||
for currency_item in currencies:
|
for currency_item in currencies:
|
||||||
if currency_item['pk'] == bom_item.pk and currency_item['sub_part'] == bom_item.sub_part.pk:
|
if currency_item['pk'] == bom_item.pk and currency_item['sub_part'] == bom_item.sub_part.pk and currency_item['purchase_price']:
|
||||||
purchase_price_currency = currency_item['purchase_price_currency']
|
purchase_price_currency = currency_item['purchase_price_currency']
|
||||||
break
|
break
|
||||||
# Convert prices
|
# Convert prices
|
||||||
@ -1093,7 +1091,8 @@ part_api_urls = [
|
|||||||
|
|
||||||
# Base URL for PartCategory API endpoints
|
# Base URL for PartCategory API endpoints
|
||||||
url(r'^category/', include([
|
url(r'^category/', include([
|
||||||
url(r'^(?P<pk>\d+)/parameters/?', CategoryParameters.as_view(), name='api-part-category-parameters'),
|
url(r'^parameters/', CategoryParameterList.as_view(), name='api-part-category-parameter-list'),
|
||||||
|
|
||||||
url(r'^(?P<pk>\d+)/?', CategoryDetail.as_view(), name='api-part-category-detail'),
|
url(r'^(?P<pk>\d+)/?', CategoryDetail.as_view(), name='api-part-category-detail'),
|
||||||
url(r'^$', CategoryList.as_view(), name='api-part-category-list'),
|
url(r'^$', CategoryList.as_view(), name='api-part-category-list'),
|
||||||
])),
|
])),
|
||||||
|
@ -526,11 +526,14 @@ class CategoryParameterTemplateSerializer(InvenTreeModelSerializer):
|
|||||||
parameter_template = PartParameterTemplateSerializer(many=False,
|
parameter_template = PartParameterTemplateSerializer(many=False,
|
||||||
read_only=True)
|
read_only=True)
|
||||||
|
|
||||||
|
category_detail = CategorySerializer(source='category', many=False, read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PartCategoryParameterTemplate
|
model = PartCategoryParameterTemplate
|
||||||
fields = [
|
fields = [
|
||||||
'pk',
|
'pk',
|
||||||
'category',
|
'category',
|
||||||
|
'category_detail',
|
||||||
'parameter_template',
|
'parameter_template',
|
||||||
'default_value',
|
'default_value',
|
||||||
]
|
]
|
||||||
|
@ -416,7 +416,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Wait for *all* the requests to complete
|
// Wait for *all* the requests to complete
|
||||||
$.when.apply($, requests).then(function() {
|
$.when.apply($, requests).done(function() {
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -832,7 +832,7 @@
|
|||||||
requests.push(inventreeDelete(url));
|
requests.push(inventreeDelete(url));
|
||||||
});
|
});
|
||||||
|
|
||||||
$.when.apply($, requests).then(function() {
|
$.when.apply($, requests).done(function() {
|
||||||
reloadSupplierPartTable();
|
reloadSupplierPartTable();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -422,17 +422,16 @@
|
|||||||
|
|
||||||
{% if roles.part.change %}
|
{% if roles.part.change %}
|
||||||
|
|
||||||
{% settings_value "INVENTREE_DOWNLOAD_FROM_URL" as allow_download %}
|
if (global_settings.INVENTREE_DOWNLOAD_FROM_URL) {
|
||||||
{% if allow_download %}
|
$("#part-image-url").click(function() {
|
||||||
$("#part-image-url").click(function() {
|
launchModalForm(
|
||||||
launchModalForm(
|
'{% url "part-image-download" part.id %}',
|
||||||
'{% url "part-image-download" part.id %}',
|
{
|
||||||
{
|
reload: true,
|
||||||
reload: true,
|
}
|
||||||
}
|
);
|
||||||
);
|
});
|
||||||
});
|
}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
$("#part-image-select").click(function() {
|
$("#part-image-select").click(function() {
|
||||||
launchModalForm("{% url 'part-image-select' part.id %}",
|
launchModalForm("{% url 'part-image-select' part.id %}",
|
||||||
|
@ -207,6 +207,24 @@ def settings_value(key, *args, **kwargs):
|
|||||||
return InvenTreeSetting.get_setting(key)
|
return InvenTreeSetting.get_setting(key)
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def user_settings(user, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Return all USER settings as a key:value dict
|
||||||
|
"""
|
||||||
|
|
||||||
|
return InvenTreeUserSetting.allValues(user=user)
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def global_settings(*args, **kwargs):
|
||||||
|
"""
|
||||||
|
Return all GLOBAL InvenTree settings as a key:value dict
|
||||||
|
"""
|
||||||
|
|
||||||
|
return InvenTreeSetting.allValues()
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def get_color_theme_css(username):
|
def get_color_theme_css(username):
|
||||||
try:
|
try:
|
||||||
@ -226,6 +244,23 @@ def get_color_theme_css(username):
|
|||||||
return inventree_css_static_url
|
return inventree_css_static_url
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def get_available_themes(*args, **kwargs):
|
||||||
|
"""
|
||||||
|
Return the available theme choices
|
||||||
|
"""
|
||||||
|
|
||||||
|
themes = []
|
||||||
|
|
||||||
|
for key, name in ColorTheme.get_color_themes_choices():
|
||||||
|
themes.append({
|
||||||
|
'key': key,
|
||||||
|
'name': name
|
||||||
|
})
|
||||||
|
|
||||||
|
return themes
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def keyvalue(dict, key):
|
def keyvalue(dict, key):
|
||||||
"""
|
"""
|
||||||
|
@ -11,6 +11,7 @@ from django.views.generic import DetailView, ListView, UpdateView
|
|||||||
from django.forms.models import model_to_dict
|
from django.forms.models import model_to_dict
|
||||||
from django.forms import HiddenInput
|
from django.forms import HiddenInput
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
|
|
||||||
@ -109,6 +110,22 @@ class StockItemDetail(InvenTreeRoleMixin, DetailView):
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
""" check if item exists else return to stock index """
|
||||||
|
|
||||||
|
stock_pk = kwargs.get('pk', None)
|
||||||
|
|
||||||
|
if stock_pk:
|
||||||
|
try:
|
||||||
|
stock_item = StockItem.objects.get(pk=stock_pk)
|
||||||
|
except StockItem.DoesNotExist:
|
||||||
|
stock_item = None
|
||||||
|
|
||||||
|
if not stock_item:
|
||||||
|
return HttpResponseRedirect(reverse('stock-index'))
|
||||||
|
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class StockItemNotes(InvenTreeRoleMixin, UpdateView):
|
class StockItemNotes(InvenTreeRoleMixin, UpdateView):
|
||||||
""" View for editing the 'notes' field of a StockItem object """
|
""" View for editing the 'notes' field of a StockItem object """
|
||||||
|
@ -116,7 +116,7 @@ addHeaderAction('latest-parts', '{% trans "Latest Parts" %}', 'fa-newspaper');
|
|||||||
loadSimplePartTable("#table-latest-parts", "{% url 'api-part-list' %}", {
|
loadSimplePartTable("#table-latest-parts", "{% url 'api-part-list' %}", {
|
||||||
params: {
|
params: {
|
||||||
ordering: "-creation_date",
|
ordering: "-creation_date",
|
||||||
max_results: {% settings_value "PART_RECENT_COUNT" %},
|
max_results: {% settings_value "PART_RECENT_COUNT" user=request.user %},
|
||||||
},
|
},
|
||||||
name: 'latest_parts',
|
name: 'latest_parts',
|
||||||
});
|
});
|
||||||
@ -155,7 +155,7 @@ loadStockTable($('#table-recently-updated-stock'), {
|
|||||||
params: {
|
params: {
|
||||||
part_detail: true,
|
part_detail: true,
|
||||||
ordering: "-updated",
|
ordering: "-updated",
|
||||||
max_results: {% settings_value "STOCK_RECENT_COUNT" %},
|
max_results: {% settings_value "STOCK_RECENT_COUNT" user=request.user %},
|
||||||
},
|
},
|
||||||
name: 'recently-updated-stock',
|
name: 'recently-updated-stock',
|
||||||
grouping: false,
|
grouping: false,
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
{% extends "InvenTree/settings/settings.html" %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load inventree_extras %}
|
|
||||||
|
|
||||||
{% block tabs %}
|
|
||||||
{% include "InvenTree/settings/tabs.html" with tab='theme' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block subtitle %}
|
|
||||||
{% trans "Theme Settings" %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block settings %}
|
|
||||||
|
|
||||||
<div class='row'>
|
|
||||||
<div class='col-sm-6'>
|
|
||||||
<h4>{% trans "Color Themes" %}</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form action="{% url 'settings-appearance' %}" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% load crispy_forms_tags %}
|
|
||||||
{% crispy form %}
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{% if invalid_color_theme %}
|
|
||||||
<div class="alert alert-danger alert-block" role="alert" style="display: inline-block;">
|
|
||||||
{% blocktrans %}
|
|
||||||
The CSS sheet "{{invalid_color_theme}}.css" for the currently selected color theme was not found.<br>
|
|
||||||
Please select another color theme :)
|
|
||||||
{% endblocktrans %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
<div class='row'>
|
|
||||||
<div class='col-sm-6'>
|
|
||||||
<h4>{% trans "Language" %}</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
|
|
||||||
<input name="next" type="hidden" value="{% url 'settings-appearance' %}">
|
|
||||||
<div class="col-sm-6" style="width: 200px;"><div id="div_id_name" class="form-group"><div class="controls ">
|
|
||||||
<select name="language" class="select form-control">
|
|
||||||
{% get_current_language as LANGUAGE_CODE %}
|
|
||||||
{% get_available_languages as LANGUAGES %}
|
|
||||||
{% get_language_info_list for LANGUAGES as languages %}
|
|
||||||
{% for language in languages %}
|
|
||||||
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
|
|
||||||
{{ language.name_local }} ({{ language.code }})
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div></div></div>
|
|
||||||
<div class="col-sm-6" style="width: auto;">
|
|
||||||
<input type="submit" value="{% trans 'Set Language' %}" class="btn btn btn-primary">
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
20
InvenTree/templates/InvenTree/settings/barcode.html
Normal file
20
InvenTree/templates/InvenTree/settings/barcode.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{% extends "panel.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
|
||||||
|
{% block label %}barcodes{% endblock %}
|
||||||
|
|
||||||
|
{% block heading %}
|
||||||
|
{% trans "Barcode Settings" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<table class='table table-striped table-condensed'>
|
||||||
|
{% include "InvenTree/settings/header.html" %}
|
||||||
|
<tbody>
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="BARCODE_ENABLE" icon="fa-qrcode" %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -1,16 +1,14 @@
|
|||||||
{% extends "InvenTree/settings/settings.html" %}
|
{% extends "panel.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load inventree_extras %}
|
{% load inventree_extras %}
|
||||||
|
|
||||||
{% block tabs %}
|
{% block label %}build-order{% endblock %}
|
||||||
{% include "InvenTree/settings/tabs.html" with tab='build' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block subtitle %}
|
{% block heading %}
|
||||||
{% trans "Build Order Settings" %}
|
{% trans "Build Order Settings" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block settings %}
|
{% block content %}
|
||||||
|
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
{% include "InvenTree/settings/header.html" %}
|
{% include "InvenTree/settings/header.html" %}
|
||||||
|
@ -1,114 +1,33 @@
|
|||||||
{% extends "InvenTree/settings/settings.html" %}
|
{% extends "panel.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block tabs %}
|
{% block label %}category{% endblock %}
|
||||||
{% include "InvenTree/settings/tabs.html" with tab='category' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block subtitle %}
|
{% block heading %}
|
||||||
{% trans "Category Settings" %}
|
{% trans "Category Settings" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block settings %}
|
{% block content %}
|
||||||
|
|
||||||
<form action="{% url 'settings-category' %}" method="post">
|
<div class='row'>
|
||||||
{% csrf_token %}
|
<form action=''>
|
||||||
{% load crispy_forms_tags %}
|
<div class='col-sm-6' style='width: 250px'>
|
||||||
<div id="category-select">
|
<div class='form-group'><div class='controls'>
|
||||||
{% crispy form %}
|
<select name='category' id='category-select'>
|
||||||
</div>
|
<!-- Will be filled by API -->
|
||||||
</form>
|
</select>
|
||||||
|
</div></div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if category %}
|
<div id='cat-param-buttons'>
|
||||||
<hr>
|
<button class='btn btn-success' id='new-cat-param' disabled=''>
|
||||||
|
<div class='fas fa-plus-circle'></div> {% trans "New Parameter" %}
|
||||||
<h4>{% trans "Category Parameter Templates" %}</h4>
|
|
||||||
|
|
||||||
<div id='param-buttons'>
|
|
||||||
<button class='btn btn-success' id='new-param'>
|
|
||||||
<span class='fas fa-plus-circle'></span> {% trans "New Parameter" %}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class='table table-striped table-condensed' id='param-table' data-toolbar='#param-buttons'>
|
<table class='table table-striped table-condensed' id='cat-param-table' data-toolbar='#cat-param-buttons'>
|
||||||
</table>
|
</table>
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js_ready %}
|
|
||||||
{{ block.super }}
|
|
||||||
|
|
||||||
{# Convert dropdown to select2 format #}
|
|
||||||
$(document).ready(function() {
|
|
||||||
attachSelect('#category-select');
|
|
||||||
});
|
|
||||||
|
|
||||||
{% if category %}
|
|
||||||
$("#param-table").inventreeTable({
|
|
||||||
url: "{% url 'api-part-category-parameters' pk=category.pk %}",
|
|
||||||
queryParams: {
|
|
||||||
ordering: 'name',
|
|
||||||
},
|
|
||||||
formatNoMatches: function() { return '{% trans "No category parameter templates found" %}'; },
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
field: 'pk',
|
|
||||||
title: 'ID',
|
|
||||||
visible: false,
|
|
||||||
switchable: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'parameter_template.name',
|
|
||||||
title: '{% trans "Parameter Template" %}',
|
|
||||||
sortable: 'true',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'default_value',
|
|
||||||
title: '{% trans "Default Value" %}',
|
|
||||||
sortable: 'true',
|
|
||||||
formatter: function(value, row, index, field) {
|
|
||||||
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 = value
|
|
||||||
html += "<div class='btn-group float-right' role='group'>" + bEdit + bDel + "</div>";
|
|
||||||
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#new-param").click(function() {
|
|
||||||
launchModalForm("{% url 'category-param-template-create' category.pk %}", {
|
|
||||||
success: function() {
|
|
||||||
$("#param-table").bootstrapTable('refresh');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#param-table").on('click', '.template-edit', function() {
|
|
||||||
var button = $(this);
|
|
||||||
|
|
||||||
var url = "/part/category/{{ category.pk }}/parameters/" + button.attr('pk') + "/edit/";
|
|
||||||
|
|
||||||
launchModalForm(url, {
|
|
||||||
success: function() {
|
|
||||||
$("#param-table").bootstrapTable('refresh');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#param-table").on('click', '.template-delete', function() {
|
|
||||||
var button = $(this);
|
|
||||||
|
|
||||||
var url = "/part/category/{{ category.pk }}/parameters/" + button.attr('pk') + "/delete/";
|
|
||||||
|
|
||||||
launchModalForm(url, {
|
|
||||||
success: function() {
|
|
||||||
$("#param-table").bootstrapTable('refresh');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
{% extends "InvenTree/settings/settings.html" %}
|
{% extends "panel.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load inventree_extras %}
|
{% load inventree_extras %}
|
||||||
|
|
||||||
{% block tabs %}
|
{% block label %}currencies{% endblock %}
|
||||||
{% include "InvenTree/settings/tabs.html" with tab='currencies' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block subtitle %}
|
{% block heading %}
|
||||||
{% trans "Currency Settings" %}
|
{% trans "Currency Settings" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block settings %}
|
{% block content %}
|
||||||
|
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
{% include "InvenTree/settings/header.html" %}
|
{% include "InvenTree/settings/header.html" %}
|
||||||
@ -55,8 +53,4 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js_ready %}
|
|
||||||
{{ block.super }}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -1,16 +1,15 @@
|
|||||||
{% extends "InvenTree/settings/settings.html" %}
|
{% extends "panel.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load inventree_extras %}
|
{% load inventree_extras %}
|
||||||
|
|
||||||
{% block tabs %}
|
{% block label %}server{% endblock %}
|
||||||
{% include "InvenTree/settings/tabs.html" with tab='global' %}
|
|
||||||
|
|
||||||
|
{% block heading %}
|
||||||
|
{% trans "Server Settings" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block subtitle %}
|
{% block content %}
|
||||||
{% trans "Global InvenTree Settings" %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block settings %}
|
|
||||||
|
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
{% include "InvenTree/settings/header.html" %}
|
{% include "InvenTree/settings/header.html" %}
|
||||||
@ -23,19 +22,4 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h4>{% trans "Barcode Settings" %}</h4>
|
|
||||||
<table class='table table-striped table-condensed'>
|
|
||||||
{% include "InvenTree/settings/header.html" %}
|
|
||||||
<tbody>
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="BARCODE_ENABLE" icon="fa-qrcode" %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h4>{% trans "Search Settings" %}</h4>
|
|
||||||
<table class='table table-striped table-condensed'>
|
|
||||||
<tbody>
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_RESULTS" icon="fa-search" %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
109
InvenTree/templates/InvenTree/settings/navbar.html
Normal file
109
InvenTree/templates/InvenTree/settings/navbar.html
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<ul class='list-group'>
|
||||||
|
|
||||||
|
<li class='list-group-item'>
|
||||||
|
<a href='#' id='item-menu-toggle'>
|
||||||
|
<span class='menu-tab-icon fas fa-expand-arrows-alt'></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item'>
|
||||||
|
<b>{% trans "User Settings" %}</b>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Account" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-account'>
|
||||||
|
<span class='fas fa-user'></span> {% trans "Account" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Home Page" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-user-home'>
|
||||||
|
<span class='fas fa-home'></span> {% trans "Home Page" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Search" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-user-search'>
|
||||||
|
<span class='fas fa-search'></span> {% trans "Search" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<li class='list-group-item' title='{% trans "Settings" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-user-settings'>
|
||||||
|
<span class='fas fa-cog'></span> {% trans "Settings" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
-->
|
||||||
|
|
||||||
|
{% if user.is_staff %}
|
||||||
|
|
||||||
|
<li class='list-group-item'>
|
||||||
|
<b>{% trans "InvenTree Settings" %}</b>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Server" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-server'>
|
||||||
|
<span class='fas fa-server'></span> {% trans "Server" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Barcodes" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-barcodes'>
|
||||||
|
<span class='fas fa-qrcode'></span> {% trans "Barcodes" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Currencies" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-currencies'>
|
||||||
|
<span class='fas fa-dollar-sign'></span> {% trans "Currencies" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Reporting" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-reporting'>
|
||||||
|
<span class='fas fa-file-pdf'></span> {% trans "Reporting" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Parts" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-parts'>
|
||||||
|
<span class='fas fa-shapes'></span> {% trans "Parts" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Categories" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-category'>
|
||||||
|
<span class='fas fa-shapes'></span> {% trans "Categories" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Stock" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-stock'>
|
||||||
|
<span class='fas fa-boxes'></span> {% trans "Stock" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Build Orders" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-build-order'>
|
||||||
|
<span class='fas fa-tools'></span> {% trans "Build Orders" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Purchase Orders" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-purchase-order'>
|
||||||
|
<span class='fas fa-shopping-cart'></span> {% trans "Purchase Orders" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='list-group-item' title='{% trans "Sales Orders" %}'>
|
||||||
|
<a href='#' class='nav-toggle' id='select-sales-order'>
|
||||||
|
<span class='fas fa-truck'></span> {% trans "Sales Orders" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</ul>
|
@ -1,15 +1,13 @@
|
|||||||
{% extends "InvenTree/settings/settings.html" %}
|
{% extends "panel.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block tabs %}
|
{% block label %}parts{% endblock %}
|
||||||
{% include "InvenTree/settings/tabs.html" with tab='part' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block subtitle %}
|
{% block heading %}
|
||||||
{% trans "Part Settings" %}
|
{% trans "Part Settings" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block settings %}
|
{% block content %}
|
||||||
|
|
||||||
<h4>{% trans "Part Options" %}</h4>
|
<h4>{% trans "Part Options" %}</h4>
|
||||||
|
|
||||||
@ -22,7 +20,6 @@
|
|||||||
{% include "InvenTree/settings/setting.html" with key="PART_SHOW_QUANTITY_IN_FORMS" icon="fa-hashtag" %}
|
{% include "InvenTree/settings/setting.html" with key="PART_SHOW_QUANTITY_IN_FORMS" icon="fa-hashtag" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="PART_SHOW_PRICE_IN_FORMS" icon="fa-dollar-sign" %}
|
{% include "InvenTree/settings/setting.html" with key="PART_SHOW_PRICE_IN_FORMS" icon="fa-dollar-sign" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="PART_SHOW_RELATED" icon="fa-random" %}
|
{% include "InvenTree/settings/setting.html" with key="PART_SHOW_RELATED" icon="fa-random" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="PART_RECENT_COUNT" icon="fa-clock" %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="PART_CREATE_INITIAL" icon="fa-boxes" %}
|
{% include "InvenTree/settings/setting.html" with key="PART_CREATE_INITIAL" icon="fa-boxes" %}
|
||||||
<tr><td colspan='5'></td></tr>
|
<tr><td colspan='5'></td></tr>
|
||||||
{% include "InvenTree/settings/setting.html" with key="PART_TEMPLATE" icon="fa-clone" %}
|
{% include "InvenTree/settings/setting.html" with key="PART_TEMPLATE" icon="fa-clone" %}
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
{% extends "InvenTree/settings/settings.html" %}
|
{% extends "panel.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block tabs %}
|
{% block label %}purchase-order{% endblock %}
|
||||||
{% include "InvenTree/settings/tabs.html" with tab='po' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block subtitle %}
|
{% block heading %}
|
||||||
{% trans "Purchase Order Settings" %}
|
{% trans "Purchase Order Settings" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block settings %}
|
{% block content %}
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
{% include "InvenTree/settings/header.html" %}
|
{% include "InvenTree/settings/header.html" %}
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
{% extends "InvenTree/settings/settings.html" %}
|
{% extends "panel.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load inventree_extras %}
|
{% load inventree_extras %}
|
||||||
|
|
||||||
{% block tabs %}
|
{% block label %}reporting{% endblock %}
|
||||||
{% include "InvenTree/settings/tabs.html" with tab='report' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block subtitle %}
|
{% block heading %}
|
||||||
{% trans "Report Settings" %}
|
{% trans "Report Settings" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block settings %}
|
{% block content %}
|
||||||
|
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
{% include "InvenTree/settings/header.html" %}
|
{% include "InvenTree/settings/header.html" %}
|
||||||
|
@ -17,23 +17,28 @@
|
|||||||
<td>
|
<td>
|
||||||
{% if setting.is_bool %}
|
{% if setting.is_bool %}
|
||||||
<div>
|
<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 %}>
|
<input fieldname='{{ setting.key.upper }}' id='setting-value-{{ setting.key.upper }}' type='checkbox' disabled='' {% if setting.as_bool %}checked=''{% endif %}>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if setting.value %}
|
<div id='setting-{{ setting.pk }}'>
|
||||||
<i><b>
|
<b>
|
||||||
{{ setting.value }}</b> {{ setting.units }}
|
<span id='setting-value-{{ setting.key.upper }}' fieldname='{{ setting.key.upper }}'>
|
||||||
</i>
|
{% if setting.value %}
|
||||||
{% else %}
|
{{ setting.value }}
|
||||||
<i>{% trans "No value set" %}</i>
|
{% else %}
|
||||||
{% endif %}
|
<i>{% trans "No value set" %}</i>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</b>
|
||||||
|
{{ setting.units }}
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td>
|
<td>
|
||||||
{% trans setting.description %}
|
{% trans setting.description %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class='btn-group float-right'>
|
<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" %}' {% if user_setting %}user='{{request.user.id}}'{% endif %}>
|
<button class='btn btn-default btn-glyph btn-edit-setting' pk='{{ setting.pk }}' setting='{{ setting.key.upper }}' title='{% trans "Edit setting" %}' {% if user_setting %}user='{{request.user.id}}'{% endif %}>
|
||||||
<span class='fas fa-edit icon-green'></span>
|
<span class='fas fa-edit icon-green'></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,30 +8,31 @@
|
|||||||
{% inventree_title %} | {% trans "Settings" %}
|
{% inventree_title %} | {% trans "Settings" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block menubar %}
|
||||||
|
{% include "InvenTree/settings/navbar.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class='settings-container'>
|
|
||||||
|
|
||||||
<h3>InvenTree {% trans "Settings" %}</h3>
|
{% include "InvenTree/settings/user.html" %}
|
||||||
<hr>
|
{% include "InvenTree/settings/user_settings.html" %}
|
||||||
|
{% include "InvenTree/settings/user_homepage.html" %}
|
||||||
|
{% include "InvenTree/settings/user_search.html" %}
|
||||||
|
|
||||||
<div class='settings-nav'>
|
{% if user.is_staff %}
|
||||||
{% block tabs %}
|
|
||||||
{% include "InvenTree/settings/tabs.html" %}
|
|
||||||
{% endblock %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class='settings-content'>
|
{% include "InvenTree/settings/global.html" %}
|
||||||
<h3>
|
{% include "InvenTree/settings/barcode.html" %}
|
||||||
{% block subtitle %}
|
{% include "InvenTree/settings/currencies.html" %}
|
||||||
SUBTITLE GOES HERE
|
{% include "InvenTree/settings/report.html" %}
|
||||||
{% endblock %}
|
{% include "InvenTree/settings/part.html" %}
|
||||||
</h3>
|
{% include "InvenTree/settings/category.html" %}
|
||||||
<hr>
|
{% include "InvenTree/settings/stock.html" %}
|
||||||
{% block settings %}
|
{% include "InvenTree/settings/build.html" %}
|
||||||
{% endblock %}
|
{% include "InvenTree/settings/po.html" %}
|
||||||
</div>
|
{% include "InvenTree/settings/so.html" %}
|
||||||
|
|
||||||
</div>
|
{% endif %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@ -53,10 +54,201 @@ $('table').find('.btn-edit-setting').click(function() {
|
|||||||
|
|
||||||
launchModalForm(
|
launchModalForm(
|
||||||
url,
|
url,
|
||||||
|
{
|
||||||
|
success: function(response) {
|
||||||
|
|
||||||
|
if (response.is_bool) {
|
||||||
|
var enabled = response.value.toLowerCase() == 'true';
|
||||||
|
$(`#setting-value-${setting}`).prop('checked', enabled);
|
||||||
|
} else {
|
||||||
|
$(`#setting-value-${setting}`).html(response.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#edit-user").on('click', function() {
|
||||||
|
launchModalForm(
|
||||||
|
"{% url 'edit-user' %}",
|
||||||
{
|
{
|
||||||
reload: true,
|
reload: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#edit-password").on('click', function() {
|
||||||
|
launchModalForm(
|
||||||
|
"{% url 'set-password' %}",
|
||||||
|
{
|
||||||
|
reload: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$('#category-select').select2({
|
||||||
|
placeholder: '',
|
||||||
|
width: '100%',
|
||||||
|
ajax: {
|
||||||
|
url: '{% url "api-part-category-list" %}',
|
||||||
|
dataType: 'json',
|
||||||
|
delay: 250,
|
||||||
|
cache: false,
|
||||||
|
data: function(params) {
|
||||||
|
if (!params.page) {
|
||||||
|
offset = 0;
|
||||||
|
} else {
|
||||||
|
offset = (params.page - 1) * 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
search: params.term,
|
||||||
|
offset: offset,
|
||||||
|
limit: 25,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
processResults: function(response) {
|
||||||
|
var data = [];
|
||||||
|
|
||||||
|
var more = false;
|
||||||
|
|
||||||
|
if ('count' in response && 'results' in response) {
|
||||||
|
// Response is paginated
|
||||||
|
data = response.results;
|
||||||
|
|
||||||
|
// Any more data available?
|
||||||
|
if (response.next) {
|
||||||
|
more = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Non-paginated response
|
||||||
|
data = response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each 'row' must have the 'id' attribute
|
||||||
|
for (var idx = 0; idx < data.length; idx++) {
|
||||||
|
data[idx].id = data[idx].pk;
|
||||||
|
data[idx].text = data[idx].pathstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref: https://select2.org/data-sources/formats
|
||||||
|
var results = {
|
||||||
|
results: data,
|
||||||
|
pagination: {
|
||||||
|
more: more,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#cat-param-table').inventreeTable({
|
||||||
|
formatNoMatches: function() { return '{% trans "No category parameter templates found" %}'; },
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
field: 'pk',
|
||||||
|
title: 'ID',
|
||||||
|
visible: false,
|
||||||
|
switchable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'parameter_template.name',
|
||||||
|
title: '{% trans "Parameter Template" %}',
|
||||||
|
sortable: 'true',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'category_detail.pathstring',
|
||||||
|
title: '{% trans "Category" %}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'default_value',
|
||||||
|
title: '{% trans "Default Value" %}',
|
||||||
|
sortable: 'true',
|
||||||
|
formatter: function(value, row, index, field) {
|
||||||
|
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 = value
|
||||||
|
html += "<div class='btn-group float-right' role='group'>" + bEdit + bDel + "</div>";
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadTemplateTable(pk) {
|
||||||
|
|
||||||
|
console.log('refresh:', pk);
|
||||||
|
|
||||||
|
// Enable the buttons
|
||||||
|
$('#new-cat-param').removeAttr('disabled');
|
||||||
|
|
||||||
|
// Load the parameter table
|
||||||
|
$("#cat-param-table").bootstrapTable('refresh', {
|
||||||
|
query: {
|
||||||
|
category: pk,
|
||||||
|
},
|
||||||
|
url: '{% url "api-part-category-parameter-list" %}',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$('body').on('change', '#category-select', function() {
|
||||||
|
var pk = $(this).val();
|
||||||
|
loadTemplateTable(pk);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#new-cat-param").click(function() {
|
||||||
|
|
||||||
|
var pk = $('#category-select').val();
|
||||||
|
|
||||||
|
launchModalForm(`/part/category/${pk}/parameters/new/`, {
|
||||||
|
success: function() {
|
||||||
|
$("#cat-param-table").bootstrapTable('refresh');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#cat-param-table").on('click', '.template-edit', function() {
|
||||||
|
|
||||||
|
var category = $('#category-select').val();
|
||||||
|
var pk = $(this).attr('pk');
|
||||||
|
|
||||||
|
var url = `/part/category/${category}/parameters/${pk}/edit/`;
|
||||||
|
|
||||||
|
launchModalForm(url, {
|
||||||
|
success: function() {
|
||||||
|
$("#cat-param-table").bootstrapTable('refresh');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#cat-param-table").on('click', '.template-delete', function() {
|
||||||
|
|
||||||
|
var category = $('#category-select').val();
|
||||||
|
var pk = $(this).attr('pk');
|
||||||
|
|
||||||
|
var url = `/part/category/${category}/parameters/${pk}/delete/`;
|
||||||
|
|
||||||
|
launchModalForm(url, {
|
||||||
|
success: function() {
|
||||||
|
$("#cat-param-table").bootstrapTable('refresh');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
enableNavbar({
|
||||||
|
label: 'settings',
|
||||||
|
toggleId: '#item-menu-toggle',
|
||||||
|
});
|
||||||
|
|
||||||
|
attachNavCallbacks({
|
||||||
|
name: 'settings',
|
||||||
|
default: 'account'
|
||||||
|
});
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
{% extends "InvenTree/settings/settings.html" %}
|
{% extends "panel.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block tabs %}
|
{% block label %}sales-order{% endblock %}
|
||||||
{% include "InvenTree/settings/tabs.html" with tab='so' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block subtitle %}
|
{% block heading %}
|
||||||
{% trans "Sales Order Settings" %}
|
{% trans "Sales Order Settings" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block settings %}
|
{% block content %}
|
||||||
|
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
{% include "InvenTree/settings/header.html" %}
|
{% include "InvenTree/settings/header.html" %}
|
||||||
|
@ -1,22 +1,18 @@
|
|||||||
{% extends "InvenTree/settings/settings.html" %}
|
{% extends "panel.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block tabs %}
|
{% block label %}stock{% endblock %}
|
||||||
{% include "InvenTree/settings/tabs.html" with tab='stock' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block subtitle %}
|
{% block heading %}
|
||||||
{% trans "Stock Settings" %}
|
{% trans "Stock Settings" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block settings %}
|
{% block content %}
|
||||||
<h4>{% trans "Stock Options" %}</h4>
|
|
||||||
|
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
{% include "InvenTree/settings/header.html" %}
|
{% include "InvenTree/settings/header.html" %}
|
||||||
<tbody>
|
<tbody>
|
||||||
{% include "InvenTree/settings/setting.html" with key="STOCK_GROUP_BY_PART" icon="fa-layer-group" %}
|
{% include "InvenTree/settings/setting.html" with key="STOCK_GROUP_BY_PART" icon="fa-layer-group" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="STOCK_RECENT_COUNT" icon="fa-clock" %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="STOCK_ENABLE_EXPIRY" icon="fa-stopwatch" %}
|
{% include "InvenTree/settings/setting.html" with key="STOCK_ENABLE_EXPIRY" icon="fa-stopwatch" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="STOCK_STALE_DAYS" icon="fa-calendar" %}
|
{% include "InvenTree/settings/setting.html" with key="STOCK_STALE_DAYS" icon="fa-calendar" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="STOCK_ALLOW_EXPIRED_SALE" icon="fa-truck" %}
|
{% include "InvenTree/settings/setting.html" with key="STOCK_ALLOW_EXPIRED_SALE" icon="fa-truck" %}
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
|
|
||||||
<h4><span class='fas fa-user'></span> {% trans "User Settings" %}</h4>
|
|
||||||
<ul class='nav nav-pills nav-stacked'>
|
|
||||||
<li{% ifequal tab 'user' %} class='active'{% endifequal %}>
|
|
||||||
<a href="{% url 'settings-user' %}"><span class='fas fa-user'></span> {% trans "Account" %}</a>
|
|
||||||
</li>
|
|
||||||
<li{% ifequal tab 'theme' %} class='active'{% endifequal %}>
|
|
||||||
<a href="{% url 'settings-appearance' %}"><span class='fas fa-fill'></span> {% trans "Appearance" %}</a>
|
|
||||||
</li>
|
|
||||||
<li{% ifequal tab 'user_settings' %} class='active'{% endifequal %}>
|
|
||||||
<a href="{% url 'settings-user-settings' %}"><span class='fas fa-cog'></span> {% trans "User Settings" %}</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 {% if tab == 'currencies' %} class='active'{% endif %}>
|
|
||||||
<a href="{% url 'settings-currencies' %}"><span class='fas fa-dollar-sign'></span> {% trans "Currencies" %}</a>
|
|
||||||
</li>
|
|
||||||
<li {% if tab == 'report' %} class='active' {% endif %}>
|
|
||||||
<a href='{% url "settings-report" %}'><span class='fas fa-file-pdf'></span> {% trans "Report" %}</a>
|
|
||||||
</li>
|
|
||||||
<li{% ifequal tab 'category' %} class='active'{% endifequal %}>
|
|
||||||
<a href="{% url 'settings-category' %}"><span class='fa fa-sitemap'></span> {% trans "Categories" %}</a>
|
|
||||||
</li>
|
|
||||||
<li{% ifequal tab 'part' %} class='active'{% endifequal %}>
|
|
||||||
<a href="{% url 'settings-part' %}"><span class='fas fa-shapes'></span> {% trans "Parts" %}</a>
|
|
||||||
</li>
|
|
||||||
<li {% if tab == 'stock' %} class='active'{% endif %}>
|
|
||||||
<a href='{% url 'settings-stock' %}'><span class='fas fa-boxes'></span> {% trans "Stock" %}</a>
|
|
||||||
</li>
|
|
||||||
<li {% if tab == 'build' %} class='active'{% endif %}>
|
|
||||||
<a href="{% url 'settings-build' %}"><span class='fas fa-tools'></span> {% trans "Build Orders" %}</a>
|
|
||||||
</li>
|
|
||||||
<li {% if tab == 'po' %} class='active'{% endif %}>
|
|
||||||
<a href="{% url 'settings-po' %}"><span class='fas fa-shopping-cart'></span> {% trans "Purchase Orders" %}</a>
|
|
||||||
</li>
|
|
||||||
<li {% if tab == 'so' %} class='active'{% endif %}>
|
|
||||||
<a href="{% url 'settings-so' %}"><span class='fas fa-truck'></span> {% trans "Sales Orders" %}</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
@ -1,69 +1,95 @@
|
|||||||
{% extends "InvenTree/settings/settings.html" %}
|
{% extends "panel.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
|
||||||
{% block tabs %}
|
{% block label %}account{% endblock %}
|
||||||
{% include "InvenTree/settings/tabs.html" with tab='user' %}
|
|
||||||
|
{% block heading %}
|
||||||
|
{% trans "Account Settings" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block subtitle %}
|
{% block content %}
|
||||||
{% trans "User Settings" %}
|
<div class='btn-group' style='float: right;'>
|
||||||
{% endblock %}
|
<div class='btn btn-primary' type='button' id='edit-user' title='{% trans "Edit User Information" %}'>
|
||||||
|
<span class='fas fa-user-cog'></span> {% trans "Edit" %}
|
||||||
{% block settings %}
|
</div>
|
||||||
|
<div class='btn btn-primary' type='button' id='edit-password' title='{% trans "Change Password" %}'>
|
||||||
<div class='container'>
|
<span class='fas fa-key'></span> {% trans "Set Password" %}
|
||||||
<h4>{% trans "User Information" %}</h4>
|
|
||||||
<div class='btn-group' style='float: right;'>
|
|
||||||
<div class='btn btn-primary' type='button' id='edit-user' title='{% trans "Edit User Information" %}'>
|
|
||||||
<span class='fas fa-user-cog'></span> {% trans "Edit" %}
|
|
||||||
</div>
|
|
||||||
<div class='btn btn-primary' type='button' id='edit-password' title='{% trans "Change Password" %}'>
|
|
||||||
<span class='fas fa-key'></span> {% trans "Set Password" %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class='table table-striped table-condensed'>
|
|
||||||
<tr>
|
|
||||||
<td>{% trans "Username" %}</td>
|
|
||||||
<td>{{ user.username }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{% trans "First Name" %}</td>
|
|
||||||
<td>{{ user.first_name }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{% trans "Last Name" %}</td>
|
|
||||||
<td>{{ user.last_name }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{% trans "Email Address" %}</td>
|
|
||||||
<td>{{ user.email }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
<table class='table table-striped table-condensed'>
|
||||||
|
<tr>
|
||||||
|
<td>{% trans "Username" %}</td>
|
||||||
|
<td>{{ user.username }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{% trans "First Name" %}</td>
|
||||||
|
<td>{{ user.first_name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{% trans "Last Name" %}</td>
|
||||||
|
<td>{{ user.last_name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{% trans "Email Address" %}</td>
|
||||||
|
<td>{{ user.email }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
{% block js_ready %}
|
<div class='panel-heading'>
|
||||||
{{ block.super }}
|
<h4>{% trans "Theme Settings" %}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
$("#edit-user").on('click', function() {
|
<div class='row'>
|
||||||
launchModalForm(
|
|
||||||
"{% url 'edit-user' %}",
|
|
||||||
{
|
|
||||||
reload: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#edit-password").on('click', function() {
|
<form action='{% url "settings-appearance" %}' method='post'>
|
||||||
launchModalForm(
|
{% csrf_token %}
|
||||||
"{% url 'set-password' %}",
|
<input name='next' type='hidden' value='{% url "settings" %}'>
|
||||||
{
|
<div class="col-sm-6" style="width: 200px;">
|
||||||
reload: true,
|
<div id="div_id_themes" class="form-group">
|
||||||
}
|
<div class="controls ">
|
||||||
);
|
<select name='theme' class='select form-control'>
|
||||||
});
|
{% get_available_themes as themes %}
|
||||||
|
{% for theme in themes %}
|
||||||
|
<option value='{{ theme.key }}'>{{ theme.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="width: auto;">
|
||||||
|
<input type="submit" value="{% trans 'Set Theme' %}" class="btn btn btn-primary">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='panel-heading'>
|
||||||
|
<h4>{% trans "Language Settings" %}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<form action="{% url 'set_language' %}" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input name="next" type="hidden" value="{% url 'settings' %}">
|
||||||
|
<div class="col-sm-6" style="width: 200px;"><div id="div_id_language" class="form-group"><div class="controls ">
|
||||||
|
<select name="language" class="select form-control">
|
||||||
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
|
{% get_available_languages as LANGUAGES %}
|
||||||
|
{% get_language_info_list for LANGUAGES as languages %}
|
||||||
|
{% for language in languages %}
|
||||||
|
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
|
||||||
|
{{ language.name_local }} ({{ language.code }})
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div></div></div>
|
||||||
|
<div class="col-sm-6" style="width: auto;">
|
||||||
|
<input type="submit" value="{% trans 'Set Language' %}" class="btn btn btn-primary">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
42
InvenTree/templates/InvenTree/settings/user_homepage.html
Normal file
42
InvenTree/templates/InvenTree/settings/user_homepage.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{% extends "panel.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
|
||||||
|
{% block label %}user-home{% endblock %}
|
||||||
|
|
||||||
|
{% block heading %}
|
||||||
|
{% trans "Home Page Settings" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class='row'>
|
||||||
|
<table class='table table-striped table-condensed'>
|
||||||
|
{% include "InvenTree/settings/header.html" %}
|
||||||
|
<tbody>
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_PART_STARRED" icon='fa-star' user_setting=True %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_PART_LATEST" icon='fa-history' user_setting=True %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="PART_RECENT_COUNT" icon="fa-clock" user_setting=True %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_BOM_VALIDATION" user_setting=True %}
|
||||||
|
<tr><td colspan='5'></td></tr>
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_STOCK_RECENT" icon='fa-history' user_setting=True %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="STOCK_RECENT_COUNT" icon="fa-clock" user_setting=True %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_STOCK_LOW" user_setting=True %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_STOCK_DEPLETED" user_setting=True %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_STOCK_NEEDED" user_setting=True %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_STOCK_EXPIRED" icon='fa-calendar-alt' user_setting=True %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_STOCK_STALE" icon='fa-calendar-alt' user_setting=True %}
|
||||||
|
<tr><td colspan='5'></td></tr>
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_BUILD_PENDING" user_setting=True %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_BUILD_OVERDUE" user_setting=True %}
|
||||||
|
<tr><td colspan='5'></td></tr>
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_PO_OUTSTANDING" user_setting=True %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_PO_OVERDUE" user_setting=True %}
|
||||||
|
<tr><td colspan='5'></td></tr>
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_SO_OUTSTANDING" user_setting=True %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_SO_OVERDUE" user_setting=True %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
23
InvenTree/templates/InvenTree/settings/user_search.html
Normal file
23
InvenTree/templates/InvenTree/settings/user_search.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{% extends "panel.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
|
||||||
|
{% block label %}user-search{% endblock %}
|
||||||
|
|
||||||
|
{% block heading %}
|
||||||
|
{% trans "Search Settings" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class='row'>
|
||||||
|
<table class='table table-striped table-condensed'>
|
||||||
|
{% include "InvenTree/settings/header.html" %}
|
||||||
|
<tbody>
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_RESULTS" user_setting=True icon='fa-search' %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -1,41 +1,21 @@
|
|||||||
{% extends "InvenTree/settings/settings.html" %}
|
{% extends "panel.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load inventree_extras %}
|
{% load inventree_extras %}
|
||||||
|
|
||||||
{% block tabs %}
|
{% block label %}user-settings{% endblock %}
|
||||||
{% include "InvenTree/settings/tabs.html" with tab='user_settings' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block subtitle %}
|
{% block heading %}
|
||||||
{% trans "User Settings" %}
|
{% trans "User Settings" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block settings %}
|
{% block content %}
|
||||||
|
|
||||||
<div class='row'>
|
<div class='row'>
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
{% include "InvenTree/settings/header.html" %}
|
{% include "InvenTree/settings/header.html" %}
|
||||||
<tbody>
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_PART_STARRED" user_setting=True %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_PART_LATEST" user_setting=True %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_BOM_VALIDATION" user_setting=True %}
|
|
||||||
<tr><td colspan='5'></td></tr>
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_STOCK_RECENT" user_setting=True %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_STOCK_LOW" user_setting=True %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_STOCK_DEPLETED" user_setting=True %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_STOCK_NEEDED" user_setting=True %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_STOCK_EXPIRED" user_setting=True %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_STOCK_STALE" user_setting=True %}
|
|
||||||
<tr><td colspan='5'></td></tr>
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_BUILD_PENDING" user_setting=True %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_BUILD_OVERDUE" user_setting=True %}
|
|
||||||
<tr><td colspan='5'></td></tr>
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_PO_OUTSTANDING" user_setting=True %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_PO_OVERDUE" user_setting=True %}
|
|
||||||
<tr><td colspan='5'></td></tr>
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_SO_OUTSTANDING" user_setting=True %}
|
|
||||||
{% include "InvenTree/settings/setting.html" with key="HOMEPAGE_SO_OVERDUE" user_setting=True %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -145,19 +145,22 @@
|
|||||||
<script type='text/javascript' src="{% static 'script/inventree/notification.js' %}"></script>
|
<script type='text/javascript' src="{% static 'script/inventree/notification.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% static 'script/inventree/sidenav.js' %}"></script>
|
<script type='text/javascript' src="{% static 'script/inventree/sidenav.js' %}"></script>
|
||||||
|
|
||||||
<!-- translated -->
|
<!-- dynamic javascript templates -->
|
||||||
<script type='text/javascript' src="{% i18n_static 'inventree.js' %}"></script>
|
<script type='text/javascript' src="{% url 'inventree.js' %}"></script>
|
||||||
|
<script type='text/javascript' src="{% url 'calendar.js' %}"></script>
|
||||||
|
<script type='text/javascript' src="{% url 'nav.js' %}"></script>
|
||||||
|
<script type='text/javascript' src="{% url 'settings.js' %}"></script>
|
||||||
|
|
||||||
|
<!-- translated javascript templates-->
|
||||||
<script type='text/javascript' src="{% i18n_static 'api.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'api.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'attachment.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'attachment.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'barcode.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'barcode.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'bom.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'bom.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'build.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'build.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'calendar.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% i18n_static 'company.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'company.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'filters.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'filters.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'forms.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'forms.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'label.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'label.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'nav.js' %}"></script>
|
|
||||||
<script type='text/javascript' src="{% i18n_static 'modals.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'modals.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'model_renderers.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'model_renderers.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% i18n_static 'order.js' %}"></script>
|
<script type='text/javascript' src="{% i18n_static 'order.js' %}"></script>
|
||||||
|
@ -91,7 +91,7 @@ function inventreeDocReady() {
|
|||||||
url: '/api/part/',
|
url: '/api/part/',
|
||||||
data: {
|
data: {
|
||||||
search: request.term,
|
search: request.term,
|
||||||
limit: {% settings_value 'SEARCH_PREVIEW_RESULTS' %},
|
limit: user_settings.SEARCH_PREVIEW_RESULTS,
|
||||||
offset: 0
|
offset: 0
|
||||||
},
|
},
|
||||||
success: function (data) {
|
success: function (data) {
|
17
InvenTree/templates/js/dynamic/settings.js
Normal file
17
InvenTree/templates/js/dynamic/settings.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{% load inventree_extras %}
|
||||||
|
// InvenTree settings
|
||||||
|
|
||||||
|
{% user_settings request.user as USER_SETTINGS %}
|
||||||
|
{% global_settings as GLOBAL_SETTINGS %}
|
||||||
|
|
||||||
|
var user_settings = {
|
||||||
|
{% for setting in USER_SETTINGS %}
|
||||||
|
{{ setting.key }}: {{ setting.value|safe }},
|
||||||
|
{% endfor %}
|
||||||
|
};
|
||||||
|
|
||||||
|
var global_settings = {
|
||||||
|
{% for setting in GLOBAL_SETTINGS %}
|
||||||
|
{{ setting.key }}: {{ setting.value|safe }},
|
||||||
|
{% endfor %}
|
||||||
|
};
|
@ -147,8 +147,7 @@ function inventreeDelete(url, options={}) {
|
|||||||
|
|
||||||
options.method = 'DELETE';
|
options.method = 'DELETE';
|
||||||
|
|
||||||
inventreePut(url, {}, options);
|
return inventreePut(url, {}, options);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
|||||||
function buildFormFields() {
|
function buildFormFields() {
|
||||||
return {
|
return {
|
||||||
reference: {
|
reference: {
|
||||||
prefix: "{% settings_value 'BUILDORDER_REFERENCE_PREFIX' %}",
|
prefix: global_settings.BUILDORDER_REFERENCE_PREFIX,
|
||||||
},
|
},
|
||||||
title: {},
|
title: {},
|
||||||
part: {},
|
part: {},
|
||||||
@ -232,7 +232,7 @@ function loadBuildOrderAllocationTable(table, options={}) {
|
|||||||
switchable: false,
|
switchable: false,
|
||||||
title: '{% trans "Build Order" %}',
|
title: '{% trans "Build Order" %}',
|
||||||
formatter: function(value, row) {
|
formatter: function(value, row) {
|
||||||
var prefix = "{% settings_value 'BUILDORDER_REFERENCE_PREFIX' %}";
|
var prefix = global_settings.BUILDORDER_REFERENCE_PREFIX;
|
||||||
|
|
||||||
var ref = `${prefix}${row.build_detail.reference}`;
|
var ref = `${prefix}${row.build_detail.reference}`;
|
||||||
|
|
||||||
@ -848,7 +848,7 @@ function loadBuildTable(table, options) {
|
|||||||
switchable: true,
|
switchable: true,
|
||||||
formatter: function(value, row, index, field) {
|
formatter: function(value, row, index, field) {
|
||||||
|
|
||||||
var prefix = "{% settings_value 'BUILDORDER_REFERENCE_PREFIX' %}";
|
var prefix = global_settings.BUILDORDER_REFERENCE_PREFIX;
|
||||||
|
|
||||||
if (prefix) {
|
if (prefix) {
|
||||||
value = `${prefix}${value}`;
|
value = `${prefix}${value}`;
|
@ -349,7 +349,7 @@ function deleteManufacturerParts(selections, options={}) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Wait for all the requests to complete
|
// Wait for all the requests to complete
|
||||||
$.when.apply($, requests).then(function() {
|
$.when.apply($, requests).done(function() {
|
||||||
|
|
||||||
if (options.onSuccess) {
|
if (options.onSuccess) {
|
||||||
options.onSuccess();
|
options.onSuccess();
|
@ -9,7 +9,7 @@ function createSalesOrder(options={}) {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
fields: {
|
fields: {
|
||||||
reference: {
|
reference: {
|
||||||
prefix: '{% settings_value "SALESORDER_REFERENCE_PREFIX" %}',
|
prefix: global_settings.SALESORDER_REFERENCE_PREFIX,
|
||||||
},
|
},
|
||||||
customer: {
|
customer: {
|
||||||
value: options.customer,
|
value: options.customer,
|
||||||
@ -40,7 +40,7 @@ function createPurchaseOrder(options={}) {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
fields: {
|
fields: {
|
||||||
reference: {
|
reference: {
|
||||||
prefix: "{% settings_value 'PURCHASEORDER_REFERENCE_PREFIX' %}",
|
prefix: global_settings.PURCHASEORDER_REFERENCE_PREFIX,
|
||||||
},
|
},
|
||||||
supplier: {
|
supplier: {
|
||||||
value: options.supplier,
|
value: options.supplier,
|
||||||
@ -214,7 +214,7 @@ function loadPurchaseOrderTable(table, options) {
|
|||||||
switchable: false,
|
switchable: false,
|
||||||
formatter: function(value, row, index, field) {
|
formatter: function(value, row, index, field) {
|
||||||
|
|
||||||
var prefix = "{% settings_value 'PURCHASEORDER_REFERENCE_PREFIX' %}";
|
var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
|
||||||
|
|
||||||
if (prefix) {
|
if (prefix) {
|
||||||
value = `${prefix}${value}`;
|
value = `${prefix}${value}`;
|
||||||
@ -309,7 +309,7 @@ function loadSalesOrderTable(table, options) {
|
|||||||
title: '{% trans "Sales Order" %}',
|
title: '{% trans "Sales Order" %}',
|
||||||
formatter: function(value, row, index, field) {
|
formatter: function(value, row, index, field) {
|
||||||
|
|
||||||
var prefix = "{% settings_value 'SALESORDER_REFERENCE_PREFIX' %}";
|
var prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
|
||||||
|
|
||||||
if (prefix) {
|
if (prefix) {
|
||||||
value = `${prefix}${value}`;
|
value = `${prefix}${value}`;
|
||||||
@ -423,7 +423,7 @@ function loadSalesOrderAllocationTable(table, options={}) {
|
|||||||
switchable: false,
|
switchable: false,
|
||||||
formatter: function(value, row) {
|
formatter: function(value, row) {
|
||||||
|
|
||||||
var prefix = "{% settings_value 'SALESORDER_REFERENCE_PREFIX' %}";
|
var prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
|
||||||
|
|
||||||
var ref = `${prefix}${row.order_detail.reference}`;
|
var ref = `${prefix}${row.order_detail.reference}`;
|
||||||
|
|
@ -6,8 +6,6 @@
|
|||||||
* Requires api.js to be loaded first
|
* Requires api.js to be loaded first
|
||||||
*/
|
*/
|
||||||
|
|
||||||
{% settings_value 'BARCODE_ENABLE' as barcodes %}
|
|
||||||
|
|
||||||
function stockStatusCodes() {
|
function stockStatusCodes() {
|
||||||
return [
|
return [
|
||||||
{% for code in StockStatus.list %}
|
{% for code in StockStatus.list %}
|
||||||
@ -287,7 +285,7 @@ function adjustStock(action, items, options={}) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Wait for *all* the requests to complete
|
// Wait for *all* the requests to complete
|
||||||
$.when.apply($, requests).then(function() {
|
$.when.apply($, requests).done(function() {
|
||||||
// Destroy the modal window
|
// Destroy the modal window
|
||||||
$(modal).modal('hide');
|
$(modal).modal('hide');
|
||||||
|
|
||||||
@ -704,8 +702,7 @@ function loadStockTable(table, options) {
|
|||||||
name: 'stock',
|
name: 'stock',
|
||||||
original: original,
|
original: original,
|
||||||
showColumns: true,
|
showColumns: true,
|
||||||
{% settings_value 'STOCK_GROUP_BY_PART' as group_by_part %}
|
{% if False %}
|
||||||
{% if group_by_part %}
|
|
||||||
groupByField: options.groupByField || 'part',
|
groupByField: options.groupByField || 'part',
|
||||||
groupBy: grouping,
|
groupBy: grouping,
|
||||||
groupByFormatter: function(field, id, data) {
|
groupByFormatter: function(field, id, data) {
|
||||||
@ -1011,14 +1008,13 @@ function loadStockTable(table, options) {
|
|||||||
title: '{% trans "Stocktake" %}',
|
title: '{% trans "Stocktake" %}',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
{% settings_value "STOCK_ENABLE_EXPIRY" as expiry %}
|
|
||||||
{% if expiry %}
|
|
||||||
{
|
{
|
||||||
field: 'expiry_date',
|
field: 'expiry_date',
|
||||||
title: '{% trans "Expiry Date" %}',
|
title: '{% trans "Expiry Date" %}',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
|
visible: global_settings.STOCK_ENABLE_EXPIRY,
|
||||||
|
switchable: global_settings.STOCK_ENABLE_EXPIRY,
|
||||||
},
|
},
|
||||||
{% endif %}
|
|
||||||
{
|
{
|
||||||
field: 'updated',
|
field: 'updated',
|
||||||
title: '{% trans "Last Updated" %}',
|
title: '{% trans "Last Updated" %}',
|
||||||
@ -1037,7 +1033,7 @@ function loadStockTable(table, options) {
|
|||||||
|
|
||||||
if (row.purchase_order_reference) {
|
if (row.purchase_order_reference) {
|
||||||
|
|
||||||
var prefix = '{% settings_value "PURCHASEORDER_REFERENCE_PREFIX" %}';
|
var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
|
||||||
|
|
||||||
text = prefix + row.purchase_order_reference;
|
text = prefix + row.purchase_order_reference;
|
||||||
}
|
}
|
||||||
@ -1090,15 +1086,18 @@ function loadStockTable(table, options) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var buttons = [
|
||||||
|
'#stock-print-options',
|
||||||
|
'#stock-options',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (global_settings.BARCODE_ENABLE) {
|
||||||
|
buttons.push('#stock-barcode-options');
|
||||||
|
}
|
||||||
|
|
||||||
linkButtonsToSelection(
|
linkButtonsToSelection(
|
||||||
table,
|
table,
|
||||||
[
|
buttons,
|
||||||
'#stock-print-options',
|
|
||||||
{% if barcodes %}
|
|
||||||
'#stock-barcode-options',
|
|
||||||
{% endif %}
|
|
||||||
'#stock-options',
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@ -1138,19 +1137,19 @@ function loadStockTable(table, options) {
|
|||||||
printTestReports(items);
|
printTestReports(items);
|
||||||
})
|
})
|
||||||
|
|
||||||
{% if barcodes %}
|
if (global_settings.BARCODE_ENABLE) {
|
||||||
$('#multi-item-barcode-scan-into-location').click(function() {
|
$('#multi-item-barcode-scan-into-location').click(function() {
|
||||||
var selections = $('#stock-table').bootstrapTable('getSelections');
|
var selections = $('#stock-table').bootstrapTable('getSelections');
|
||||||
|
|
||||||
var items = [];
|
var items = [];
|
||||||
|
|
||||||
selections.forEach(function(item) {
|
selections.forEach(function(item) {
|
||||||
items.push(item.pk);
|
items.push(item.pk);
|
||||||
})
|
})
|
||||||
|
|
||||||
scanItemsIntoLocation(items);
|
scanItemsIntoLocation(items);
|
||||||
});
|
});
|
||||||
{% endif %}
|
}
|
||||||
|
|
||||||
$('#multi-item-stocktake').click(function() {
|
$('#multi-item-stocktake').click(function() {
|
||||||
stockAdjustment('count');
|
stockAdjustment('count');
|
||||||
@ -1265,7 +1264,7 @@ function loadStockTable(table, options) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$.when.apply($, requests).then(function() {
|
$.when.apply($, requests).done(function() {
|
||||||
$("#stock-table").bootstrapTable('refresh');
|
$("#stock-table").bootstrapTable('refresh');
|
||||||
});
|
});
|
||||||
})
|
})
|
@ -121,7 +121,8 @@ function getAvailableTableFilters(tableKey) {
|
|||||||
|
|
||||||
// Filters for the "Stock" table
|
// Filters for the "Stock" table
|
||||||
if (tableKey == 'stock') {
|
if (tableKey == 'stock') {
|
||||||
return {
|
|
||||||
|
var filters = {
|
||||||
active: {
|
active: {
|
||||||
type: 'bool',
|
type: 'bool',
|
||||||
title: '{% trans "Active parts" %}',
|
title: '{% trans "Active parts" %}',
|
||||||
@ -147,19 +148,6 @@ function getAvailableTableFilters(tableKey) {
|
|||||||
title: '{% trans "Depleted" %}',
|
title: '{% trans "Depleted" %}',
|
||||||
description: '{% trans "Show stock items which are depleted" %}',
|
description: '{% trans "Show stock items which are depleted" %}',
|
||||||
},
|
},
|
||||||
{% settings_value "STOCK_ENABLE_EXPIRY" as expiry %}
|
|
||||||
{% if expiry %}
|
|
||||||
expired: {
|
|
||||||
type: 'bool',
|
|
||||||
title: '{% trans "Expired" %}',
|
|
||||||
description: '{% trans "Show stock items which have expired" %}',
|
|
||||||
},
|
|
||||||
stale: {
|
|
||||||
type: 'bool',
|
|
||||||
title: '{% trans "Stale" %}',
|
|
||||||
description: '{% trans "Show stock which is close to expiring" %}',
|
|
||||||
},
|
|
||||||
{% endif %}
|
|
||||||
in_stock: {
|
in_stock: {
|
||||||
type: 'bool',
|
type: 'bool',
|
||||||
title: '{% trans "In Stock" %}',
|
title: '{% trans "In Stock" %}',
|
||||||
@ -216,6 +204,23 @@ function getAvailableTableFilters(tableKey) {
|
|||||||
description: '{% trans "Show stock items which have a purchase price set" %}',
|
description: '{% trans "Show stock items which have a purchase price set" %}',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Optional filters if stock expiry functionality is enabled
|
||||||
|
if (global_settings.STOCK_ENABLE_EXPIRY) {
|
||||||
|
filters.expired = {
|
||||||
|
type: 'bool',
|
||||||
|
title: '{% trans "Expired" %}',
|
||||||
|
description: '{% trans "Show stock items which have expired" %}',
|
||||||
|
};
|
||||||
|
|
||||||
|
filters.stale = {
|
||||||
|
type: 'bool',
|
||||||
|
title: '{% trans "Stale" %}',
|
||||||
|
description: '{% trans "Show stock which is close to expiring" %}',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filters for the 'stock test' table
|
// Filters for the 'stock test' table
|
13
InvenTree/templates/panel.html
Normal file
13
InvenTree/templates/panel.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<div class='panel panel-default panel-inventree panel-hidden' id='panel-{% block label %}name{% endblock %}'>
|
||||||
|
{% block panel_heading %}
|
||||||
|
<div class='panel-heading'>
|
||||||
|
<h4>{% block heading %}HEADING{% endblock %}</h4>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block panel_content %}
|
||||||
|
<div class='panel-content'>
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
121
ci/check_js_templates.py
Normal file
121
ci/check_js_templates.py
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
"""
|
||||||
|
Test that the "translated" javascript files to not contain template tags
|
||||||
|
which need to be determined at "run time".
|
||||||
|
|
||||||
|
This is because the "translated" javascript files are compiled into the "static" directory.
|
||||||
|
|
||||||
|
They should only contain template tags that render static information.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
here = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
template_dir = os.path.abspath(os.path.join(here, '..', 'InvenTree', 'templates'))
|
||||||
|
|
||||||
|
# We only care about the 'translated' files
|
||||||
|
js_i18n_dir = os.path.join(template_dir, 'js', 'translated')
|
||||||
|
js_dynamic_dir = os.path.join(template_dir, 'js', 'dynamic')
|
||||||
|
|
||||||
|
errors = 0
|
||||||
|
|
||||||
|
print("=================================")
|
||||||
|
print("Checking static javascript files:")
|
||||||
|
print("=================================")
|
||||||
|
|
||||||
|
def check_invalid_tag(data):
|
||||||
|
|
||||||
|
pattern = r"{%(\w+)"
|
||||||
|
|
||||||
|
err_count = 0
|
||||||
|
|
||||||
|
for idx, line in enumerate(data):
|
||||||
|
|
||||||
|
results = re.findall(pattern, line)
|
||||||
|
|
||||||
|
for result in results:
|
||||||
|
err_count += 1
|
||||||
|
|
||||||
|
print(f" - Error on line {idx+1}: %{{{result[0]}")
|
||||||
|
|
||||||
|
return err_count
|
||||||
|
|
||||||
|
def check_prohibited_tags(data):
|
||||||
|
|
||||||
|
allowed_tags = [
|
||||||
|
'if',
|
||||||
|
'elif',
|
||||||
|
'else',
|
||||||
|
'endif',
|
||||||
|
'for',
|
||||||
|
'endfor',
|
||||||
|
'trans',
|
||||||
|
'load',
|
||||||
|
'include',
|
||||||
|
'url',
|
||||||
|
]
|
||||||
|
|
||||||
|
pattern = r"{% (\w+)\s"
|
||||||
|
|
||||||
|
err_count = 0
|
||||||
|
|
||||||
|
has_trans = False
|
||||||
|
|
||||||
|
for idx, line in enumerate(data):
|
||||||
|
|
||||||
|
for tag in re.findall(pattern, line):
|
||||||
|
|
||||||
|
if tag not in allowed_tags:
|
||||||
|
print(f" > Line {idx+1} contains prohibited template tag '{tag}'")
|
||||||
|
err_count += 1
|
||||||
|
|
||||||
|
if tag == 'trans':
|
||||||
|
has_trans = True
|
||||||
|
|
||||||
|
if not has_trans:
|
||||||
|
print(f" > file is missing 'trans' tags")
|
||||||
|
err_count += 1
|
||||||
|
|
||||||
|
return err_count
|
||||||
|
|
||||||
|
|
||||||
|
for filename in pathlib.Path(js_i18n_dir).rglob('*.js'):
|
||||||
|
|
||||||
|
print(f"Checking file 'translated/{os.path.basename(filename)}':")
|
||||||
|
|
||||||
|
with open(filename, 'r') as js_file:
|
||||||
|
data = js_file.readlines()
|
||||||
|
|
||||||
|
errors += check_invalid_tag(data)
|
||||||
|
errors += check_prohibited_tags(data)
|
||||||
|
|
||||||
|
for filename in pathlib.Path(js_dynamic_dir).rglob('*.js'):
|
||||||
|
|
||||||
|
print(f"Checking file 'dynamic/{os.path.basename(filename)}':")
|
||||||
|
|
||||||
|
# Check that the 'dynamic' files do not contains any translated strings
|
||||||
|
with open(filename, 'r') as js_file:
|
||||||
|
data = js_file.readlines()
|
||||||
|
|
||||||
|
pattern = r'{% trans '
|
||||||
|
|
||||||
|
err_count = 0
|
||||||
|
|
||||||
|
for idx, line in enumerate(data):
|
||||||
|
|
||||||
|
results = re.findall(pattern, line)
|
||||||
|
|
||||||
|
if len(results) > 0:
|
||||||
|
errors += 1
|
||||||
|
|
||||||
|
print(f" > prohibited {{% trans %}} tag found at line {idx + 1}")
|
||||||
|
|
||||||
|
if errors > 0:
|
||||||
|
print(f"Found {errors} incorrect template tags")
|
||||||
|
|
||||||
|
sys.exit(errors)
|
@ -27,6 +27,10 @@ ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DATA_DIR}/media"
|
|||||||
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DATA_DIR}/config.yaml"
|
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DATA_DIR}/config.yaml"
|
||||||
ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DATA_DIR}/secret_key.txt"
|
ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DATA_DIR}/secret_key.txt"
|
||||||
|
|
||||||
|
# Worker configuration (can be altered by user)
|
||||||
|
ENV INVENTREE_GUNICORN_WORKERS="4"
|
||||||
|
ENV INVENTREE_BACKGROUND_WORKERS="4"
|
||||||
|
|
||||||
# Default web server port is 8000
|
# Default web server port is 8000
|
||||||
ENV INVENTREE_WEB_PORT="8000"
|
ENV INVENTREE_WEB_PORT="8000"
|
||||||
|
|
||||||
|
@ -1,6 +1,22 @@
|
|||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
workers = multiprocessing.cpu_count() * 2 + 1
|
|
||||||
|
logger = logging.getLogger('inventree')
|
||||||
|
|
||||||
|
workers = os.environ.get('INVENTREE_GUNICORN_WORKERS', None)
|
||||||
|
|
||||||
|
if workers is not None:
|
||||||
|
try:
|
||||||
|
workers = int(workers)
|
||||||
|
except ValueError:
|
||||||
|
workers = None
|
||||||
|
|
||||||
|
if workers is None:
|
||||||
|
workers = multiprocessing.cpu_count() * 2 + 1
|
||||||
|
|
||||||
|
logger.info(f"Starting gunicorn server with {workers} workers")
|
||||||
|
|
||||||
max_requests = 1000
|
max_requests = 1000
|
||||||
max_requests_jitter = 50
|
max_requests_jitter = 50
|
||||||
|
@ -45,5 +45,7 @@ python3 manage.py migrate --noinput || exit 1
|
|||||||
python3 manage.py migrate --run-syncdb || exit 1
|
python3 manage.py migrate --run-syncdb || exit 1
|
||||||
python3 manage.py clearsessions || exit 1
|
python3 manage.py clearsessions || exit 1
|
||||||
|
|
||||||
|
invoke static
|
||||||
|
|
||||||
# Launch a development server
|
# Launch a development server
|
||||||
python3 manage.py runserver ${INVENTREE_WEB_ADDR}:${INVENTREE_WEB_PORT}
|
python3 manage.py runserver ${INVENTREE_WEB_ADDR}:${INVENTREE_WEB_PORT}
|
||||||
|
@ -39,4 +39,4 @@ python3 manage.py collectstatic --noinput || exit 1
|
|||||||
python3 manage.py clearsessions || exit 1
|
python3 manage.py clearsessions || exit 1
|
||||||
|
|
||||||
# Now we can launch the server
|
# Now we can launch the server
|
||||||
gunicorn -c $INVENTREE_HOME/gunicorn.conf.py InvenTree.wsgi -b 0.0.0.0:$INVENTREE_WEB_PORT
|
gunicorn -c $INVENTREE_HOME/gunicorn.conf.py InvenTree.wsgi -b 0.0.0.0:$INVENTREE_WEB_PORT
|
||||||
|
@ -11,4 +11,4 @@ python3 manage.py wait_for_db
|
|||||||
sleep 10
|
sleep 10
|
||||||
|
|
||||||
# Now we can launch the background worker process
|
# Now we can launch the background worker process
|
||||||
python3 manage.py qcluster
|
python3 manage.py qcluster
|
||||||
|
Loading…
x
Reference in New Issue
Block a user