From 307a097ab4685d45bbf7930a728740979b6db986 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 May 2021 00:56:14 +0200 Subject: [PATCH 001/445] adding in url --- InvenTree/part/urls.py | 3 +++ InvenTree/part/views.py | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index c734b7f610..e2b172780a 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -120,6 +120,9 @@ part_urls = [ # Create a new part url(r'^new/?', views.PartCreate.as_view(), name='part-create'), + # Upload a part + url(r'^import/', views.PartImport.as_view(), name='part-upload'), + # Create a new BOM item url(r'^bom/new/?', views.BomItemCreate.as_view(), name='bom-item-create'), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 2fabdb9fc8..d9b0b51693 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -39,6 +39,7 @@ from .models import PartSellPriceBreak from common.models import InvenTreeSetting from company.models import SupplierPart +from common.views import FileManagementFormView import common.settings as inventree_settings @@ -718,6 +719,9 @@ class PartCreate(AjaxCreateView): return initials +class PartImport(FileManagementFormView): + ''' Part: Upload file, match to fields and import parts(using multi-Step form) ''' + class PartNotes(UpdateView): """ View for editing the 'notes' field of a Part object. Presents a live markdown editor. From 8effdffe6f8f43491d5b97e37d6ca3137a997f40 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 May 2021 00:57:18 +0200 Subject: [PATCH 002/445] templates and FileManagement config --- InvenTree/common/files.py | 21 ++++ .../part/import_wizard/match_fields.html | 99 +++++++++++++++++++ .../part/import_wizard/match_references.html | 90 +++++++++++++++++ .../part/import_wizard/part_upload.html | 61 ++++++++++++ InvenTree/part/views.py | 25 +++++ 5 files changed, 296 insertions(+) create mode 100644 InvenTree/part/templates/part/import_wizard/match_fields.html create mode 100644 InvenTree/part/templates/part/import_wizard/match_references.html create mode 100644 InvenTree/part/templates/part/import_wizard/part_upload.html diff --git a/InvenTree/common/files.py b/InvenTree/common/files.py index 377120f44d..759ff04ee7 100644 --- a/InvenTree/common/files.py +++ b/InvenTree/common/files.py @@ -109,6 +109,27 @@ class FileManager: # Update headers self.update_headers() + if self.name == 'part': + self.REQUIRED_HEADERS = [ + 'Name', + 'Description', + ] + + self.OPTIONAL_HEADERS = [ + 'Keywords', + 'IPN', + 'Revision', + 'Link', + 'default_expiry', + 'minimum_stock', + 'Units', + 'Notes', + ] + + # Update headers + self.update_headers() + + def guess_header(self, header, threshold=80): """ Try to match a header (from the file) to a list of known headers diff --git a/InvenTree/part/templates/part/import_wizard/match_fields.html b/InvenTree/part/templates/part/import_wizard/match_fields.html new file mode 100644 index 0000000000..54008d6bae --- /dev/null +++ b/InvenTree/part/templates/part/import_wizard/match_fields.html @@ -0,0 +1,99 @@ +{% extends "part/import_wizard/part_upload.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} + +{% block form_alert %} +{% if missing_columns and missing_columns|length > 0 %} + +{% endif %} +{% if duplicates and duplicates|length > 0 %} + +{% endif %} +{% endblock form_alert %} + +{% block form_buttons_top %} + {% if wizard.steps.prev %} + + {% endif %} + +{% endblock form_buttons_top %} + +{% block form_content %} + + + {% trans "File Fields" %} + + {% for col in form %} + +
+ + {{ col.name }} + +
+ + {% endfor %} + + + + + {% trans "Match Fields" %} + + {% for col in form %} + + {{ col }} + {% for duplicate in duplicates %} + {% if duplicate == col.name %} + + {% endif %} + {% endfor %} + + {% endfor %} + + {% for row in rows %} + {% with forloop.counter as row_index %} + + + + + {{ row_index }} + {% for item in row.data %} + + + {{ item }} + + {% endfor %} + + {% endwith %} + {% endfor %} + +{% endblock form_content %} + +{% block form_buttons_bottom %} +{% endblock form_buttons_bottom %} + +{% block js_ready %} +{{ block.super }} + +$('.fieldselect').select2({ + width: '100%', + matcher: partialMatcher, +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/import_wizard/match_references.html b/InvenTree/part/templates/part/import_wizard/match_references.html new file mode 100644 index 0000000000..efc69b98d5 --- /dev/null +++ b/InvenTree/part/templates/part/import_wizard/match_references.html @@ -0,0 +1,90 @@ +{% extends "part/import_wizard/part_upload.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} + +{% block form_alert %} +{% if form.errors %} +{% endif %} +{% if form_errors %} + +{% endif %} +{% endblock form_alert %} + +{% block form_buttons_top %} + {% if wizard.steps.prev %} + + {% endif %} + +{% endblock form_buttons_top %} + +{% block form_content %} + + + + {% trans "Row" %} + {% for col in columns %} + + + + + {% if col.guess %} + {{ col.guess }} + {% else %} + {{ col.name }} + {% endif %} + + {% endfor %} + + + + {% comment %} Dummy row for javascript del_row method {% endcomment %} + {% for row in rows %} + + + + + + {% add row.index 1 %} + + {% for item in row.data %} + + {% if item.column.guess %} + {% with row_name=item.column.guess|lower %} + {% for field in form.visible_fields %} + {% if field.name == row|keyvalue:row_name %} + {{ field }} + {% endif %} + {% endfor %} + {% endwith %} + {% else %} + {{ item.cell }} + {% endif %} + + + {% endfor %} + + {% endfor %} + +{% endblock form_content %} + +{% block form_buttons_bottom %} +{% endblock form_buttons_bottom %} + +{% block js_ready %} +{{ block.super }} + +$('.bomselect').select2({ + dropdownAutoWidth: true, + matcher: partialMatcher, +}); + +$('.currencyselect').select2({ + dropdownAutoWidth: true, +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/import_wizard/part_upload.html b/InvenTree/part/templates/part/import_wizard/part_upload.html new file mode 100644 index 0000000000..87809603bb --- /dev/null +++ b/InvenTree/part/templates/part/import_wizard/part_upload.html @@ -0,0 +1,61 @@ +{% extends "part/category.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} + +{% block menubar %} +{% include 'part/category_navbar.html' with tab='import' %} +{% endblock %} + +{% block category_content %} +
+
+

+ {% trans "Import Parts from File" %} + {{ wizard.form.media }} +

+
+
+ {% if roles.part.change %} + +

{% blocktrans with step=wizard.steps.step1 count=wizard.steps.count %}Step {{step}} of {{count}}{% endblocktrans %} + {% if description %}- {{ description }}{% endif %}

+ + {% block form_alert %} + {% endblock form_alert %} + +
+ {% csrf_token %} + {% load crispy_forms_tags %} + + {% block form_buttons_top %} + {% endblock form_buttons_top %} + + + {{ wizard.management_form }} + {% block form_content %} + {% crispy wizard.form %} + {% endblock form_content %} +
+ + {% block form_buttons_bottom %} + {% if wizard.steps.prev %} + + {% endif %} + +
+ {% endblock form_buttons_bottom %} + + {% else %} + + {% endif %} +
+
+{% endblock %} + +{% block js_ready %} +{{ block.super }} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index d9b0b51693..1e19387e81 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -722,6 +722,31 @@ class PartCreate(AjaxCreateView): class PartImport(FileManagementFormView): ''' Part: Upload file, match to fields and import parts(using multi-Step form) ''' + name = 'part' + form_steps_template = [ + 'part/import_wizard/part_upload.html', + 'part/import_wizard/match_fields.html', + 'part/import_wizard/match_references.html', + ] + form_steps_description = [ + _("Upload File"), + _("Match Fields"), + _("Match References"), + ] + + form_field_map = { + 'name': 'name', + 'description': 'description', + 'keywords': 'keywords', + 'IPN': 'IPN', + 'revision': 'revision', + 'link': 'link', + 'default_expiry': 'default_expiry', + 'minimum_stock': 'minimum_stock', + 'units': 'units', + 'notes': 'notes', + } + class PartNotes(UpdateView): """ View for editing the 'notes' field of a Part object. Presents a live markdown editor. From 4ae7debb2b7f61fbe9c75bdafea630d6b7911a04 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 May 2021 00:57:38 +0200 Subject: [PATCH 003/445] navigation --- InvenTree/part/templates/part/category_navbar.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/InvenTree/part/templates/part/category_navbar.html b/InvenTree/part/templates/part/category_navbar.html index e723db358d..e5fb13bbda 100644 --- a/InvenTree/part/templates/part/category_navbar.html +++ b/InvenTree/part/templates/part/category_navbar.html @@ -30,6 +30,13 @@ +
  • + + + {% trans "Upload File" %} + +
  • + {% if category %}
  • From 0c5fa5777029588db382dbceef018e19ecd504ca Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 May 2021 00:58:03 +0200 Subject: [PATCH 004/445] template tag for dict-reading --- InvenTree/part/templatetags/inventree_extras.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py index 2c588a81e5..6ac34f9d5e 100644 --- a/InvenTree/part/templatetags/inventree_extras.py +++ b/InvenTree/part/templatetags/inventree_extras.py @@ -162,6 +162,11 @@ def get_color_theme_css(username): return inventree_css_static_url +@register.filter +def keyvalue(dict, key): + return dict[key] + + @register.simple_tag() def authorized_owners(group): """ Return authorized owners """ From f136f90e129b3fb44bc98d96927a9835367c174f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 May 2021 00:59:47 +0200 Subject: [PATCH 005/445] config for all form-fields --- InvenTree/common/forms.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/InvenTree/common/forms.py b/InvenTree/common/forms.py index 8a0017e38b..c869d4a4f3 100644 --- a/InvenTree/common/forms.py +++ b/InvenTree/common/forms.py @@ -151,6 +151,8 @@ class MatchItem(forms.Form): # Set field name field_name = col_guess.lower() + '-' + str(row['index']) # Set field input box + + # TODO maybe not here but in an own function? if 'quantity' in col_guess.lower(): self.fields[field_name] = forms.CharField( required=False, @@ -164,6 +166,15 @@ class MatchItem(forms.Form): }) ) + else: + # Get value + value = row.get(col_guess.lower(), '') + # Set field input box + self.fields[field_name] = forms.CharField( + required=True, + initial=value, + ) + # Create item selection box elif col_guess in file_manager.ITEM_MATCH_HEADERS: # Get item options From 888154e30bd46ef6a052b92050298a7644081d02 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 May 2021 01:01:57 +0200 Subject: [PATCH 006/445] added todo for cleaner implemention --- InvenTree/common/files.py | 1 + 1 file changed, 1 insertion(+) diff --git a/InvenTree/common/files.py b/InvenTree/common/files.py index 759ff04ee7..c4b40e1e2b 100644 --- a/InvenTree/common/files.py +++ b/InvenTree/common/files.py @@ -109,6 +109,7 @@ class FileManager: # Update headers self.update_headers() + # TODO maybe not here but in an own function? if self.name == 'part': self.REQUIRED_HEADERS = [ 'Name', From f1f75b45cbc3c9b90718bdc176040f5ccd665dc5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 May 2021 01:02:25 +0200 Subject: [PATCH 007/445] using messages for alerts --- InvenTree/InvenTree/settings.py | 7 +++++++ InvenTree/part/templates/part/category.html | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 7ff90fc7c3..3f9c2d6cec 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -21,6 +21,7 @@ from datetime import datetime import yaml from django.utils.translation import gettext_lazy as _ +from django.contrib.messages import constants as messages def _is_true(x): @@ -593,3 +594,9 @@ IMPORT_EXPORT_USE_TRANSACTIONS = True INTERNAL_IPS = [ '127.0.0.1', ] + +MESSAGE_TAGS = { + messages.SUCCESS: 'alert alert-block alert-success', + messages.ERROR: 'alert alert-block alert-danger', + messages.INFO: 'alert alert-block alert-info', +} diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html index b79ee0ee60..0b7fbba8f5 100644 --- a/InvenTree/part/templates/part/category.html +++ b/InvenTree/part/templates/part/category.html @@ -8,6 +8,15 @@ {% block content %} +{% if messages %} + {% for message in messages %} +
    + {{ message|safe }} +
    + {% endfor %} +{% endif %} + +
    From 437e75c598df179a4249745be34f46b3d1e83f09 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 May 2021 01:09:29 +0200 Subject: [PATCH 008/445] form functions --- InvenTree/part/views.py | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 1e19387e81..7c1f1d0325 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -747,6 +747,51 @@ class PartImport(FileManagementFormView): 'notes': 'notes', } + def get_field_selection(self): + """ Fill the form fields for step 3 """ + + # collect reference indexes + idx_s = {} + for col in self.file_manager.HEADERS: + index = self.get_column_index(col) + if index >= 0: + idx_s[col] = index + + for row in self.rows: + for idx in idx_s: + data = row['data'][idx_s[idx]]['cell'] + row[idx.lower()] = data + + + def done(self, form_list, **kwargs): + """ Create items """ + items = {} + + for form_key, form_value in self.get_all_cleaned_data().items(): + # Split key from row value + try: + (field, idx) = form_key.split('-') + except ValueError: + continue + + try: + if idx not in items: + # Insert into items + items.update({ + idx: { + self.form_field_map[field]: form_value, + } + }) + else: + # Update items + items[idx][self.form_field_map[field]] = form_value + except KeyError: + pass + + + return HttpResponseRedirect(reverse('part-index')) + + class PartNotes(UpdateView): """ View for editing the 'notes' field of a Part object. Presents a live markdown editor. From 6c2e18dd7a31da3dead3f88ea3431bfe5fd9d068 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 May 2021 01:09:50 +0200 Subject: [PATCH 009/445] part creation + alerts --- InvenTree/part/views.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 7c1f1d0325..3170a48c16 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -17,6 +17,7 @@ from django.views.generic import DetailView, ListView, FormView, UpdateView from django.forms.models import model_to_dict from django.forms import HiddenInput, CheckboxInput from django.conf import settings +from django.contrib import messages from moneyed import CURRENCIES @@ -788,6 +789,36 @@ class PartImport(FileManagementFormView): except KeyError: pass + import_done = 0 + import_error = [] + + # Create Part instances + for part_data in items.values(): + new_part = Part( + name=part_data.get('name', ''), + description=part_data.get('description', ''), + keywords=part_data.get('keywords', None), + IPN=part_data.get('ipn', None), + revision=part_data.get('revision', None), + link=part_data.get('link', None), + default_expiry=part_data.get('default_expiry', 0), + minimum_stock=part_data.get('minimum_stock', 0), + units=part_data.get('units', None), + notes=part_data.get('notes', None), + ) + try: + new_part.save() + import_done += 1 + except ValidationError as _e: + import_error.append(', '.join(set(_e.messages))) + + # Set alerts + if import_done: + alert = f"{_('Part-Import')}
    {_('Imported {n} parts').format(n=import_done)}" + messages.success(self.request, alert) + if import_error: + error_text = '\n'.join([f'
  • x{import_error.count(a)}: {a}
  • ' for a in set(import_error)]) + messages.error(self.request, f"{_('Some errors occured:')}
      {error_text}
    ") return HttpResponseRedirect(reverse('part-index')) From 27ed20c1239f08cb356abd187ae30954f8ac099d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 May 2021 08:36:08 +0200 Subject: [PATCH 010/445] fix for wrong mapping --- InvenTree/part/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 3170a48c16..89eaca25c4 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -739,7 +739,7 @@ class PartImport(FileManagementFormView): 'name': 'name', 'description': 'description', 'keywords': 'keywords', - 'IPN': 'IPN', + 'ipn': 'ipn', 'revision': 'revision', 'link': 'link', 'default_expiry': 'default_expiry', From 941ac25d53350be3995e40fc04bae420a74fb00b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 May 2021 08:45:01 +0200 Subject: [PATCH 011/445] style fixes --- InvenTree/common/files.py | 1 - InvenTree/part/views.py | 1 - 2 files changed, 2 deletions(-) diff --git a/InvenTree/common/files.py b/InvenTree/common/files.py index c4b40e1e2b..9c4e7c039c 100644 --- a/InvenTree/common/files.py +++ b/InvenTree/common/files.py @@ -130,7 +130,6 @@ class FileManager: # Update headers self.update_headers() - def guess_header(self, header, threshold=80): """ Try to match a header (from the file) to a list of known headers diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 89eaca25c4..ac2749a612 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -763,7 +763,6 @@ class PartImport(FileManagementFormView): data = row['data'][idx_s[idx]]['cell'] row[idx.lower()] = data - def done(self, form_list, **kwargs): """ Create items """ items = {} From 90ae2813870588fcb2f10fb2dfb5baf69c6ac4b0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 16 May 2021 15:50:13 +0200 Subject: [PATCH 012/445] adding in optional headers --- InvenTree/common/files.py | 6 ++++-- InvenTree/common/forms.py | 21 +++++++++++++++++++++ InvenTree/part/views.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/InvenTree/common/files.py b/InvenTree/common/files.py index 9c4e7c039c..62f6426ef7 100644 --- a/InvenTree/common/files.py +++ b/InvenTree/common/files.py @@ -26,6 +26,8 @@ class FileManager: # Fields which would be helpful but are not required OPTIONAL_HEADERS = [] + OPTIONAL_MATCH_HEADERS = [] + EDITABLE_HEADERS = [] HEADERS = [] @@ -82,8 +84,8 @@ class FileManager: def update_headers(self): """ Update headers """ - self.HEADERS = self.REQUIRED_HEADERS + self.ITEM_MATCH_HEADERS + self.OPTIONAL_HEADERS - + self.HEADERS = self.REQUIRED_HEADERS + self.ITEM_MATCH_HEADERS + self.OPTIONAL_MATCH_HEADERS + self.OPTIONAL_HEADERS + def setup(self): """ Setup headers depending on the file name """ diff --git a/InvenTree/common/forms.py b/InvenTree/common/forms.py index c869d4a4f3..e166d235d8 100644 --- a/InvenTree/common/forms.py +++ b/InvenTree/common/forms.py @@ -220,3 +220,24 @@ class MatchItem(forms.Form): required=False, initial=value, ) + + # Optional item selection box + elif col_guess in file_manager.OPTIONAL_MATCH_HEADERS: + # Get item options + item_options = [(option.id, option) for option in row['match_options_' + col_guess]] + # Get item match + item_match = row['match_' + col_guess] + # Set field name + field_name = col_guess.lower() + '-' + str(row['index']) + # Set field select box + self.fields[field_name] = forms.ChoiceField( + choices=[('', '-' * 10)] + item_options, + required=False, + widget=forms.Select(attrs={ + 'class': 'select bomselect', + }) + ) + # Update select box when match was found + if item_match: + # Update initial value + self.fields[field_name].initial = item_match.id diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index ac2749a612..23799e4fec 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -751,6 +751,7 @@ class PartImport(FileManagementFormView): def get_field_selection(self): """ Fill the form fields for step 3 """ + self.file_manager.setup() # collect reference indexes idx_s = {} for col in self.file_manager.HEADERS: @@ -758,9 +759,24 @@ class PartImport(FileManagementFormView): if index >= 0: idx_s[col] = index + # fetch available elements + self.allowed_items = {} + self.matches = {} for row in self.rows: for idx in idx_s: data = row['data'][idx_s[idx]]['cell'] + + if idx in self.file_manager.OPTIONAL_MATCH_HEADERS: + try: + exact_match = self.allowed_items[idx].get(**{a:data for a in self.matches[idx]}) + except (ValueError, self.allowed_items[idx].model.DoesNotExist, self.allowed_items[idx].model.MultipleObjectsReturned): + exact_match = None + + row['match_options_' + idx] = self.allowed_items[idx] + row['match_' + idx] = exact_match + continue + + # general fields row[idx.lower()] = data def done(self, form_list, **kwargs): @@ -793,6 +809,19 @@ class PartImport(FileManagementFormView): # Create Part instances for part_data in items.values(): + + # set related parts + optional_matches = {} + for idx in self.file_manager.OPTIONAL_MATCH_HEADERS: + if idx.lower() in part_data: + try: + optional_matches[idx] = self.allowed_items[idx].get(pk=int(part_data[idx.lower()])) + except (ValueError, self.allowed_items[idx].model.DoesNotExist, self.allowed_items[idx].model.MultipleObjectsReturned): + optional_matches[idx] = None + else: + optional_matches[idx] = None + + # add part new_part = Part( name=part_data.get('name', ''), description=part_data.get('description', ''), From 8168db806180f71541fa845fee9fac868acab13d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 16 May 2021 15:57:57 +0200 Subject: [PATCH 013/445] implementation for part import --- InvenTree/common/files.py | 6 ++++++ InvenTree/part/views.py | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/InvenTree/common/files.py b/InvenTree/common/files.py index 62f6426ef7..94f96f42e5 100644 --- a/InvenTree/common/files.py +++ b/InvenTree/common/files.py @@ -118,6 +118,12 @@ class FileManager: 'Description', ] + self.OPTIONAL_MATCH_HEADERS = [ + 'Category', + 'default_location', + 'default_supplier', + ] + self.OPTIONAL_HEADERS = [ 'Keywords', 'IPN', diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 23799e4fec..75ab43ef81 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -42,6 +42,8 @@ from common.models import InvenTreeSetting from company.models import SupplierPart from common.views import FileManagementFormView +from stock.models import StockLocation + import common.settings as inventree_settings from . import forms as part_forms @@ -746,6 +748,9 @@ class PartImport(FileManagementFormView): 'minimum_stock': 'minimum_stock', 'units': 'units', 'notes': 'notes', + 'category': 'category', + 'default_location': 'default_location', + 'default_supplier': 'default_supplier', } def get_field_selection(self): @@ -762,6 +767,14 @@ class PartImport(FileManagementFormView): # fetch available elements self.allowed_items = {} self.matches = {} + + self.allowed_items['Category'] = PartCategory.objects.all() + self.matches['Category'] = ['name__contains'] + self.allowed_items['default_location'] = StockLocation.objects.all() + self.matches['default_location'] = ['name__contains'] + self.allowed_items['default_supplier'] = SupplierPart.objects.all() + self.matches['default_supplier'] = ['SKU__contains'] + for row in self.rows: for idx in idx_s: data = row['data'][idx_s[idx]]['cell'] @@ -833,6 +846,9 @@ class PartImport(FileManagementFormView): minimum_stock=part_data.get('minimum_stock', 0), units=part_data.get('units', None), notes=part_data.get('notes', None), + category=optional_matches['Category'], + default_location=optional_matches['default_location'], + default_supplier=optional_matches['default_supplier'], ) try: new_part.save() From b9c73b1e603d4fe7e6f882bf670a8411df244b2d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 16 May 2021 15:58:35 +0200 Subject: [PATCH 014/445] simpler code --- InvenTree/common/forms.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/InvenTree/common/forms.py b/InvenTree/common/forms.py index e166d235d8..0c91dcfeea 100644 --- a/InvenTree/common/forms.py +++ b/InvenTree/common/forms.py @@ -145,11 +145,11 @@ class MatchItem(forms.Form): for col in row['data']: # Get column matching col_guess = col['column'].get('guess', None) + # Set field name + field_name = col_guess.lower() + '-' + str(row['index']) # Create input for required headers if col_guess in file_manager.REQUIRED_HEADERS: - # Set field name - field_name = col_guess.lower() + '-' + str(row['index']) # Set field input box # TODO maybe not here but in an own function? @@ -201,8 +201,6 @@ class MatchItem(forms.Form): # Optional entries elif col_guess in file_manager.OPTIONAL_HEADERS: - # Set field name - field_name = col_guess.lower() + '-' + str(row['index']) # Get value value = row.get(col_guess.lower(), '') # Set field input box @@ -227,8 +225,6 @@ class MatchItem(forms.Form): item_options = [(option.id, option) for option in row['match_options_' + col_guess]] # Get item match item_match = row['match_' + col_guess] - # Set field name - field_name = col_guess.lower() + '-' + str(row['index']) # Set field select box self.fields[field_name] = forms.ChoiceField( choices=[('', '-' * 10)] + item_options, From 3a5b4ab74b6979a583ccd16323e40f895efe4298 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 16 May 2021 16:00:02 +0200 Subject: [PATCH 015/445] crispy forms for FileManagementFormView --- InvenTree/common/views.py | 10 ++++++++++ .../templates/order/order_wizard/match_parts.html | 9 +++++---- .../templates/part/import_wizard/match_references.html | 3 ++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/InvenTree/common/views.py b/InvenTree/common/views.py index fa605c2b80..0b2eda794e 100644 --- a/InvenTree/common/views.py +++ b/InvenTree/common/views.py @@ -13,6 +13,7 @@ from django.conf import settings from django.core.files.storage import FileSystemStorage from formtools.wizard.views import SessionWizardView +from crispy_forms.helper import FormHelper from InvenTree.views import AjaxUpdateView from InvenTree.helpers import str2bool @@ -269,6 +270,15 @@ class FileManagementFormView(MultiStepFormView): return super().get_form_kwargs() + def get_form(self, step=None, data=None, files=None): + """ add crispy-form helper to form """ + form = super().get_form(step=step, data=data, files=files) + + form.helper = FormHelper() + form.helper.form_show_labels = False + + return form + def get_form_table_data(self, form_data): """ Extract table cell data from form data and fields. These data are used to maintain state between sessions. diff --git a/InvenTree/order/templates/order/order_wizard/match_parts.html b/InvenTree/order/templates/order/order_wizard/match_parts.html index f97edff913..e0f030bad5 100644 --- a/InvenTree/order/templates/order/order_wizard/match_parts.html +++ b/InvenTree/order/templates/order/order_wizard/match_parts.html @@ -2,6 +2,7 @@ {% load inventree_extras %} {% load i18n %} {% load static %} +{% load crispy_forms_tags %} {% block form_alert %} {% if form.errors %} @@ -67,7 +68,7 @@ {% for field in form.visible_fields %} {% if field.name == row.quantity %} - {{ field }} + {{ field|as_crispy_field }} {% endif %} {% endfor %} {% if row.errors.quantity %} @@ -80,19 +81,19 @@ {% if item.column.guess == 'Purchase_Price' %} {% for field in form.visible_fields %} {% if field.name == row.purchase_price %} - {{ field }} + {{ field|as_crispy_field }} {% endif %} {% endfor %} {% elif item.column.guess == 'Reference' %} {% for field in form.visible_fields %} {% if field.name == row.reference %} - {{ field }} + {{ field|as_crispy_field }} {% endif %} {% endfor %} {% elif item.column.guess == 'Notes' %} {% for field in form.visible_fields %} {% if field.name == row.notes %} - {{ field }} + {{ field|as_crispy_field }} {% endif %} {% endfor %} {% else %} diff --git a/InvenTree/part/templates/part/import_wizard/match_references.html b/InvenTree/part/templates/part/import_wizard/match_references.html index efc69b98d5..99b9ccd191 100644 --- a/InvenTree/part/templates/part/import_wizard/match_references.html +++ b/InvenTree/part/templates/part/import_wizard/match_references.html @@ -2,6 +2,7 @@ {% load inventree_extras %} {% load i18n %} {% load static %} +{% load crispy_forms_tags %} {% block form_alert %} {% if form.errors %} @@ -57,7 +58,7 @@ {% with row_name=item.column.guess|lower %} {% for field in form.visible_fields %} {% if field.name == row|keyvalue:row_name %} - {{ field }} + {{ field|as_crispy_field }} {% endif %} {% endfor %} {% endwith %} From 508099e536360184f269bcd45b601f7598f168e9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 16 May 2021 19:53:01 +0200 Subject: [PATCH 016/445] style fixing --- InvenTree/common/views.py | 2 +- InvenTree/part/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/common/views.py b/InvenTree/common/views.py index 0b2eda794e..6018f64cef 100644 --- a/InvenTree/common/views.py +++ b/InvenTree/common/views.py @@ -275,7 +275,7 @@ class FileManagementFormView(MultiStepFormView): form = super().get_form(step=step, data=data, files=files) form.helper = FormHelper() - form.helper.form_show_labels = False + form.helper.form_show_labels = False return form diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 75ab43ef81..266b31ada7 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -781,7 +781,7 @@ class PartImport(FileManagementFormView): if idx in self.file_manager.OPTIONAL_MATCH_HEADERS: try: - exact_match = self.allowed_items[idx].get(**{a:data for a in self.matches[idx]}) + exact_match = self.allowed_items[idx].get(**{a: data for a in self.matches[idx]}) except (ValueError, self.allowed_items[idx].model.DoesNotExist, self.allowed_items[idx].model.MultipleObjectsReturned): exact_match = None From eafaf92ae272691839cdd487f40bf9174db43941 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 May 2021 01:02:31 +0200 Subject: [PATCH 017/445] unified naming schema --- InvenTree/part/templates/part/category_navbar.html | 6 +++--- InvenTree/part/urls.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/InvenTree/part/templates/part/category_navbar.html b/InvenTree/part/templates/part/category_navbar.html index e5fb13bbda..e2cbaf55db 100644 --- a/InvenTree/part/templates/part/category_navbar.html +++ b/InvenTree/part/templates/part/category_navbar.html @@ -30,10 +30,10 @@
    -
  • - +
  • + - {% trans "Upload File" %} + {% trans "Import Parts" %}
  • diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index e2b172780a..131797ea03 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -121,7 +121,7 @@ part_urls = [ url(r'^new/?', views.PartCreate.as_view(), name='part-create'), # Upload a part - url(r'^import/', views.PartImport.as_view(), name='part-upload'), + url(r'^import/', views.PartImport.as_view(), name='part-import'), # Create a new BOM item url(r'^bom/new/?', views.BomItemCreate.as_view(), name='bom-item-create'), From 92f8bd36f1eb962ead461de29ac87e6a8d9cd282 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 May 2021 01:55:47 +0200 Subject: [PATCH 018/445] inherited setup method --- InvenTree/common/files.py | 52 +++++---------------------------------- InvenTree/common/views.py | 11 ++++++++- InvenTree/order/views.py | 21 ++++++++++++++++ InvenTree/part/views.py | 28 +++++++++++++++++++++ 4 files changed, 65 insertions(+), 47 deletions(-) diff --git a/InvenTree/common/files.py b/InvenTree/common/files.py index 94f96f42e5..52e461c9c7 100644 --- a/InvenTree/common/files.py +++ b/InvenTree/common/files.py @@ -87,56 +87,16 @@ class FileManager: self.HEADERS = self.REQUIRED_HEADERS + self.ITEM_MATCH_HEADERS + self.OPTIONAL_MATCH_HEADERS + self.OPTIONAL_HEADERS def setup(self): - """ Setup headers depending on the file name """ + """ + Setup headers + should be overriden in usage to set the Different Headers + """ if not self.name: return - if self.name == 'order': - self.REQUIRED_HEADERS = [ - 'Quantity', - ] - - self.ITEM_MATCH_HEADERS = [ - 'Manufacturer_MPN', - 'Supplier_SKU', - ] - - self.OPTIONAL_HEADERS = [ - 'Purchase_Price', - 'Reference', - 'Notes', - ] - - # Update headers - self.update_headers() - - # TODO maybe not here but in an own function? - if self.name == 'part': - self.REQUIRED_HEADERS = [ - 'Name', - 'Description', - ] - - self.OPTIONAL_MATCH_HEADERS = [ - 'Category', - 'default_location', - 'default_supplier', - ] - - self.OPTIONAL_HEADERS = [ - 'Keywords', - 'IPN', - 'Revision', - 'Link', - 'default_expiry', - 'minimum_stock', - 'Units', - 'Notes', - ] - - # Update headers - self.update_headers() + # Update headers + self.update_headers() def guess_header(self, header, threshold=80): """ Try to match a header (from the file) to a list of known headers diff --git a/InvenTree/common/views.py b/InvenTree/common/views.py index 669a5e8212..72a8d7fb1a 100644 --- a/InvenTree/common/views.py +++ b/InvenTree/common/views.py @@ -189,6 +189,15 @@ class FileManagementFormView(MultiStepFormView): media_folder = 'file_upload/' extra_context_data = {} + def __init__(self, *args, **kwargs): + """ initialize the FormView """ + # perform all checks and inits from MultiStepFormView + super().__init__(*args, **kwargs) + + # Check + if not(hasattr(self, 'file_manager_class') and issubclass(self.file_manager_class, FileManager)): + raise NotImplementedError('A subclass of a file manager class needs to be set!') + def get_context_data(self, form, **kwargs): context = super().get_context_data(form=form, **kwargs) @@ -228,7 +237,7 @@ class FileManagementFormView(MultiStepFormView): # Get file file = upload_files.get('upload-file', None) if file: - self.file_manager = FileManager(file=file, name=self.name) + self.file_manager = self.file_manager_class(file=file, name=self.name) def get_form_kwargs(self, step=None): """ Update kwargs to dynamically build forms """ diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index c8ec42d3e7..bbda2f1716 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -31,6 +31,7 @@ from part.models import Part from common.models import InvenTreeSetting from common.views import FileManagementFormView +from common.files import FileManager from . import forms as order_forms from part.views import PartPricing @@ -591,6 +592,26 @@ class PurchaseOrderUpload(FileManagementFormView): 'reference': 'reference', 'notes': 'notes', } + class MyManger(FileManager): + def setup(self): + self.REQUIRED_HEADERS = [ + 'Quantity', + ] + + self.ITEM_MATCH_HEADERS = [ + 'Manufacturer_MPN', + 'Supplier_SKU', + ] + + self.OPTIONAL_HEADERS = [ + 'Purchase_Price', + 'Reference', + 'Notes', + ] + + return super().setup() + + file_manager_class = MyManger def get_order(self): """ Get order or return 404 """ diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 266b31ada7..d3c32bebca 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -40,6 +40,7 @@ from .models import PartSellPriceBreak from common.models import InvenTreeSetting from company.models import SupplierPart +from common.files import FileManager from common.views import FileManagementFormView from stock.models import StockLocation @@ -752,6 +753,33 @@ class PartImport(FileManagementFormView): 'default_location': 'default_location', 'default_supplier': 'default_supplier', } + class MyManger(FileManager): + def setup(self): + self.REQUIRED_HEADERS = [ + 'Name', + 'Description', + ] + + self.OPTIONAL_MATCH_HEADERS = [ + 'Category', + 'default_location', + 'default_supplier', + ] + + self.OPTIONAL_HEADERS = [ + 'Keywords', + 'IPN', + 'Revision', + 'Link', + 'default_expiry', + 'minimum_stock', + 'Units', + 'Notes', + ] + + return super().setup() + + file_manager_class = MyManger def get_field_selection(self): """ Fill the form fields for step 3 """ From cb0ef30effafd7bf9319ae3bae3f1af2e2163b2e Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 May 2021 10:17:19 +0200 Subject: [PATCH 019/445] form overrides --- InvenTree/common/views.py | 21 +++++++++++++++++++-- InvenTree/order/views.py | 11 ++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/InvenTree/common/views.py b/InvenTree/common/views.py index 72a8d7fb1a..b645d16651 100644 --- a/InvenTree/common/views.py +++ b/InvenTree/common/views.py @@ -191,10 +191,27 @@ class FileManagementFormView(MultiStepFormView): def __init__(self, *args, **kwargs): """ initialize the FormView """ - # perform all checks and inits from MultiStepFormView + # check if form_list should be overriden + if hasattr(self, 'form_list_override'): + # check for list + if not isinstance(self.form_list_override, list): + raise ValueError('form_list_override must be a list') + + # loop through and override /add form_list enrties + for entry in self.form_list_override: + # fetch postition + pos = [self.form_list.index(i) for i in self.form_list if i[0] == 'items'] + # replace if exists + if pos: + self.form_list[pos[0]] = entry + # or append + else: + self.form_list.append(entry) + + # perform all checks and inits for MultiStepFormView super().__init__(*args, **kwargs) - # Check + # Check for file manager class if not(hasattr(self, 'file_manager_class') and issubclass(self.file_manager_class, FileManager)): raise NotImplementedError('A subclass of a file manager class needs to be set!') diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index bbda2f1716..2cb7263269 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -32,6 +32,7 @@ from part.models import Part from common.models import InvenTreeSetting from common.views import FileManagementFormView from common.files import FileManager +from common import forms as cm_forms from . import forms as order_forms from part.views import PartPricing @@ -573,7 +574,16 @@ class SalesOrderShip(AjaxUpdateView): class PurchaseOrderUpload(FileManagementFormView): ''' PurchaseOrder: Upload file, match to fields and parts (using multi-Step form) ''' + class MyMatch(cm_forms.MatchItem): + """ override MatchItem fields """ + def get_special_field(self, col_guess, row, file_manager): + """ set special field """ + # run default + super().get_special_field(col_guess, row, file_manager) name = 'order' + form_list_override = [ + ('items', MyMatch), + ] form_steps_template = [ 'order/order_wizard/po_upload.html', 'order/order_wizard/match_fields.html', @@ -584,7 +594,6 @@ class PurchaseOrderUpload(FileManagementFormView): _("Match Fields"), _("Match Supplier Parts"), ] - # Form field name: PurchaseOrderLineItem field form_field_map = { 'item_select': 'part', 'quantity': 'quantity', From ad4902ea44e63436c9d9080ae42354646503917c Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 May 2021 10:19:35 +0200 Subject: [PATCH 020/445] restucture --- InvenTree/common/forms.py | 90 +++++++++++++++------------------------ InvenTree/order/views.py | 31 +++++++++++++- 2 files changed, 65 insertions(+), 56 deletions(-) diff --git a/InvenTree/common/forms.py b/InvenTree/common/forms.py index 0c91dcfeea..3ce83ac72f 100644 --- a/InvenTree/common/forms.py +++ b/InvenTree/common/forms.py @@ -10,8 +10,6 @@ from decimal import Decimal, InvalidOperation from django import forms from django.utils.translation import gettext as _ -from djmoney.forms.fields import MoneyField - from InvenTree.forms import HelperForm from .files import FileManager @@ -119,21 +117,6 @@ class MatchItem(forms.Form): super().__init__(*args, **kwargs) - def clean(number): - """ Clean-up decimal value """ - - # Check if empty - if not number: - return number - - # Check if decimal type - try: - clean_number = Decimal(number) - except InvalidOperation: - clean_number = number - - return clean_number.quantize(Decimal(1)) if clean_number == clean_number.to_integral() else clean_number.normalize() - # Setup FileManager file_manager.setup() @@ -148,32 +131,20 @@ class MatchItem(forms.Form): # Set field name field_name = col_guess.lower() + '-' + str(row['index']) + # check if field def was overriden + overriden_field = self.get_special_field(col_guess, row, file_manager) + if overriden_field: + self.fields[field_name] = overriden_field + # Create input for required headers - if col_guess in file_manager.REQUIRED_HEADERS: + elif col_guess in file_manager.REQUIRED_HEADERS: + # Get value + value = row.get(col_guess.lower(), '') # Set field input box - - # TODO maybe not here but in an own function? - if 'quantity' in col_guess.lower(): - self.fields[field_name] = forms.CharField( - required=False, - widget=forms.NumberInput(attrs={ - 'name': 'quantity' + str(row['index']), - 'class': 'numberinput', # form-control', - 'type': 'number', - 'min': '0', - 'step': 'any', - 'value': clean(row.get('quantity', '')), - }) - ) - - else: - # Get value - value = row.get(col_guess.lower(), '') - # Set field input box - self.fields[field_name] = forms.CharField( - required=True, - initial=value, - ) + self.fields[field_name] = forms.CharField( + required=True, + initial=value, + ) # Create item selection box elif col_guess in file_manager.ITEM_MATCH_HEADERS: @@ -204,20 +175,10 @@ class MatchItem(forms.Form): # Get value value = row.get(col_guess.lower(), '') # Set field input box - if 'price' in col_guess.lower(): - self.fields[field_name] = MoneyField( - label=_(col_guess), - default_currency=InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY'), - decimal_places=5, - max_digits=19, - required=False, - default_amount=clean(value), - ) - else: - self.fields[field_name] = forms.CharField( - required=False, - initial=value, - ) + self.fields[field_name] = forms.CharField( + required=False, + initial=value, + ) # Optional item selection box elif col_guess in file_manager.OPTIONAL_MATCH_HEADERS: @@ -237,3 +198,22 @@ class MatchItem(forms.Form): if item_match: # Update initial value self.fields[field_name].initial = item_match.id + + def clean_nbr(self, number): + """ Clean-up decimal value """ + + # Check if empty + if not number: + return number + + # Check if decimal type + try: + clean_number = Decimal(number) + except InvalidOperation: + clean_number = number + + return clean_number.quantize(Decimal(1)) if clean_number == clean_number.to_integral() else clean_number.normalize() + + def get_special_field(self, col_guess, row, file_manager): + """ function to be overriden in inherited forms to add specific form settings """ + pass diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 2cb7263269..d89401e3cb 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -15,7 +15,7 @@ from django.http import HttpResponseRedirect from django.utils.translation import ugettext_lazy as _ from django.views.generic import DetailView, ListView, UpdateView from django.views.generic.edit import FormMixin -from django.forms import HiddenInput, IntegerField +from django.forms import HiddenInput, IntegerField, CharField, NumberInput import logging from decimal import Decimal, InvalidOperation @@ -44,6 +44,8 @@ from InvenTree.views import InvenTreeRoleMixin from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus, StockStatus +from djmoney.forms.fields import MoneyField + logger = logging.getLogger("inventree") @@ -580,6 +582,33 @@ class PurchaseOrderUpload(FileManagementFormView): """ set special field """ # run default super().get_special_field(col_guess, row, file_manager) + + # set quantity field + if 'quantity' in col_guess.lower(): + return CharField( + required=False, + widget=NumberInput(attrs={ + 'name': 'quantity' + str(row['index']), + 'class': 'numberinput', + 'type': 'number', + 'min': '0', + 'step': 'any', + 'value': self.clean_nbr(row.get('quantity', '')), + }) + ) + # set price field + elif 'price' in col_guess.lower(): + return MoneyField( + label=_(col_guess), + default_currency=InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY'), + decimal_places=5, + max_digits=19, + required=False, + default_amount=self.clean_nbr(row.get('price', '')), + ) + + + name = 'order' form_list_override = [ ('items', MyMatch), From 64f8846e9901bfc0f849049c7c06e16c5a64772c Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 May 2021 10:47:56 +0200 Subject: [PATCH 021/445] generalising for done() --- InvenTree/common/views.py | 27 +++++++++++++++++++++++++++ InvenTree/order/views.py | 21 +-------------------- InvenTree/part/views.py | 23 +---------------------- 3 files changed, 29 insertions(+), 42 deletions(-) diff --git a/InvenTree/common/views.py b/InvenTree/common/views.py index b645d16651..53909cc0d7 100644 --- a/InvenTree/common/views.py +++ b/InvenTree/common/views.py @@ -450,6 +450,33 @@ class FileManagementFormView(MultiStepFormView): """ pass + def get_clean_items(self): + """ returns dict with all cleaned values """ + items = {} + + for form_key, form_value in self.get_all_cleaned_data().items(): + # Split key from row value + try: + (field, idx) = form_key.split('-') + except ValueError: + continue + + try: + if idx not in items: + # Insert into items + items.update({ + idx: { + self.form_field_map[field]: form_value, + } + }) + else: + # Update items + items[idx][self.form_field_map[field]] = form_value + except KeyError: + pass + + return items + def check_field_selection(self, form): """ Check field matching """ diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index d89401e3cb..3db0d4412f 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -767,26 +767,7 @@ class PurchaseOrderUpload(FileManagementFormView): """ Once all the data is in, process it to add PurchaseOrderLineItem instances to the order """ order = self.get_order() - - items = {} - - for form_key, form_value in self.get_all_cleaned_data().items(): - # Split key from row value - try: - (field, idx) = form_key.split('-') - except ValueError: - continue - - if idx not in items: - # Insert into items - items.update({ - idx: { - self.form_field_map[field]: form_value, - } - }) - else: - # Update items - items[idx][self.form_field_map[field]] = form_value + items = self.get_clean_items() # Create PurchaseOrderLineItem instances for purchase_order_item in items.values(): diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index d3c32bebca..1e5e2153e8 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -822,28 +822,7 @@ class PartImport(FileManagementFormView): def done(self, form_list, **kwargs): """ Create items """ - items = {} - - for form_key, form_value in self.get_all_cleaned_data().items(): - # Split key from row value - try: - (field, idx) = form_key.split('-') - except ValueError: - continue - - try: - if idx not in items: - # Insert into items - items.update({ - idx: { - self.form_field_map[field]: form_value, - } - }) - else: - # Update items - items[idx][self.form_field_map[field]] = form_value - except KeyError: - pass + items = self.get_clean_items() import_done = 0 import_error = [] From db9fd282768f1bacc89a68710b8cae380583b0db Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 May 2021 10:48:29 +0200 Subject: [PATCH 022/445] preparing stuff for gen get_field_selection() --- InvenTree/part/views.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 1e5e2153e8..45a5ad1c2b 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -783,15 +783,6 @@ class PartImport(FileManagementFormView): def get_field_selection(self): """ Fill the form fields for step 3 """ - - self.file_manager.setup() - # collect reference indexes - idx_s = {} - for col in self.file_manager.HEADERS: - index = self.get_column_index(col) - if index >= 0: - idx_s[col] = index - # fetch available elements self.allowed_items = {} self.matches = {} @@ -803,6 +794,15 @@ class PartImport(FileManagementFormView): self.allowed_items['default_supplier'] = SupplierPart.objects.all() self.matches['default_supplier'] = ['SKU__contains'] + # setup + self.file_manager.setup() + # collect reference indexes + idx_s = {} + for col in self.file_manager.HEADERS: + index = self.get_column_index(col) + if index >= 0: + idx_s[col] = index + for row in self.rows: for idx in idx_s: data = row['data'][idx_s[idx]]['cell'] From e49256a2182fe1d1b8e57958c398ce7549688641 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 May 2021 10:52:27 +0200 Subject: [PATCH 023/445] fixed bug pointed out by @eeintech --- InvenTree/part/templates/part/import_wizard/match_fields.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/part/templates/part/import_wizard/match_fields.html b/InvenTree/part/templates/part/import_wizard/match_fields.html index 54008d6bae..ba709bc639 100644 --- a/InvenTree/part/templates/part/import_wizard/match_fields.html +++ b/InvenTree/part/templates/part/import_wizard/match_fields.html @@ -55,7 +55,7 @@ {{ col }} {% for duplicate in duplicates %} - {% if duplicate == col.name %} + {% if duplicate == col.value %} From 616dd76f8ab2ef9993b73ca39d833cd403b0a38d Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 May 2021 11:10:01 +0200 Subject: [PATCH 024/445] refactor and doc --- InvenTree/order/views.py | 39 +++++++++++++++++++-------------------- InvenTree/part/views.py | 12 +++++++----- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 3db0d4412f..9aa9b8d473 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -576,6 +576,7 @@ class SalesOrderShip(AjaxUpdateView): class PurchaseOrderUpload(FileManagementFormView): ''' PurchaseOrder: Upload file, match to fields and parts (using multi-Step form) ''' + # overriden classes class MyMatch(cm_forms.MatchItem): """ override MatchItem fields """ def get_special_field(self, col_guess, row, file_manager): @@ -607,7 +608,24 @@ class PurchaseOrderUpload(FileManagementFormView): default_amount=self.clean_nbr(row.get('price', '')), ) + class MyFileManager(FileManager): + def setup(self): + self.REQUIRED_HEADERS = [ + 'Quantity', + ] + self.ITEM_MATCH_HEADERS = [ + 'Manufacturer_MPN', + 'Supplier_SKU', + ] + + self.OPTIONAL_HEADERS = [ + 'Purchase_Price', + 'Reference', + 'Notes', + ] + + return super().setup() name = 'order' form_list_override = [ @@ -630,26 +648,7 @@ class PurchaseOrderUpload(FileManagementFormView): 'reference': 'reference', 'notes': 'notes', } - class MyManger(FileManager): - def setup(self): - self.REQUIRED_HEADERS = [ - 'Quantity', - ] - - self.ITEM_MATCH_HEADERS = [ - 'Manufacturer_MPN', - 'Supplier_SKU', - ] - - self.OPTIONAL_HEADERS = [ - 'Purchase_Price', - 'Reference', - 'Notes', - ] - - return super().setup() - - file_manager_class = MyManger + file_manager_class = MyFileManager def get_order(self): """ Get order or return 404 """ diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 45a5ad1c2b..65a5cc652d 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -796,16 +796,18 @@ class PartImport(FileManagementFormView): # setup self.file_manager.setup() - # collect reference indexes - idx_s = {} + # collect submitted column indexes + col_ids = {} for col in self.file_manager.HEADERS: index = self.get_column_index(col) if index >= 0: - idx_s[col] = index + col_ids[col] = index + # parse all rows for row in self.rows: - for idx in idx_s: - data = row['data'][idx_s[idx]]['cell'] + # check each submitted column + for idx in col_ids: + data = row['data'][col_ids[idx]]['cell'] if idx in self.file_manager.OPTIONAL_MATCH_HEADERS: try: From dd56bc1fa531eca2a6e703443d9d3540e2eca4aa Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 May 2021 11:18:13 +0200 Subject: [PATCH 025/445] setup not realy needed --- InvenTree/order/views.py | 27 ++++++++++++-------------- InvenTree/part/views.py | 42 ++++++++++++++++++---------------------- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 9aa9b8d473..5d0acb9a7c 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -609,23 +609,20 @@ class PurchaseOrderUpload(FileManagementFormView): ) class MyFileManager(FileManager): - def setup(self): - self.REQUIRED_HEADERS = [ - 'Quantity', - ] + REQUIRED_HEADERS = [ + 'Quantity', + ] - self.ITEM_MATCH_HEADERS = [ - 'Manufacturer_MPN', - 'Supplier_SKU', - ] + ITEM_MATCH_HEADERS = [ + 'Manufacturer_MPN', + 'Supplier_SKU', + ] - self.OPTIONAL_HEADERS = [ - 'Purchase_Price', - 'Reference', - 'Notes', - ] - - return super().setup() + OPTIONAL_HEADERS = [ + 'Purchase_Price', + 'Reference', + 'Notes', + ] name = 'order' form_list_override = [ diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 65a5cc652d..1a792dd0ce 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -754,31 +754,27 @@ class PartImport(FileManagementFormView): 'default_supplier': 'default_supplier', } class MyManger(FileManager): - def setup(self): - self.REQUIRED_HEADERS = [ - 'Name', - 'Description', - ] + REQUIRED_HEADERS = [ + 'Name', + 'Description', + ] - self.OPTIONAL_MATCH_HEADERS = [ - 'Category', - 'default_location', - 'default_supplier', - ] - - self.OPTIONAL_HEADERS = [ - 'Keywords', - 'IPN', - 'Revision', - 'Link', - 'default_expiry', - 'minimum_stock', - 'Units', - 'Notes', - ] - - return super().setup() + OPTIONAL_MATCH_HEADERS = [ + 'Category', + 'default_location', + 'default_supplier', + ] + OPTIONAL_HEADERS = [ + 'Keywords', + 'IPN', + 'Revision', + 'Link', + 'default_expiry', + 'minimum_stock', + 'Units', + 'Notes', + ] file_manager_class = MyManger def get_field_selection(self): From 9a42421852b0fe69264b25cac4a2a598283ceaa4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 May 2021 11:20:25 +0200 Subject: [PATCH 026/445] restructure overrides --- InvenTree/part/views.py | 47 +++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 1a792dd0ce..b9c4d2ec03 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -726,6 +726,29 @@ class PartCreate(AjaxCreateView): class PartImport(FileManagementFormView): ''' Part: Upload file, match to fields and import parts(using multi-Step form) ''' + class MyFileManager(FileManager): + REQUIRED_HEADERS = [ + 'Name', + 'Description', + ] + + OPTIONAL_MATCH_HEADERS = [ + 'Category', + 'default_location', + 'default_supplier', + ] + + OPTIONAL_HEADERS = [ + 'Keywords', + 'IPN', + 'Revision', + 'Link', + 'default_expiry', + 'minimum_stock', + 'Units', + 'Notes', + ] + name = 'part' form_steps_template = [ 'part/import_wizard/part_upload.html', @@ -753,29 +776,7 @@ class PartImport(FileManagementFormView): 'default_location': 'default_location', 'default_supplier': 'default_supplier', } - class MyManger(FileManager): - REQUIRED_HEADERS = [ - 'Name', - 'Description', - ] - - OPTIONAL_MATCH_HEADERS = [ - 'Category', - 'default_location', - 'default_supplier', - ] - - OPTIONAL_HEADERS = [ - 'Keywords', - 'IPN', - 'Revision', - 'Link', - 'default_expiry', - 'minimum_stock', - 'Units', - 'Notes', - ] - file_manager_class = MyManger + file_manager_class = MyFileManager def get_field_selection(self): """ Fill the form fields for step 3 """ From 900f707ff9cebc1e7da9fe3e6fa43f310b307552 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 May 2021 11:51:08 +0200 Subject: [PATCH 027/445] permission added --- InvenTree/part/templates/part/category_navbar.html | 2 ++ InvenTree/part/views.py | 1 + 2 files changed, 3 insertions(+) diff --git a/InvenTree/part/templates/part/category_navbar.html b/InvenTree/part/templates/part/category_navbar.html index e2cbaf55db..553b03745b 100644 --- a/InvenTree/part/templates/part/category_navbar.html +++ b/InvenTree/part/templates/part/category_navbar.html @@ -30,12 +30,14 @@ + {% if user.is_staff and roles.part.add %}
  • {% trans "Import Parts" %}
  • + {% endif %} {% if category %}
  • diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index b9c4d2ec03..20185b7a1c 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -725,6 +725,7 @@ class PartCreate(AjaxCreateView): class PartImport(FileManagementFormView): ''' Part: Upload file, match to fields and import parts(using multi-Step form) ''' + permission_required = 'part.add' class MyFileManager(FileManager): REQUIRED_HEADERS = [ From 3c5bb048a1b8e3bd964dc85973f20c5cb7f71312 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 22 May 2021 15:39:54 +0200 Subject: [PATCH 028/445] renaming a few parts --- InvenTree/order/views.py | 8 ++++---- InvenTree/part/views.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 5d0acb9a7c..312c49b6db 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -577,7 +577,7 @@ class PurchaseOrderUpload(FileManagementFormView): ''' PurchaseOrder: Upload file, match to fields and parts (using multi-Step form) ''' # overriden classes - class MyMatch(cm_forms.MatchItem): + class OrderMatchItem(cm_forms.MatchItem): """ override MatchItem fields """ def get_special_field(self, col_guess, row, file_manager): """ set special field """ @@ -608,7 +608,7 @@ class PurchaseOrderUpload(FileManagementFormView): default_amount=self.clean_nbr(row.get('price', '')), ) - class MyFileManager(FileManager): + class OrderFileManager(FileManager): REQUIRED_HEADERS = [ 'Quantity', ] @@ -626,7 +626,7 @@ class PurchaseOrderUpload(FileManagementFormView): name = 'order' form_list_override = [ - ('items', MyMatch), + ('items', OrderMatchItem), ] form_steps_template = [ 'order/order_wizard/po_upload.html', @@ -645,7 +645,7 @@ class PurchaseOrderUpload(FileManagementFormView): 'reference': 'reference', 'notes': 'notes', } - file_manager_class = MyFileManager + file_manager_class = OrderFileManager def get_order(self): """ Get order or return 404 """ diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 20185b7a1c..91ff3bacf6 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -727,7 +727,7 @@ class PartImport(FileManagementFormView): ''' Part: Upload file, match to fields and import parts(using multi-Step form) ''' permission_required = 'part.add' - class MyFileManager(FileManager): + class PartFileManager(FileManager): REQUIRED_HEADERS = [ 'Name', 'Description', @@ -777,7 +777,7 @@ class PartImport(FileManagementFormView): 'default_location': 'default_location', 'default_supplier': 'default_supplier', } - file_manager_class = MyFileManager + file_manager_class = PartFileManager def get_field_selection(self): """ Fill the form fields for step 3 """ From 4319ba16af0fc9dfe96fa6322bc596fd21f5eea7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 26 May 2021 09:20:50 +0200 Subject: [PATCH 029/445] Settings to show import-button --- InvenTree/common/models.py | 7 +++++++ .../part/templates/part/category_navbar.html | 5 ++++- .../templates/InvenTree/settings/part.html | 20 +++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 99712b2a93..30de70f6d9 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -211,6 +211,13 @@ class InvenTreeSetting(models.Model): 'validator': bool, }, + 'PART_SHOW_IMPORT': { + 'name': _('Show Import in Views'), + 'description': _('Display the import wizard in some part views'), + 'default': False, + 'validator': bool, + }, + 'REPORT_DEBUG_MODE': { 'name': _('Debug Mode'), 'description': _('Generate reports in debug mode (HTML output)'), diff --git a/InvenTree/part/templates/part/category_navbar.html b/InvenTree/part/templates/part/category_navbar.html index 553b03745b..f6d083b864 100644 --- a/InvenTree/part/templates/part/category_navbar.html +++ b/InvenTree/part/templates/part/category_navbar.html @@ -1,4 +1,7 @@ {% load i18n %} +{% load inventree_extras %} + +{% settings_value 'PART_SHOW_IMPORT' as show_import %} ",{class:"select2-results__options select2-results__options--nested"});p.append(l),s.append(a),s.append(p)}else this.template(e,t);return f.StoreData(t,"data",e),t},i.prototype.bind=function(t,e){var l=this,n=t.id+"-results";this.$results.attr("id",n),t.on("results:all",function(e){l.clear(),l.append(e.data),t.isOpen()&&(l.setClasses(),l.highlightFirstItem())}),t.on("results:append",function(e){l.append(e.data),t.isOpen()&&l.setClasses()}),t.on("query",function(e){l.hideMessages(),l.showLoading(e)}),t.on("select",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("unselect",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("open",function(){l.$results.attr("aria-expanded","true"),l.$results.attr("aria-hidden","false"),l.setClasses(),l.ensureHighlightVisible()}),t.on("close",function(){l.$results.attr("aria-expanded","false"),l.$results.attr("aria-hidden","true"),l.$results.removeAttr("aria-activedescendant")}),t.on("results:toggle",function(){var e=l.getHighlightedResults();0!==e.length&&e.trigger("mouseup")}),t.on("results:select",function(){var e=l.getHighlightedResults();if(0!==e.length){var t=f.GetData(e[0],"data");"true"==e.attr("aria-selected")?l.trigger("close",{}):l.trigger("select",{data:t})}}),t.on("results:previous",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e);if(!(n<=0)){var i=n-1;0===e.length&&(i=0);var r=t.eq(i);r.trigger("mouseenter");var o=l.$results.offset().top,s=r.offset().top,a=l.$results.scrollTop()+(s-o);0===i?l.$results.scrollTop(0):s-o<0&&l.$results.scrollTop(a)}}),t.on("results:next",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e)+1;if(!(n>=t.length)){var i=t.eq(n);i.trigger("mouseenter");var r=l.$results.offset().top+l.$results.outerHeight(!1),o=i.offset().top+i.outerHeight(!1),s=l.$results.scrollTop()+o-r;0===n?l.$results.scrollTop(0):rthis.$results.outerHeight()||o<0)&&this.$results.scrollTop(r)}},i.prototype.template=function(e,t){var n=this.options.get("templateResult"),i=this.options.get("escapeMarkup"),r=n(e,t);null==r?t.style.display="none":"string"==typeof r?t.innerHTML=i(r):h(t).append(r)},i}),e.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),e.define("select2/selection/base",["jquery","../utils","../keys"],function(n,i,r){function o(e,t){this.$element=e,this.options=t,o.__super__.constructor.call(this)}return i.Extend(o,i.Observable),o.prototype.render=function(){var e=n('');return this._tabindex=0,null!=i.GetData(this.$element[0],"old-tabindex")?this._tabindex=i.GetData(this.$element[0],"old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),e.attr("title",this.$element.attr("title")),e.attr("tabindex",this._tabindex),e.attr("aria-disabled","false"),this.$selection=e},o.prototype.bind=function(e,t){var n=this,i=e.id+"-results";this.container=e,this.$selection.on("focus",function(e){n.trigger("focus",e)}),this.$selection.on("blur",function(e){n._handleBlur(e)}),this.$selection.on("keydown",function(e){n.trigger("keypress",e),e.which===r.SPACE&&e.preventDefault()}),e.on("results:focus",function(e){n.$selection.attr("aria-activedescendant",e.data._resultId)}),e.on("selection:update",function(e){n.update(e.data)}),e.on("open",function(){n.$selection.attr("aria-expanded","true"),n.$selection.attr("aria-owns",i),n._attachCloseHandler(e)}),e.on("close",function(){n.$selection.attr("aria-expanded","false"),n.$selection.removeAttr("aria-activedescendant"),n.$selection.removeAttr("aria-owns"),n.$selection.trigger("focus"),n._detachCloseHandler(e)}),e.on("enable",function(){n.$selection.attr("tabindex",n._tabindex),n.$selection.attr("aria-disabled","false")}),e.on("disable",function(){n.$selection.attr("tabindex","-1"),n.$selection.attr("aria-disabled","true")})},o.prototype._handleBlur=function(e){var t=this;window.setTimeout(function(){document.activeElement==t.$selection[0]||n.contains(t.$selection[0],document.activeElement)||t.trigger("blur",e)},1)},o.prototype._attachCloseHandler=function(e){n(document.body).on("mousedown.select2."+e.id,function(e){var t=n(e.target).closest(".select2");n(".select2.select2-container--open").each(function(){this!=t[0]&&i.GetData(this,"element").select2("close")})})},o.prototype._detachCloseHandler=function(e){n(document.body).off("mousedown.select2."+e.id)},o.prototype.position=function(e,t){t.find(".selection").append(e)},o.prototype.destroy=function(){this._detachCloseHandler(this.container)},o.prototype.update=function(e){throw new Error("The `update` method must be defined in child classes.")},o.prototype.isEnabled=function(){return!this.isDisabled()},o.prototype.isDisabled=function(){return this.options.get("disabled")},o}),e.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(e,t,n,i){function r(){r.__super__.constructor.apply(this,arguments)}return n.Extend(r,t),r.prototype.render=function(){var e=r.__super__.render.call(this);return e.addClass("select2-selection--single"),e.html(''),e},r.prototype.bind=function(t,e){var n=this;r.__super__.bind.apply(this,arguments);var i=t.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",i).attr("role","textbox").attr("aria-readonly","true"),this.$selection.attr("aria-labelledby",i),this.$selection.on("mousedown",function(e){1===e.which&&n.trigger("toggle",{originalEvent:e})}),this.$selection.on("focus",function(e){}),this.$selection.on("blur",function(e){}),t.on("focus",function(e){t.isOpen()||n.$selection.trigger("focus")})},r.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},r.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},r.prototype.selectionContainer=function(){return e("")},r.prototype.update=function(e){if(0!==e.length){var t=e[0],n=this.$selection.find(".select2-selection__rendered"),i=this.display(t,n);n.empty().append(i);var r=t.title||t.text;r?n.attr("title",r):n.removeAttr("title")}else this.clear()},r}),e.define("select2/selection/multiple",["jquery","./base","../utils"],function(r,e,l){function n(e,t){n.__super__.constructor.apply(this,arguments)}return l.Extend(n,e),n.prototype.render=function(){var e=n.__super__.render.call(this);return e.addClass("select2-selection--multiple"),e.html('
      '),e},n.prototype.bind=function(e,t){var i=this;n.__super__.bind.apply(this,arguments),this.$selection.on("click",function(e){i.trigger("toggle",{originalEvent:e})}),this.$selection.on("click",".select2-selection__choice__remove",function(e){if(!i.isDisabled()){var t=r(this).parent(),n=l.GetData(t[0],"data");i.trigger("unselect",{originalEvent:e,data:n})}})},n.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},n.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},n.prototype.selectionContainer=function(){return r('
    • ×
    • ')},n.prototype.update=function(e){if(this.clear(),0!==e.length){for(var t=[],n=0;n×');a.StoreData(i[0],"data",t),this.$selection.find(".select2-selection__rendered").prepend(i)}},e}),e.define("select2/selection/search",["jquery","../utils","../keys"],function(i,a,l){function e(e,t,n){e.call(this,t,n)}return e.prototype.render=function(e){var t=i('');this.$searchContainer=t,this.$search=t.find("input");var n=e.call(this);return this._transferTabIndex(),n},e.prototype.bind=function(e,t,n){var i=this,r=t.id+"-results";e.call(this,t,n),t.on("open",function(){i.$search.attr("aria-controls",r),i.$search.trigger("focus")}),t.on("close",function(){i.$search.val(""),i.$search.removeAttr("aria-controls"),i.$search.removeAttr("aria-activedescendant"),i.$search.trigger("focus")}),t.on("enable",function(){i.$search.prop("disabled",!1),i._transferTabIndex()}),t.on("disable",function(){i.$search.prop("disabled",!0)}),t.on("focus",function(e){i.$search.trigger("focus")}),t.on("results:focus",function(e){e.data._resultId?i.$search.attr("aria-activedescendant",e.data._resultId):i.$search.removeAttr("aria-activedescendant")}),this.$selection.on("focusin",".select2-search--inline",function(e){i.trigger("focus",e)}),this.$selection.on("focusout",".select2-search--inline",function(e){i._handleBlur(e)}),this.$selection.on("keydown",".select2-search--inline",function(e){if(e.stopPropagation(),i.trigger("keypress",e),i._keyUpPrevented=e.isDefaultPrevented(),e.which===l.BACKSPACE&&""===i.$search.val()){var t=i.$searchContainer.prev(".select2-selection__choice");if(0this.maximumInputLength?this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),e.define("select2/data/maximumSelectionLength",[],function(){function e(e,t,n){this.maximumSelectionLength=n.get("maximumSelectionLength"),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var i=this;e.call(this,t,n),t.on("select",function(){i._checkIfMaximumSelected()})},e.prototype.query=function(e,t,n){var i=this;this._checkIfMaximumSelected(function(){e.call(i,t,n)})},e.prototype._checkIfMaximumSelected=function(e,n){var i=this;this.current(function(e){var t=null!=e?e.length:0;0=i.maximumSelectionLength?i.trigger("results:message",{message:"maximumSelected",args:{maximum:i.maximumSelectionLength}}):n&&n()})},e}),e.define("select2/dropdown",["jquery","./utils"],function(t,e){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return e.Extend(n,e.Observable),n.prototype.render=function(){var e=t('');return e.attr("dir",this.options.get("dir")),this.$dropdown=e},n.prototype.bind=function(){},n.prototype.position=function(e,t){},n.prototype.destroy=function(){this.$dropdown.remove()},n}),e.define("select2/dropdown/search",["jquery","../utils"],function(o,e){function t(){}return t.prototype.render=function(e){var t=e.call(this),n=o('');return this.$searchContainer=n,this.$search=n.find("input"),t.prepend(n),t},t.prototype.bind=function(e,t,n){var i=this,r=t.id+"-results";e.call(this,t,n),this.$search.on("keydown",function(e){i.trigger("keypress",e),i._keyUpPrevented=e.isDefaultPrevented()}),this.$search.on("input",function(e){o(this).off("keyup")}),this.$search.on("keyup input",function(e){i.handleSearch(e)}),t.on("open",function(){i.$search.attr("tabindex",0),i.$search.attr("aria-controls",r),i.$search.trigger("focus"),window.setTimeout(function(){i.$search.trigger("focus")},0)}),t.on("close",function(){i.$search.attr("tabindex",-1),i.$search.removeAttr("aria-controls"),i.$search.removeAttr("aria-activedescendant"),i.$search.val(""),i.$search.trigger("blur")}),t.on("focus",function(){t.isOpen()||i.$search.trigger("focus")}),t.on("results:all",function(e){null!=e.query.term&&""!==e.query.term||(i.showSearch(e)?i.$searchContainer.removeClass("select2-search--hide"):i.$searchContainer.addClass("select2-search--hide"))}),t.on("results:focus",function(e){e.data._resultId?i.$search.attr("aria-activedescendant",e.data._resultId):i.$search.removeAttr("aria-activedescendant")})},t.prototype.handleSearch=function(e){if(!this._keyUpPrevented){var t=this.$search.val();this.trigger("query",{term:t})}this._keyUpPrevented=!1},t.prototype.showSearch=function(e,t){return!0},t}),e.define("select2/dropdown/hidePlaceholder",[],function(){function e(e,t,n,i){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n,i)}return e.prototype.append=function(e,t){t.results=this.removePlaceholder(t.results),e.call(this,t)},e.prototype.normalizePlaceholder=function(e,t){return"string"==typeof t&&(t={id:"",text:t}),t},e.prototype.removePlaceholder=function(e,t){for(var n=t.slice(0),i=t.length-1;0<=i;i--){var r=t[i];this.placeholder.id===r.id&&n.splice(i,1)}return n},e}),e.define("select2/dropdown/infiniteScroll",["jquery"],function(n){function e(e,t,n,i){this.lastParams={},e.call(this,t,n,i),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return e.prototype.append=function(e,t){this.$loadingMore.remove(),this.loading=!1,e.call(this,t),this.showLoadingMore(t)&&(this.$results.append(this.$loadingMore),this.loadMoreIfNeeded())},e.prototype.bind=function(e,t,n){var i=this;e.call(this,t,n),t.on("query",function(e){i.lastParams=e,i.loading=!0}),t.on("query:append",function(e){i.lastParams=e,i.loading=!0}),this.$results.on("scroll",this.loadMoreIfNeeded.bind(this))},e.prototype.loadMoreIfNeeded=function(){var e=n.contains(document.documentElement,this.$loadingMore[0]);if(!this.loading&&e){var t=this.$results.offset().top+this.$results.outerHeight(!1);this.$loadingMore.offset().top+this.$loadingMore.outerHeight(!1)<=t+50&&this.loadMore()}},e.prototype.loadMore=function(){this.loading=!0;var e=n.extend({},{page:1},this.lastParams);e.page++,this.trigger("query:append",e)},e.prototype.showLoadingMore=function(e,t){return t.pagination&&t.pagination.more},e.prototype.createLoadingMore=function(){var e=n('
    • '),t=this.options.get("translations").get("loadingMore");return e.html(t(this.lastParams)),e},e}),e.define("select2/dropdown/attachBody",["jquery","../utils"],function(f,a){function e(e,t,n){this.$dropdownParent=f(n.get("dropdownParent")||document.body),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var i=this;e.call(this,t,n),t.on("open",function(){i._showDropdown(),i._attachPositioningHandler(t),i._bindContainerResultHandlers(t)}),t.on("close",function(){i._hideDropdown(),i._detachPositioningHandler(t)}),this.$dropdownContainer.on("mousedown",function(e){e.stopPropagation()})},e.prototype.destroy=function(e){e.call(this),this.$dropdownContainer.remove()},e.prototype.position=function(e,t,n){t.attr("class",n.attr("class")),t.removeClass("select2"),t.addClass("select2-container--open"),t.css({position:"absolute",top:-999999}),this.$container=n},e.prototype.render=function(e){var t=f(""),n=e.call(this);return t.append(n),this.$dropdownContainer=t},e.prototype._hideDropdown=function(e){this.$dropdownContainer.detach()},e.prototype._bindContainerResultHandlers=function(e,t){if(!this._containerResultsHandlersBound){var n=this;t.on("results:all",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:append",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:message",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("select",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("unselect",function(){n._positionDropdown(),n._resizeDropdown()}),this._containerResultsHandlersBound=!0}},e.prototype._attachPositioningHandler=function(e,t){var n=this,i="scroll.select2."+t.id,r="resize.select2."+t.id,o="orientationchange.select2."+t.id,s=this.$container.parents().filter(a.hasScroll);s.each(function(){a.StoreData(this,"select2-scroll-position",{x:f(this).scrollLeft(),y:f(this).scrollTop()})}),s.on(i,function(e){var t=a.GetData(this,"select2-scroll-position");f(this).scrollTop(t.y)}),f(window).on(i+" "+r+" "+o,function(e){n._positionDropdown(),n._resizeDropdown()})},e.prototype._detachPositioningHandler=function(e,t){var n="scroll.select2."+t.id,i="resize.select2."+t.id,r="orientationchange.select2."+t.id;this.$container.parents().filter(a.hasScroll).off(n),f(window).off(n+" "+i+" "+r)},e.prototype._positionDropdown=function(){var e=f(window),t=this.$dropdown.hasClass("select2-dropdown--above"),n=this.$dropdown.hasClass("select2-dropdown--below"),i=null,r=this.$container.offset();r.bottom=r.top+this.$container.outerHeight(!1);var o={height:this.$container.outerHeight(!1)};o.top=r.top,o.bottom=r.top+o.height;var s=this.$dropdown.outerHeight(!1),a=e.scrollTop(),l=e.scrollTop()+e.height(),c=ar.bottom+s,d={left:r.left,top:o.bottom},p=this.$dropdownParent;"static"===p.css("position")&&(p=p.offsetParent());var h={top:0,left:0};(f.contains(document.body,p[0])||p[0].isConnected)&&(h=p.offset()),d.top-=h.top,d.left-=h.left,t||n||(i="below"),u||!c||t?!c&&u&&t&&(i="below"):i="above",("above"==i||t&&"below"!==i)&&(d.top=o.top-h.top-s),null!=i&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+i),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+i)),this.$dropdownContainer.css(d)},e.prototype._resizeDropdown=function(){var e={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(e.minWidth=e.width,e.position="relative",e.width="auto"),this.$dropdown.css(e)},e.prototype._showDropdown=function(e){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},e}),e.define("select2/dropdown/minimumResultsForSearch",[],function(){function e(e,t,n,i){this.minimumResultsForSearch=n.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),e.call(this,t,n,i)}return e.prototype.showSearch=function(e,t){return!(function e(t){for(var n=0,i=0;i');return e.attr("dir",this.options.get("dir")),this.$container=e,this.$container.addClass("select2-container--"+this.options.get("theme")),u.StoreData(e[0],"element",this.$element),e},d}),e.define("select2/compat/utils",["jquery"],function(s){return{syncCssClasses:function(e,t,n){var i,r,o=[];(i=s.trim(e.attr("class")))&&s((i=""+i).split(/\s+/)).each(function(){0===this.indexOf("select2-")&&o.push(this)}),(i=s.trim(t.attr("class")))&&s((i=""+i).split(/\s+/)).each(function(){0!==this.indexOf("select2-")&&null!=(r=n(this))&&o.push(r)}),e.attr("class",o.join(" "))}}}),e.define("select2/compat/containerCss",["jquery","./utils"],function(s,a){function l(e){return null}function e(){}return e.prototype.render=function(e){var t=e.call(this),n=this.options.get("containerCssClass")||"";s.isFunction(n)&&(n=n(this.$element));var i=this.options.get("adaptContainerCssClass");if(i=i||l,-1!==n.indexOf(":all:")){n=n.replace(":all:","");var r=i;i=function(e){var t=r(e);return null!=t?t+" "+e:e}}var o=this.options.get("containerCss")||{};return s.isFunction(o)&&(o=o(this.$element)),a.syncCssClasses(t,this.$element,i),t.css(o),t.addClass(n),t},e}),e.define("select2/compat/dropdownCss",["jquery","./utils"],function(s,a){function l(e){return null}function e(){}return e.prototype.render=function(e){var t=e.call(this),n=this.options.get("dropdownCssClass")||"";s.isFunction(n)&&(n=n(this.$element));var i=this.options.get("adaptDropdownCssClass");if(i=i||l,-1!==n.indexOf(":all:")){n=n.replace(":all:","");var r=i;i=function(e){var t=r(e);return null!=t?t+" "+e:e}}var o=this.options.get("dropdownCss")||{};return s.isFunction(o)&&(o=o(this.$element)),a.syncCssClasses(t,this.$element,i),t.css(o),t.addClass(n),t},e}),e.define("select2/compat/initSelection",["jquery"],function(i){function e(e,t,n){n.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `initSelection` option has been deprecated in favor of a custom data adapter that overrides the `current` method. This method is now called multiple times instead of a single time when the instance is initialized. Support will be removed for the `initSelection` option in future versions of Select2"),this.initSelection=n.get("initSelection"),this._isInitialized=!1,e.call(this,t,n)}return e.prototype.current=function(e,t){var n=this;this._isInitialized?e.call(this,t):this.initSelection.call(null,this.$element,function(e){n._isInitialized=!0,i.isArray(e)||(e=[e]),t(e)})},e}),e.define("select2/compat/inputData",["jquery","../utils"],function(s,i){function e(e,t,n){this._currentData=[],this._valueSeparator=n.get("valueSeparator")||",","hidden"===t.prop("type")&&n.get("debug")&&console&&console.warn&&console.warn("Select2: Using a hidden input with Select2 is no longer supported and may stop working in the future. It is recommended to use a `' + + ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' + '' ); @@ -1873,14 +2000,18 @@ S2.define('select2/selection/search',[ Search.prototype.bind = function (decorated, container, $container) { var self = this; + var resultsId = container.id + '-results'; + decorated.call(this, container, $container); container.on('open', function () { + self.$search.attr('aria-controls', resultsId); self.$search.trigger('focus'); }); container.on('close', function () { self.$search.val(''); + self.$search.removeAttr('aria-controls'); self.$search.removeAttr('aria-activedescendant'); self.$search.trigger('focus'); }); @@ -1900,7 +2031,11 @@ S2.define('select2/selection/search',[ }); container.on('results:focus', function (params) { - self.$search.attr('aria-activedescendant', params.id); + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } }); this.$selection.on('focusin', '.select2-search--inline', function (evt) { @@ -1925,7 +2060,7 @@ S2.define('select2/selection/search',[ .prev('.select2-selection__choice'); if ($previousChoice.length > 0) { - var item = $previousChoice.data('data'); + var item = Utils.GetData($previousChoice[0], 'data'); self.searchRemoveChoice(item); @@ -1934,6 +2069,12 @@ S2.define('select2/selection/search',[ } }); + this.$selection.on('click', '.select2-search--inline', function (evt) { + if (self.$search.val()) { + evt.stopPropagation(); + } + }); + // Try to detect the IE version should the `documentMode` property that // is stored on the document. This is only implemented in IE and is // slightly cleaner than doing a user agent check. @@ -2019,7 +2160,7 @@ S2.define('select2/selection/search',[ this.resizeSearch(); if (searchHadFocus) { - this.$search.focus(); + this.$search.trigger('focus'); } }; @@ -2052,7 +2193,7 @@ S2.define('select2/selection/search',[ var width = ''; if (this.$search.attr('placeholder') !== '') { - width = this.$selection.find('.select2-selection__rendered').innerWidth(); + width = this.$selection.find('.select2-selection__rendered').width(); } else { var minimumWidth = this.$search.val().length + 1; @@ -2076,10 +2217,13 @@ S2.define('select2/selection/eventRelay',[ 'open', 'opening', 'close', 'closing', 'select', 'selecting', - 'unselect', 'unselecting' + 'unselect', 'unselecting', + 'clear', 'clearing' ]; - var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting']; + var preventableEvents = [ + 'opening', 'closing', 'selecting', 'unselecting', 'clearing' + ]; decorated.call(this, container, $container); @@ -2412,6 +2556,7 @@ S2.define('select2/diacritics',[ '\u019F': 'O', '\uA74A': 'O', '\uA74C': 'O', + '\u0152': 'OE', '\u01A2': 'OI', '\uA74E': 'OO', '\u0222': 'OU', @@ -2821,6 +2966,7 @@ S2.define('select2/diacritics',[ '\uA74B': 'o', '\uA74D': 'o', '\u0275': 'o', + '\u0153': 'oe', '\u01A3': 'oi', '\u0223': 'ou', '\uA74F': 'oo', @@ -2989,8 +3135,9 @@ S2.define('select2/diacritics',[ '\u03CD': '\u03C5', '\u03CB': '\u03C5', '\u03B0': '\u03C5', - '\u03C9': '\u03C9', - '\u03C2': '\u03C3' + '\u03CE': '\u03C9', + '\u03C2': '\u03C3', + '\u2019': '\'' }; return diacritics; @@ -3075,7 +3222,7 @@ S2.define('select2/data/select',[ if ($(data.element).is('option')) { data.element.selected = true; - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); return; } @@ -3096,13 +3243,13 @@ S2.define('select2/data/select',[ } self.$element.val(val); - self.$element.trigger('change'); + self.$element.trigger('input').trigger('change'); }); } else { var val = data.id; this.$element.val(val); - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); } }; @@ -3118,7 +3265,7 @@ S2.define('select2/data/select',[ if ($(data.element).is('option')) { data.element.selected = false; - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); return; } @@ -3136,7 +3283,7 @@ S2.define('select2/data/select',[ self.$element.val(val); - self.$element.trigger('change'); + self.$element.trigger('input').trigger('change'); }); }; @@ -3158,7 +3305,7 @@ S2.define('select2/data/select',[ // Remove anything added to child elements this.$element.find('*').each(function () { // Remove any custom data set by Select2 - $.removeData(this, 'data'); + Utils.RemoveData(this); }); }; @@ -3231,7 +3378,7 @@ S2.define('select2/data/select',[ normalizedData.element = option; // Override the option's data with the combined data - $.data(option, 'data', normalizedData); + Utils.StoreData(option, 'data', normalizedData); return $option; }; @@ -3239,7 +3386,7 @@ S2.define('select2/data/select',[ SelectAdapter.prototype.item = function ($option) { var data = {}; - data = $.data($option[0], 'data'); + data = Utils.GetData($option[0], 'data'); if (data != null) { return data; @@ -3277,13 +3424,13 @@ S2.define('select2/data/select',[ data = this._normalizeItem(data); data.element = $option[0]; - $.data($option[0], 'data', data); + Utils.StoreData($option[0], 'data', data); return data; }; SelectAdapter.prototype._normalizeItem = function (item) { - if (!$.isPlainObject(item)) { + if (item !== Object(item)) { item = { id: item, text: item @@ -3329,15 +3476,19 @@ S2.define('select2/data/array',[ 'jquery' ], function (SelectAdapter, Utils, $) { function ArrayAdapter ($element, options) { - var data = options.get('data') || []; + this._dataToConvert = options.get('data') || []; ArrayAdapter.__super__.constructor.call(this, $element, options); - - this.addOptions(this.convertToOptions(data)); } Utils.Extend(ArrayAdapter, SelectAdapter); + ArrayAdapter.prototype.bind = function (container, $container) { + ArrayAdapter.__super__.bind.call(this, container, $container); + + this.addOptions(this.convertToOptions(this._dataToConvert)); + }; + ArrayAdapter.prototype.select = function (data) { var $option = this.$element.find('option').filter(function (i, elm) { return elm.value == data.id.toString(); @@ -3487,7 +3638,8 @@ S2.define('select2/data/ajax',[ }, function () { // Attempt to detect if a request was aborted // Only works if the transport exposes a status property - if ($request.status && $request.status === '0') { + if ('status' in $request && + ($request.status === 0 || $request.status === '0')) { return; } @@ -3626,8 +3778,6 @@ S2.define('select2/data/tags',[ }; Tags.prototype._removeOldTags = function (_) { - var tag = this._lastTag; - var $options = this.$element.find('option[data-select2-tag]'); $options.each(function () { @@ -3702,7 +3852,7 @@ S2.define('select2/data/tokenizer',[ // Replace the search term if we have the search box if (this.$search.length) { this.$search.val(tokenData.term); - this.$search.focus(); + this.$search.trigger('focus'); } params.term = tokenData.term; @@ -3831,10 +3981,30 @@ S2.define('select2/data/maximumSelectionLength',[ decorated.call(this, $e, options); } + MaximumSelectionLength.prototype.bind = + function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function () { + self._checkIfMaximumSelected(); + }); + }; + MaximumSelectionLength.prototype.query = function (decorated, params, callback) { var self = this; + this._checkIfMaximumSelected(function () { + decorated.call(self, params, callback); + }); + }; + + MaximumSelectionLength.prototype._checkIfMaximumSelected = + function (_, successCallback) { + var self = this; + this.current(function (currentData) { var count = currentData != null ? currentData.length : 0; if (self.maximumSelectionLength > 0 && @@ -3847,7 +4017,10 @@ S2.define('select2/data/maximumSelectionLength',[ }); return; } - decorated.call(self, params, callback); + + if (successCallback) { + successCallback(); + } }); }; @@ -3886,7 +4059,7 @@ S2.define('select2/dropdown',[ }; Dropdown.prototype.position = function ($dropdown, $container) { - // Should be implmented in subclasses + // Should be implemented in subclasses }; Dropdown.prototype.destroy = function () { @@ -3910,7 +4083,7 @@ S2.define('select2/dropdown/search',[ '' + '' + + ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' + '' ); @@ -3925,6 +4098,8 @@ S2.define('select2/dropdown/search',[ Search.prototype.bind = function (decorated, container, $container) { var self = this; + var resultsId = container.id + '-results'; + decorated.call(this, container, $container); this.$search.on('keydown', function (evt) { @@ -3947,23 +4122,27 @@ S2.define('select2/dropdown/search',[ container.on('open', function () { self.$search.attr('tabindex', 0); + self.$search.attr('aria-controls', resultsId); - self.$search.focus(); + self.$search.trigger('focus'); window.setTimeout(function () { - self.$search.focus(); + self.$search.trigger('focus'); }, 0); }); container.on('close', function () { self.$search.attr('tabindex', -1); + self.$search.removeAttr('aria-controls'); + self.$search.removeAttr('aria-activedescendant'); self.$search.val(''); + self.$search.trigger('blur'); }); container.on('focus', function () { if (!container.isOpen()) { - self.$search.focus(); + self.$search.trigger('focus'); } }); @@ -3978,6 +4157,14 @@ S2.define('select2/dropdown/search',[ } } }); + + container.on('results:focus', function (params) { + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } + }); }; Search.prototype.handleSearch = function (evt) { @@ -4062,6 +4249,7 @@ S2.define('select2/dropdown/infiniteScroll',[ if (this.showLoadingMore(data)) { this.$results.append(this.$loadingMore); + this.loadMoreIfNeeded(); } }; @@ -4080,25 +4268,27 @@ S2.define('select2/dropdown/infiniteScroll',[ self.loading = true; }); - this.$results.on('scroll', function () { - var isLoadMoreVisible = $.contains( - document.documentElement, - self.$loadingMore[0] - ); + this.$results.on('scroll', this.loadMoreIfNeeded.bind(this)); + }; - if (self.loading || !isLoadMoreVisible) { - return; - } + InfiniteScroll.prototype.loadMoreIfNeeded = function () { + var isLoadMoreVisible = $.contains( + document.documentElement, + this.$loadingMore[0] + ); - var currentOffset = self.$results.offset().top + - self.$results.outerHeight(false); - var loadingMoreOffset = self.$loadingMore.offset().top + - self.$loadingMore.outerHeight(false); + if (this.loading || !isLoadMoreVisible) { + return; + } - if (currentOffset + 50 >= loadingMoreOffset) { - self.loadMore(); - } - }); + var currentOffset = this.$results.offset().top + + this.$results.outerHeight(false); + var loadingMoreOffset = this.$loadingMore.offset().top + + this.$loadingMore.outerHeight(false); + + if (currentOffset + 50 >= loadingMoreOffset) { + this.loadMore(); + } }; InfiniteScroll.prototype.loadMore = function () { @@ -4119,7 +4309,7 @@ S2.define('select2/dropdown/infiniteScroll',[ var $option = $( '
    • ' + 'role="option" aria-disabled="true">' ); var message = this.options.get('translations').get('loadingMore'); @@ -4137,7 +4327,7 @@ S2.define('select2/dropdown/attachBody',[ '../utils' ], function ($, Utils) { function AttachBody (decorated, $element, options) { - this.$dropdownParent = options.get('dropdownParent') || $(document.body); + this.$dropdownParent = $(options.get('dropdownParent') || document.body); decorated.call(this, $element, options); } @@ -4145,27 +4335,14 @@ S2.define('select2/dropdown/attachBody',[ AttachBody.prototype.bind = function (decorated, container, $container) { var self = this; - var setupResultsEvents = false; - decorated.call(this, container, $container); container.on('open', function () { self._showDropdown(); self._attachPositioningHandler(container); - if (!setupResultsEvents) { - setupResultsEvents = true; - - container.on('results:all', function () { - self._positionDropdown(); - self._resizeDropdown(); - }); - - container.on('results:append', function () { - self._positionDropdown(); - self._resizeDropdown(); - }); - } + // Must bind after the results handlers to ensure correct sizing + self._bindContainerResultHandlers(container); }); container.on('close', function () { @@ -4214,6 +4391,44 @@ S2.define('select2/dropdown/attachBody',[ this.$dropdownContainer.detach(); }; + AttachBody.prototype._bindContainerResultHandlers = + function (decorated, container) { + + // These should only be bound once + if (this._containerResultsHandlersBound) { + return; + } + + var self = this; + + container.on('results:all', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:append', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:message', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('select', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('unselect', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + this._containerResultsHandlersBound = true; + }; + AttachBody.prototype._attachPositioningHandler = function (decorated, container) { var self = this; @@ -4224,14 +4439,14 @@ S2.define('select2/dropdown/attachBody',[ var $watchers = this.$container.parents().filter(Utils.hasScroll); $watchers.each(function () { - $(this).data('select2-scroll-position', { + Utils.StoreData(this, 'select2-scroll-position', { x: $(this).scrollLeft(), y: $(this).scrollTop() }); }); $watchers.on(scrollEvent, function (ev) { - var position = $(this).data('select2-scroll-position'); + var position = Utils.GetData(this, 'select2-scroll-position'); $(this).scrollTop(position.y); }); @@ -4290,16 +4505,26 @@ S2.define('select2/dropdown/attachBody',[ top: container.bottom }; - // Determine what the parent element is to use for calciulating the offset + // Determine what the parent element is to use for calculating the offset var $offsetParent = this.$dropdownParent; - // For statically positoned elements, we need to get the element + // For statically positioned elements, we need to get the element // that is determining the offset if ($offsetParent.css('position') === 'static') { $offsetParent = $offsetParent.offsetParent(); } - var parentOffset = $offsetParent.offset(); + var parentOffset = { + top: 0, + left: 0 + }; + + if ( + $.contains(document.body, $offsetParent[0]) || + $offsetParent[0].isConnected + ) { + parentOffset = $offsetParent.offset(); + } css.top -= parentOffset.top; css.left -= parentOffset.left; @@ -4396,8 +4621,8 @@ S2.define('select2/dropdown/minimumResultsForSearch',[ }); S2.define('select2/dropdown/selectOnClose',[ - -], function () { + '../utils' +], function (Utils) { function SelectOnClose () { } SelectOnClose.prototype.bind = function (decorated, container, $container) { @@ -4428,7 +4653,7 @@ S2.define('select2/dropdown/selectOnClose',[ return; } - var data = $highlightedResults.data('data'); + var data = Utils.GetData($highlightedResults[0], 'data'); // Don't re-select already selected resulte if ( @@ -4469,7 +4694,7 @@ S2.define('select2/dropdown/closeOnSelect',[ var originalEvent = evt.originalEvent; // Don't close if the control key is being held - if (originalEvent && originalEvent.ctrlKey) { + if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) { return; } @@ -4523,6 +4748,9 @@ S2.define('select2/i18n/en',[],function () { }, searching: function () { return 'Searching…'; + }, + removeAllItems: function () { + return 'Remove all items'; } }; }); @@ -4761,66 +4989,29 @@ S2.define('select2/defaults',[ ); } - if (typeof options.language === 'string') { - // Check if the language is specified with a region - if (options.language.indexOf('-') > 0) { - // Extract the region information if it is included - var languageParts = options.language.split('-'); - var baseLanguage = languageParts[0]; + // If the defaults were not previously applied from an element, it is + // possible for the language option to have not been resolved + options.language = this._resolveLanguage(options.language); - options.language = [options.language, baseLanguage]; - } else { - options.language = [options.language]; + // Always fall back to English since it will always be complete + options.language.push('en'); + + var uniqueLanguages = []; + + for (var l = 0; l < options.language.length; l++) { + var language = options.language[l]; + + if (uniqueLanguages.indexOf(language) === -1) { + uniqueLanguages.push(language); } } - if ($.isArray(options.language)) { - var languages = new Translation(); - options.language.push('en'); + options.language = uniqueLanguages; - var languageNames = options.language; - - for (var l = 0; l < languageNames.length; l++) { - var name = languageNames[l]; - var language = {}; - - try { - // Try to load it with the original name - language = Translation.loadPath(name); - } catch (e) { - try { - // If we couldn't load it, check if it wasn't the full path - name = this.defaults.amdLanguageBase + name; - language = Translation.loadPath(name); - } catch (ex) { - // The translation could not be loaded at all. Sometimes this is - // because of a configuration problem, other times this can be - // because of how Select2 helps load all possible translation files. - if (options.debug && window.console && console.warn) { - console.warn( - 'Select2: The language file for "' + name + '" could not be ' + - 'automatically loaded. A fallback will be used instead.' - ); - } - - continue; - } - } - - languages.extend(language); - } - - options.translations = languages; - } else { - var baseTranslation = Translation.loadPath( - this.defaults.amdLanguageBase + 'en' - ); - var customTranslation = new Translation(options.language); - - customTranslation.extend(baseTranslation); - - options.translations = customTranslation; - } + options.translations = this._processTranslations( + options.language, + options.debug + ); return options; }; @@ -4887,13 +5078,14 @@ S2.define('select2/defaults',[ debug: false, dropdownAutoWidth: false, escapeMarkup: Utils.escapeMarkup, - language: EnglishTranslation, + language: {}, matcher: matcher, minimumInputLength: 0, maximumInputLength: 0, maximumSelectionLength: 0, minimumResultsForSearch: 0, selectOnClose: false, + scrollAfterSelect: false, sorter: function (data) { return data; }, @@ -4908,6 +5100,103 @@ S2.define('select2/defaults',[ }; }; + Defaults.prototype.applyFromElement = function (options, $element) { + var optionLanguage = options.language; + var defaultLanguage = this.defaults.language; + var elementLanguage = $element.prop('lang'); + var parentLanguage = $element.closest('[lang]').prop('lang'); + + var languages = Array.prototype.concat.call( + this._resolveLanguage(elementLanguage), + this._resolveLanguage(optionLanguage), + this._resolveLanguage(defaultLanguage), + this._resolveLanguage(parentLanguage) + ); + + options.language = languages; + + return options; + }; + + Defaults.prototype._resolveLanguage = function (language) { + if (!language) { + return []; + } + + if ($.isEmptyObject(language)) { + return []; + } + + if ($.isPlainObject(language)) { + return [language]; + } + + var languages; + + if (!$.isArray(language)) { + languages = [language]; + } else { + languages = language; + } + + var resolvedLanguages = []; + + for (var l = 0; l < languages.length; l++) { + resolvedLanguages.push(languages[l]); + + if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) { + // Extract the region information if it is included + var languageParts = languages[l].split('-'); + var baseLanguage = languageParts[0]; + + resolvedLanguages.push(baseLanguage); + } + } + + return resolvedLanguages; + }; + + Defaults.prototype._processTranslations = function (languages, debug) { + var translations = new Translation(); + + for (var l = 0; l < languages.length; l++) { + var languageData = new Translation(); + + var language = languages[l]; + + if (typeof language === 'string') { + try { + // Try to load it with the original name + languageData = Translation.loadPath(language); + } catch (e) { + try { + // If we couldn't load it, check if it wasn't the full path + language = this.defaults.amdLanguageBase + language; + languageData = Translation.loadPath(language); + } catch (ex) { + // The translation could not be loaded at all. Sometimes this is + // because of a configuration problem, other times this can be + // because of how Select2 helps load all possible translation files + if (debug && window.console && console.warn) { + console.warn( + 'Select2: The language file for "' + language + '" could ' + + 'not be automatically loaded. A fallback will be used instead.' + ); + } + } + } + } else if ($.isPlainObject(language)) { + languageData = new Translation(language); + } else { + languageData = language; + } + + translations.extend(languageData); + } + + return translations; + }; + Defaults.prototype.set = function (key, value) { var camelKey = $.camelCase(key); @@ -4916,7 +5205,7 @@ S2.define('select2/defaults',[ var convertedData = Utils._convertData(data); - $.extend(this.defaults, convertedData); + $.extend(true, this.defaults, convertedData); }; var defaults = new Defaults(); @@ -4937,6 +5226,10 @@ S2.define('select2/options',[ this.fromElement($element); } + if ($element != null) { + this.options = Defaults.applyFromElement(this.options, $element); + } + this.options = Defaults.apply(this.options); if ($element && $element.is('input')) { @@ -4960,14 +5253,6 @@ S2.define('select2/options',[ this.options.disabled = $e.prop('disabled'); } - if (this.options.language == null) { - if ($e.prop('lang')) { - this.options.language = $e.prop('lang').toLowerCase(); - } else if ($e.closest('[lang]').prop('lang')) { - this.options.language = $e.closest('[lang]').prop('lang'); - } - } - if (this.options.dir == null) { if ($e.prop('dir')) { this.options.dir = $e.prop('dir'); @@ -4981,7 +5266,7 @@ S2.define('select2/options',[ $e.prop('disabled', this.options.disabled); $e.prop('multiple', this.options.multiple); - if ($e.data('select2Tags')) { + if (Utils.GetData($e[0], 'select2Tags')) { if (this.options.debug && window.console && console.warn) { console.warn( 'Select2: The `data-select2-tags` attribute has been changed to ' + @@ -4990,11 +5275,11 @@ S2.define('select2/options',[ ); } - $e.data('data', $e.data('select2Tags')); - $e.data('tags', true); + Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags')); + Utils.StoreData($e[0], 'tags', true); } - if ($e.data('ajaxUrl')) { + if (Utils.GetData($e[0], 'ajaxUrl')) { if (this.options.debug && window.console && console.warn) { console.warn( 'Select2: The `data-ajax-url` attribute has been changed to ' + @@ -5003,21 +5288,45 @@ S2.define('select2/options',[ ); } - $e.attr('ajax--url', $e.data('ajaxUrl')); - $e.data('ajax--url', $e.data('ajaxUrl')); + $e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl')); + Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl')); } var dataset = {}; + function upperCaseLetter(_, letter) { + return letter.toUpperCase(); + } + + // Pre-load all of the attributes which are prefixed with `data-` + for (var attr = 0; attr < $e[0].attributes.length; attr++) { + var attributeName = $e[0].attributes[attr].name; + var prefix = 'data-'; + + if (attributeName.substr(0, prefix.length) == prefix) { + // Get the contents of the attribute after `data-` + var dataName = attributeName.substring(prefix.length); + + // Get the data contents from the consistent source + // This is more than likely the jQuery data helper + var dataValue = Utils.GetData($e[0], dataName); + + // camelCase the attribute name to match the spec + var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter); + + // Store the data attribute contents into the dataset since + dataset[camelDataName] = dataValue; + } + } + // Prefer the element's `dataset` attribute if it exists // jQuery 1.x does not correctly handle data attributes with multiple dashes if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) { - dataset = $.extend(true, {}, $e[0].dataset, $e.data()); - } else { - dataset = $e.data(); + dataset = $.extend(true, {}, $e[0].dataset, dataset); } - var data = $.extend(true, {}, dataset); + // Prefer our internal data cache if it exists + var data = $.extend(true, {}, Utils.GetData($e[0]), dataset); data = Utils._convertData(data); @@ -5054,8 +5363,8 @@ S2.define('select2/core',[ './keys' ], function ($, Options, Utils, KEYS) { var Select2 = function ($element, options) { - if ($element.data('select2') != null) { - $element.data('select2').destroy(); + if (Utils.GetData($element[0], 'select2') != null) { + Utils.GetData($element[0], 'select2').destroy(); } this.$element = $element; @@ -5071,7 +5380,7 @@ S2.define('select2/core',[ // Set up the tabindex var tabindex = $element.attr('tabindex') || 0; - $element.data('old-tabindex', tabindex); + Utils.StoreData($element[0], 'old-tabindex', tabindex); $element.attr('tabindex', '-1'); // Set up containers and adapters @@ -5132,6 +5441,9 @@ S2.define('select2/core',[ // Synchronize any monitored attributes this._syncAttributes(); + Utils.StoreData($element[0], 'select2', this); + + // Ensure backwards compatibility with $element.data('select2'). $element.data('select2', this); }; @@ -5208,6 +5520,12 @@ S2.define('select2/core',[ return null; } + if (method == 'computedstyle') { + var computedStyle = window.getComputedStyle($element[0]); + + return computedStyle.width; + } + return method; }; @@ -5248,8 +5566,8 @@ S2.define('select2/core',[ if (observer != null) { this._observer = new observer(function (mutations) { - $.each(mutations, self._syncA); - $.each(mutations, self._syncS); + self._syncA(); + self._syncS(null, mutations); }); this._observer.observe(this.$element[0], { attributes: true, @@ -5371,7 +5689,7 @@ S2.define('select2/core',[ if (self.isOpen()) { if (key === KEYS.ESC || key === KEYS.TAB || (key === KEYS.UP && evt.altKey)) { - self.close(); + self.close(evt); evt.preventDefault(); } else if (key === KEYS.ENTER) { @@ -5405,7 +5723,7 @@ S2.define('select2/core',[ Select2.prototype._syncAttributes = function () { this.options.set('disabled', this.$element.prop('disabled')); - if (this.options.get('disabled')) { + if (this.isDisabled()) { if (this.isOpen()) { this.close(); } @@ -5416,7 +5734,7 @@ S2.define('select2/core',[ } }; - Select2.prototype._syncSubtree = function (evt, mutations) { + Select2.prototype._isChangeMutation = function (evt, mutations) { var changed = false; var self = this; @@ -5444,7 +5762,22 @@ S2.define('select2/core',[ } } else if (mutations.removedNodes && mutations.removedNodes.length > 0) { changed = true; + } else if ($.isArray(mutations)) { + $.each(mutations, function(evt, mutation) { + if (self._isChangeMutation(evt, mutation)) { + // We've found a change mutation. + // Let's escape from the loop and continue + changed = true; + return false; + } + }); } + return changed; + }; + + Select2.prototype._syncSubtree = function (evt, mutations) { + var changed = this._isChangeMutation(evt, mutations); + var self = this; // Only re-pull the data if we think there is a change if (changed) { @@ -5466,7 +5799,8 @@ S2.define('select2/core',[ 'open': 'opening', 'close': 'closing', 'select': 'selecting', - 'unselect': 'unselecting' + 'unselect': 'unselecting', + 'clear': 'clearing' }; if (args === undefined) { @@ -5494,7 +5828,7 @@ S2.define('select2/core',[ }; Select2.prototype.toggleDropdown = function () { - if (this.options.get('disabled')) { + if (this.isDisabled()) { return; } @@ -5510,15 +5844,40 @@ S2.define('select2/core',[ return; } + if (this.isDisabled()) { + return; + } + this.trigger('query', {}); }; - Select2.prototype.close = function () { + Select2.prototype.close = function (evt) { if (!this.isOpen()) { return; } - this.trigger('close', {}); + this.trigger('close', { originalEvent : evt }); + }; + + /** + * Helper method to abstract the "enabled" (not "disabled") state of this + * object. + * + * @return {true} if the instance is not disabled. + * @return {false} if the instance is disabled. + */ + Select2.prototype.isEnabled = function () { + return !this.isDisabled(); + }; + + /** + * Helper method to abstract the "disabled" state of this object. + * + * @return {true} if the disabled option is true. + * @return {false} if the disabled option is false. + */ + Select2.prototype.isDisabled = function () { + return this.options.get('disabled'); }; Select2.prototype.isOpen = function () { @@ -5595,7 +5954,7 @@ S2.define('select2/core',[ }); } - this.$element.val(newVal).trigger('change'); + this.$element.val(newVal).trigger('input').trigger('change'); }; Select2.prototype.destroy = function () { @@ -5621,10 +5980,12 @@ S2.define('select2/core',[ this._syncS = null; this.$element.off('.select2'); - this.$element.attr('tabindex', this.$element.data('old-tabindex')); + this.$element.attr('tabindex', + Utils.GetData(this.$element[0], 'old-tabindex')); this.$element.removeClass('select2-hidden-accessible'); this.$element.attr('aria-hidden', 'false'); + Utils.RemoveData(this.$element[0]); this.$element.removeData('select2'); this.dataAdapter.destroy(); @@ -5652,7 +6013,7 @@ S2.define('select2/core',[ this.$container.addClass('select2-container--' + this.options.get('theme')); - $container.data('element', this.$element); + Utils.StoreData($container[0], 'element', this.$element); return $container; }; @@ -5672,8 +6033,9 @@ S2.define('jquery.select2',[ 'jquery-mousewheel', './select2/core', - './select2/defaults' -], function ($, _, Select2, Defaults) { + './select2/defaults', + './select2/utils' +], function ($, _, Select2, Defaults, Utils) { if ($.fn.select2 == null) { // All methods that should return the element var thisMethods = ['open', 'close', 'destroy']; @@ -5694,7 +6056,7 @@ S2.define('jquery.select2',[ var args = Array.prototype.slice.call(arguments, 1); this.each(function () { - var instance = $(this).data('select2'); + var instance = Utils.GetData(this, 'select2'); if (instance == null && window.console && console.error) { console.error( diff --git a/InvenTree/InvenTree/static/select2/js/select2.min.js b/InvenTree/InvenTree/static/select2/js/select2.min.js new file mode 100644 index 0000000000..e421426434 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/select2.min.js @@ -0,0 +1,2 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ +!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return void 0===t&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t),t}:n(jQuery)}(function(u){var e=function(){if(u&&u.fn&&u.fn.select2&&u.fn.select2.amd)var e=u.fn.select2.amd;var t,n,r,h,o,s,f,g,m,v,y,_,i,a,b;function w(e,t){return i.call(e,t)}function l(e,t){var n,r,i,o,s,a,l,c,u,d,p,h=t&&t.split("/"),f=y.map,g=f&&f["*"]||{};if(e){for(s=(e=e.split("/")).length-1,y.nodeIdCompat&&b.test(e[s])&&(e[s]=e[s].replace(b,"")),"."===e[0].charAt(0)&&h&&(e=h.slice(0,h.length-1).concat(e)),u=0;u":">",'"':""","'":"'","/":"/"};return"string"!=typeof e?e:String(e).replace(/[&<>"'\/\\]/g,function(e){return t[e]})},i.appendMany=function(e,t){if("1.7"===o.fn.jquery.substr(0,3)){var n=o();o.map(t,function(e){n=n.add(e)}),t=n}e.append(t)},i.__cache={};var n=0;return i.GetUniqueElementId=function(e){var t=e.getAttribute("data-select2-id");return null==t&&(e.id?(t=e.id,e.setAttribute("data-select2-id",t)):(e.setAttribute("data-select2-id",++n),t=n.toString())),t},i.StoreData=function(e,t,n){var r=i.GetUniqueElementId(e);i.__cache[r]||(i.__cache[r]={}),i.__cache[r][t]=n},i.GetData=function(e,t){var n=i.GetUniqueElementId(e);return t?i.__cache[n]&&null!=i.__cache[n][t]?i.__cache[n][t]:o(e).data(t):i.__cache[n]},i.RemoveData=function(e){var t=i.GetUniqueElementId(e);null!=i.__cache[t]&&delete i.__cache[t],e.removeAttribute("data-select2-id")},i}),e.define("select2/results",["jquery","./utils"],function(h,f){function r(e,t,n){this.$element=e,this.data=n,this.options=t,r.__super__.constructor.call(this)}return f.Extend(r,f.Observable),r.prototype.render=function(){var e=h('
        ');return this.options.get("multiple")&&e.attr("aria-multiselectable","true"),this.$results=e},r.prototype.clear=function(){this.$results.empty()},r.prototype.displayMessage=function(e){var t=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var n=h(''),r=this.options.get("translations").get(e.message);n.append(t(r(e.args))),n[0].className+=" select2-results__message",this.$results.append(n)},r.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},r.prototype.append=function(e){this.hideLoading();var t=[];if(null!=e.results&&0!==e.results.length){e.results=this.sort(e.results);for(var n=0;n",{class:"select2-results__options select2-results__options--nested"});p.append(l),s.append(a),s.append(p)}else this.template(e,t);return f.StoreData(t,"data",e),t},r.prototype.bind=function(t,e){var l=this,n=t.id+"-results";this.$results.attr("id",n),t.on("results:all",function(e){l.clear(),l.append(e.data),t.isOpen()&&(l.setClasses(),l.highlightFirstItem())}),t.on("results:append",function(e){l.append(e.data),t.isOpen()&&l.setClasses()}),t.on("query",function(e){l.hideMessages(),l.showLoading(e)}),t.on("select",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("unselect",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("open",function(){l.$results.attr("aria-expanded","true"),l.$results.attr("aria-hidden","false"),l.setClasses(),l.ensureHighlightVisible()}),t.on("close",function(){l.$results.attr("aria-expanded","false"),l.$results.attr("aria-hidden","true"),l.$results.removeAttr("aria-activedescendant")}),t.on("results:toggle",function(){var e=l.getHighlightedResults();0!==e.length&&e.trigger("mouseup")}),t.on("results:select",function(){var e=l.getHighlightedResults();if(0!==e.length){var t=f.GetData(e[0],"data");"true"==e.attr("aria-selected")?l.trigger("close",{}):l.trigger("select",{data:t})}}),t.on("results:previous",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e);if(!(n<=0)){var r=n-1;0===e.length&&(r=0);var i=t.eq(r);i.trigger("mouseenter");var o=l.$results.offset().top,s=i.offset().top,a=l.$results.scrollTop()+(s-o);0===r?l.$results.scrollTop(0):s-o<0&&l.$results.scrollTop(a)}}),t.on("results:next",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e)+1;if(!(n>=t.length)){var r=t.eq(n);r.trigger("mouseenter");var i=l.$results.offset().top+l.$results.outerHeight(!1),o=r.offset().top+r.outerHeight(!1),s=l.$results.scrollTop()+o-i;0===n?l.$results.scrollTop(0):ithis.$results.outerHeight()||o<0)&&this.$results.scrollTop(i)}},r.prototype.template=function(e,t){var n=this.options.get("templateResult"),r=this.options.get("escapeMarkup"),i=n(e,t);null==i?t.style.display="none":"string"==typeof i?t.innerHTML=r(i):h(t).append(i)},r}),e.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),e.define("select2/selection/base",["jquery","../utils","../keys"],function(n,r,i){function o(e,t){this.$element=e,this.options=t,o.__super__.constructor.call(this)}return r.Extend(o,r.Observable),o.prototype.render=function(){var e=n('');return this._tabindex=0,null!=r.GetData(this.$element[0],"old-tabindex")?this._tabindex=r.GetData(this.$element[0],"old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),e.attr("title",this.$element.attr("title")),e.attr("tabindex",this._tabindex),e.attr("aria-disabled","false"),this.$selection=e},o.prototype.bind=function(e,t){var n=this,r=e.id+"-results";this.container=e,this.$selection.on("focus",function(e){n.trigger("focus",e)}),this.$selection.on("blur",function(e){n._handleBlur(e)}),this.$selection.on("keydown",function(e){n.trigger("keypress",e),e.which===i.SPACE&&e.preventDefault()}),e.on("results:focus",function(e){n.$selection.attr("aria-activedescendant",e.data._resultId)}),e.on("selection:update",function(e){n.update(e.data)}),e.on("open",function(){n.$selection.attr("aria-expanded","true"),n.$selection.attr("aria-owns",r),n._attachCloseHandler(e)}),e.on("close",function(){n.$selection.attr("aria-expanded","false"),n.$selection.removeAttr("aria-activedescendant"),n.$selection.removeAttr("aria-owns"),n.$selection.trigger("focus"),n._detachCloseHandler(e)}),e.on("enable",function(){n.$selection.attr("tabindex",n._tabindex),n.$selection.attr("aria-disabled","false")}),e.on("disable",function(){n.$selection.attr("tabindex","-1"),n.$selection.attr("aria-disabled","true")})},o.prototype._handleBlur=function(e){var t=this;window.setTimeout(function(){document.activeElement==t.$selection[0]||n.contains(t.$selection[0],document.activeElement)||t.trigger("blur",e)},1)},o.prototype._attachCloseHandler=function(e){n(document.body).on("mousedown.select2."+e.id,function(e){var t=n(e.target).closest(".select2");n(".select2.select2-container--open").each(function(){this!=t[0]&&r.GetData(this,"element").select2("close")})})},o.prototype._detachCloseHandler=function(e){n(document.body).off("mousedown.select2."+e.id)},o.prototype.position=function(e,t){t.find(".selection").append(e)},o.prototype.destroy=function(){this._detachCloseHandler(this.container)},o.prototype.update=function(e){throw new Error("The `update` method must be defined in child classes.")},o.prototype.isEnabled=function(){return!this.isDisabled()},o.prototype.isDisabled=function(){return this.options.get("disabled")},o}),e.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(e,t,n,r){function i(){i.__super__.constructor.apply(this,arguments)}return n.Extend(i,t),i.prototype.render=function(){var e=i.__super__.render.call(this);return e.addClass("select2-selection--single"),e.html(''),e},i.prototype.bind=function(t,e){var n=this;i.__super__.bind.apply(this,arguments);var r=t.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",r).attr("role","textbox").attr("aria-readonly","true"),this.$selection.attr("aria-labelledby",r),this.$selection.on("mousedown",function(e){1===e.which&&n.trigger("toggle",{originalEvent:e})}),this.$selection.on("focus",function(e){}),this.$selection.on("blur",function(e){}),t.on("focus",function(e){t.isOpen()||n.$selection.trigger("focus")})},i.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},i.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},i.prototype.selectionContainer=function(){return e("")},i.prototype.update=function(e){if(0!==e.length){var t=e[0],n=this.$selection.find(".select2-selection__rendered"),r=this.display(t,n);n.empty().append(r);var i=t.title||t.text;i?n.attr("title",i):n.removeAttr("title")}else this.clear()},i}),e.define("select2/selection/multiple",["jquery","./base","../utils"],function(i,e,l){function n(e,t){n.__super__.constructor.apply(this,arguments)}return l.Extend(n,e),n.prototype.render=function(){var e=n.__super__.render.call(this);return e.addClass("select2-selection--multiple"),e.html('
          '),e},n.prototype.bind=function(e,t){var r=this;n.__super__.bind.apply(this,arguments),this.$selection.on("click",function(e){r.trigger("toggle",{originalEvent:e})}),this.$selection.on("click",".select2-selection__choice__remove",function(e){if(!r.isDisabled()){var t=i(this).parent(),n=l.GetData(t[0],"data");r.trigger("unselect",{originalEvent:e,data:n})}})},n.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},n.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},n.prototype.selectionContainer=function(){return i('
        • ×
        • ')},n.prototype.update=function(e){if(this.clear(),0!==e.length){for(var t=[],n=0;n×');a.StoreData(r[0],"data",t),this.$selection.find(".select2-selection__rendered").prepend(r)}},e}),e.define("select2/selection/search",["jquery","../utils","../keys"],function(r,a,l){function e(e,t,n){e.call(this,t,n)}return e.prototype.render=function(e){var t=r('');this.$searchContainer=t,this.$search=t.find("input");var n=e.call(this);return this._transferTabIndex(),n},e.prototype.bind=function(e,t,n){var r=this,i=t.id+"-results";e.call(this,t,n),t.on("open",function(){r.$search.attr("aria-controls",i),r.$search.trigger("focus")}),t.on("close",function(){r.$search.val(""),r.$search.removeAttr("aria-controls"),r.$search.removeAttr("aria-activedescendant"),r.$search.trigger("focus")}),t.on("enable",function(){r.$search.prop("disabled",!1),r._transferTabIndex()}),t.on("disable",function(){r.$search.prop("disabled",!0)}),t.on("focus",function(e){r.$search.trigger("focus")}),t.on("results:focus",function(e){e.data._resultId?r.$search.attr("aria-activedescendant",e.data._resultId):r.$search.removeAttr("aria-activedescendant")}),this.$selection.on("focusin",".select2-search--inline",function(e){r.trigger("focus",e)}),this.$selection.on("focusout",".select2-search--inline",function(e){r._handleBlur(e)}),this.$selection.on("keydown",".select2-search--inline",function(e){if(e.stopPropagation(),r.trigger("keypress",e),r._keyUpPrevented=e.isDefaultPrevented(),e.which===l.BACKSPACE&&""===r.$search.val()){var t=r.$searchContainer.prev(".select2-selection__choice");if(0this.maximumInputLength?this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),e.define("select2/data/maximumSelectionLength",[],function(){function e(e,t,n){this.maximumSelectionLength=n.get("maximumSelectionLength"),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("select",function(){r._checkIfMaximumSelected()})},e.prototype.query=function(e,t,n){var r=this;this._checkIfMaximumSelected(function(){e.call(r,t,n)})},e.prototype._checkIfMaximumSelected=function(e,n){var r=this;this.current(function(e){var t=null!=e?e.length:0;0=r.maximumSelectionLength?r.trigger("results:message",{message:"maximumSelected",args:{maximum:r.maximumSelectionLength}}):n&&n()})},e}),e.define("select2/dropdown",["jquery","./utils"],function(t,e){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return e.Extend(n,e.Observable),n.prototype.render=function(){var e=t('');return e.attr("dir",this.options.get("dir")),this.$dropdown=e},n.prototype.bind=function(){},n.prototype.position=function(e,t){},n.prototype.destroy=function(){this.$dropdown.remove()},n}),e.define("select2/dropdown/search",["jquery","../utils"],function(o,e){function t(){}return t.prototype.render=function(e){var t=e.call(this),n=o('');return this.$searchContainer=n,this.$search=n.find("input"),t.prepend(n),t},t.prototype.bind=function(e,t,n){var r=this,i=t.id+"-results";e.call(this,t,n),this.$search.on("keydown",function(e){r.trigger("keypress",e),r._keyUpPrevented=e.isDefaultPrevented()}),this.$search.on("input",function(e){o(this).off("keyup")}),this.$search.on("keyup input",function(e){r.handleSearch(e)}),t.on("open",function(){r.$search.attr("tabindex",0),r.$search.attr("aria-controls",i),r.$search.trigger("focus"),window.setTimeout(function(){r.$search.trigger("focus")},0)}),t.on("close",function(){r.$search.attr("tabindex",-1),r.$search.removeAttr("aria-controls"),r.$search.removeAttr("aria-activedescendant"),r.$search.val(""),r.$search.trigger("blur")}),t.on("focus",function(){t.isOpen()||r.$search.trigger("focus")}),t.on("results:all",function(e){null!=e.query.term&&""!==e.query.term||(r.showSearch(e)?r.$searchContainer.removeClass("select2-search--hide"):r.$searchContainer.addClass("select2-search--hide"))}),t.on("results:focus",function(e){e.data._resultId?r.$search.attr("aria-activedescendant",e.data._resultId):r.$search.removeAttr("aria-activedescendant")})},t.prototype.handleSearch=function(e){if(!this._keyUpPrevented){var t=this.$search.val();this.trigger("query",{term:t})}this._keyUpPrevented=!1},t.prototype.showSearch=function(e,t){return!0},t}),e.define("select2/dropdown/hidePlaceholder",[],function(){function e(e,t,n,r){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n,r)}return e.prototype.append=function(e,t){t.results=this.removePlaceholder(t.results),e.call(this,t)},e.prototype.normalizePlaceholder=function(e,t){return"string"==typeof t&&(t={id:"",text:t}),t},e.prototype.removePlaceholder=function(e,t){for(var n=t.slice(0),r=t.length-1;0<=r;r--){var i=t[r];this.placeholder.id===i.id&&n.splice(r,1)}return n},e}),e.define("select2/dropdown/infiniteScroll",["jquery"],function(n){function e(e,t,n,r){this.lastParams={},e.call(this,t,n,r),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return e.prototype.append=function(e,t){this.$loadingMore.remove(),this.loading=!1,e.call(this,t),this.showLoadingMore(t)&&(this.$results.append(this.$loadingMore),this.loadMoreIfNeeded())},e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("query",function(e){r.lastParams=e,r.loading=!0}),t.on("query:append",function(e){r.lastParams=e,r.loading=!0}),this.$results.on("scroll",this.loadMoreIfNeeded.bind(this))},e.prototype.loadMoreIfNeeded=function(){var e=n.contains(document.documentElement,this.$loadingMore[0]);if(!this.loading&&e){var t=this.$results.offset().top+this.$results.outerHeight(!1);this.$loadingMore.offset().top+this.$loadingMore.outerHeight(!1)<=t+50&&this.loadMore()}},e.prototype.loadMore=function(){this.loading=!0;var e=n.extend({},{page:1},this.lastParams);e.page++,this.trigger("query:append",e)},e.prototype.showLoadingMore=function(e,t){return t.pagination&&t.pagination.more},e.prototype.createLoadingMore=function(){var e=n('
        • '),t=this.options.get("translations").get("loadingMore");return e.html(t(this.lastParams)),e},e}),e.define("select2/dropdown/attachBody",["jquery","../utils"],function(f,a){function e(e,t,n){this.$dropdownParent=f(n.get("dropdownParent")||document.body),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("open",function(){r._showDropdown(),r._attachPositioningHandler(t),r._bindContainerResultHandlers(t)}),t.on("close",function(){r._hideDropdown(),r._detachPositioningHandler(t)}),this.$dropdownContainer.on("mousedown",function(e){e.stopPropagation()})},e.prototype.destroy=function(e){e.call(this),this.$dropdownContainer.remove()},e.prototype.position=function(e,t,n){t.attr("class",n.attr("class")),t.removeClass("select2"),t.addClass("select2-container--open"),t.css({position:"absolute",top:-999999}),this.$container=n},e.prototype.render=function(e){var t=f(""),n=e.call(this);return t.append(n),this.$dropdownContainer=t},e.prototype._hideDropdown=function(e){this.$dropdownContainer.detach()},e.prototype._bindContainerResultHandlers=function(e,t){if(!this._containerResultsHandlersBound){var n=this;t.on("results:all",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:append",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:message",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("select",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("unselect",function(){n._positionDropdown(),n._resizeDropdown()}),this._containerResultsHandlersBound=!0}},e.prototype._attachPositioningHandler=function(e,t){var n=this,r="scroll.select2."+t.id,i="resize.select2."+t.id,o="orientationchange.select2."+t.id,s=this.$container.parents().filter(a.hasScroll);s.each(function(){a.StoreData(this,"select2-scroll-position",{x:f(this).scrollLeft(),y:f(this).scrollTop()})}),s.on(r,function(e){var t=a.GetData(this,"select2-scroll-position");f(this).scrollTop(t.y)}),f(window).on(r+" "+i+" "+o,function(e){n._positionDropdown(),n._resizeDropdown()})},e.prototype._detachPositioningHandler=function(e,t){var n="scroll.select2."+t.id,r="resize.select2."+t.id,i="orientationchange.select2."+t.id;this.$container.parents().filter(a.hasScroll).off(n),f(window).off(n+" "+r+" "+i)},e.prototype._positionDropdown=function(){var e=f(window),t=this.$dropdown.hasClass("select2-dropdown--above"),n=this.$dropdown.hasClass("select2-dropdown--below"),r=null,i=this.$container.offset();i.bottom=i.top+this.$container.outerHeight(!1);var o={height:this.$container.outerHeight(!1)};o.top=i.top,o.bottom=i.top+o.height;var s=this.$dropdown.outerHeight(!1),a=e.scrollTop(),l=e.scrollTop()+e.height(),c=ai.bottom+s,d={left:i.left,top:o.bottom},p=this.$dropdownParent;"static"===p.css("position")&&(p=p.offsetParent());var h={top:0,left:0};(f.contains(document.body,p[0])||p[0].isConnected)&&(h=p.offset()),d.top-=h.top,d.left-=h.left,t||n||(r="below"),u||!c||t?!c&&u&&t&&(r="below"):r="above",("above"==r||t&&"below"!==r)&&(d.top=o.top-h.top-s),null!=r&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+r),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+r)),this.$dropdownContainer.css(d)},e.prototype._resizeDropdown=function(){var e={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(e.minWidth=e.width,e.position="relative",e.width="auto"),this.$dropdown.css(e)},e.prototype._showDropdown=function(e){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},e}),e.define("select2/dropdown/minimumResultsForSearch",[],function(){function e(e,t,n,r){this.minimumResultsForSearch=n.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),e.call(this,t,n,r)}return e.prototype.showSearch=function(e,t){return!(function e(t){for(var n=0,r=0;r');return e.attr("dir",this.options.get("dir")),this.$container=e,this.$container.addClass("select2-container--"+this.options.get("theme")),u.StoreData(e[0],"element",this.$element),e},d}),e.define("jquery-mousewheel",["jquery"],function(e){return e}),e.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults","./select2/utils"],function(i,e,o,t,s){if(null==i.fn.select2){var a=["open","close","destroy"];i.fn.select2=function(t){if("object"==typeof(t=t||{}))return this.each(function(){var e=i.extend(!0,{},t);new o(i(this),e)}),this;if("string"!=typeof t)throw new Error("Invalid arguments for Select2: "+t);var n,r=Array.prototype.slice.call(arguments,1);return this.each(function(){var e=s.GetData(this,"select2");null==e&&window.console&&console.error&&console.error("The select2('"+t+"') method was called on an element that is not using Select2."),n=e[t].apply(e,r)}),-1 Date: Fri, 25 Jun 2021 13:47:09 +1000 Subject: [PATCH 095/445] Fixes for base template --- InvenTree/templates/base.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html index 128cbba2dd..f35dd09fc8 100644 --- a/InvenTree/templates/base.html +++ b/InvenTree/templates/base.html @@ -40,8 +40,8 @@ - - + + @@ -136,7 +136,7 @@ - + From 4cf69a5a4cee2e96e7e6af3691da60305f1db467 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 25 Jun 2021 13:47:33 +1000 Subject: [PATCH 096/445] Custom rendering functions --- InvenTree/templates/js/forms.js | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 036928616c..cf6cbd5855 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -346,14 +346,19 @@ function initializeRelatedFields(modal, url, fields, options) { // Find the select element and attach a select2 to it var select = $(modal).find(`#id_${name}`); - console.log('modal:', modal); + // TODO: Add 'placeholder' support for entry select2 fields + + // TODO: Add 'pagination' support for the query select.select2({ ajax: { url: field.api_url, dataType: 'json', + allowClear: !field.required, // Allow non required fields to be cleared dropdownParent: $(modal), dropdownAutoWidth: false, + delay: 250, + cache: true, // matcher: partialMatcher, data: function(params) { // Re-format search term into InvenTree API style @@ -385,16 +390,20 @@ function initializeRelatedFields(modal, url, fields, options) { return results; }, - templateResult: function(item, container) { - // Custom formatting for the item - console.log("templateResult:", item); - if (field.model) { - // If the 'model' is specified, hand it off to the custom model render - return renderModelData(field.model, item, field, options); - } else { - // Simply render the 'text' parameter - return item.text; - } + }, + templateResult: function(item, container) { + console.log('templateResult:', item); + return item.text; + }, + templateSelection: function(item, container) { + // Custom formatting for the item + console.log("templateSelection:", item); + if (field.model) { + // If the 'model' is specified, hand it off to the custom model render + return renderModelData(field.model, item, field, options); + } else { + // Simply render the 'text' parameter + return item.text; } } }); From d411728be61e75a216bec4ec60264cab2420f08a Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 25 Jun 2021 13:58:36 +1000 Subject: [PATCH 097/445] Start of custom rendering support based on model --- InvenTree/templates/js/forms.js | 172 +++++++++++++++++++------------- 1 file changed, 104 insertions(+), 68 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index cf6cbd5855..d0c0cb5424 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -343,90 +343,126 @@ function initializeRelatedFields(modal, url, fields, options) { continue; } - // Find the select element and attach a select2 to it - var select = $(modal).find(`#id_${name}`); - - // TODO: Add 'placeholder' support for entry select2 fields - - // TODO: Add 'pagination' support for the query - - select.select2({ - ajax: { - url: field.api_url, - dataType: 'json', - allowClear: !field.required, // Allow non required fields to be cleared - dropdownParent: $(modal), - dropdownAutoWidth: false, - delay: 250, - cache: true, - // matcher: partialMatcher, - data: function(params) { - // Re-format search term into InvenTree API style - return { - search: params.term, - }; - }, - processResults: function(data) { - // Convert the returned InvenTree data into select2-friendly format - var rows = []; - - // Only ever show the first x items - for (var idx = 0; idx < data.length && idx < 50; idx++) { - var row = data[idx]; - - // Reformat to match select2 requirements - row.id = row.id || row.pk; - - // TODO: Fix me? - row.text = `This is ${field.api_url}${row.id}/`; - - rows.push(row); - } - - // Ref: https://select2.org/data-sources/formats - var results = { - results: rows, - }; - - return results; - }, - }, - templateResult: function(item, container) { - console.log('templateResult:', item); - return item.text; - }, - templateSelection: function(item, container) { - // Custom formatting for the item - console.log("templateSelection:", item); - if (field.model) { - // If the 'model' is specified, hand it off to the custom model render - return renderModelData(field.model, item, field, options); - } else { - // Simply render the 'text' parameter - return item.text; - } - } - }); + initializeRelatedField(modal, name, field, options); } } +/* + * Initializea single related-field + * + * argument: + * - modal: DOM identifier for the modal window + * - name: name of the field e.g. 'location' + * - field: Field definition from the OPTIONS request + * - options: Original options object provided by the client + */ +function initializeRelatedField(modal, name, field, options) { + + // Find the select element and attach a select2 to it + var select = $(modal).find(`#id_${name}`); + + // TODO: Add 'placeholder' support for entry select2 fields + + // TODO: Add 'pagination' support for the query + + select.select2({ + ajax: { + url: field.api_url, + dataType: 'json', + allowClear: !field.required, // Allow non required fields to be cleared + dropdownParent: $(modal), + dropdownAutoWidth: false, + delay: 250, + cache: true, + // matcher: partialMatcher, + data: function(params) { + // Re-format search term into InvenTree API style + return { + search: params.term, + }; + }, + processResults: function(data) { + // Convert the returned InvenTree data into select2-friendly format + var rows = []; + + // Only ever show the first x items + for (var idx = 0; idx < data.length && idx < 50; idx++) { + var row = data[idx]; + + // Reformat to match select2 requirements + row.id = row.id || row.pk; + + // TODO: Fix me? + row.text = `This is ${field.api_url}${row.id}/`; + + rows.push(row); + } + + // Ref: https://select2.org/data-sources/formats + var results = { + results: rows, + }; + + return results; + }, + }, + templateResult: function(item, container) { + // Custom formatting for the search results + if (field.model) { + // If the 'model' is specified, hand it off to the custom model render + return renderModelData(name, field.model, item, field, options); + } else { + // Simply render the 'text' parameter + return item.text; + } + }, + templateSelection: function(item, container) { + // Custom formatting for selected item + if (field.model) { + // If the 'model' is specified, hand it off to the custom model render + return renderModelData(name, field.model, item, field, options); + } else { + // Simply render the 'text' parameter + return item.text; + } + } + }); +} + + /* * Render a "foreign key" model reference in a select2 instance. * Allows custom rendering with access to the entire serialized object. * * arguments: + * - name: The name of the field e.g. 'location' * - model: The name of the InvenTree model e.g. 'stockitem' * - data: The JSON data representation of the modal instance (GET request) * - parameters: The field definition (OPTIONS) request * - options: Other options provided at time of modal creation by the client */ -function renderModelData(model, data, paramaters, options) { +function renderModelData(name, model, data, paramaters, options) { - console.log(model, '->', data); + // TODO: Implement this function for various models - // TODO: Implement? - return data.text; + var html = null; + + switch (model) { + case 'company': + html = `${data.name} - ${data.description}`; + default: + break; + } + + if (html != null) { + // Render HTML to an object + var $state = $(html); + return $state; + } else { + // Simple text rendering + return data.text; + } } From b29db6f258e29bbda44824f62b2e75394f52e237 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 25 Jun 2021 15:22:40 +1000 Subject: [PATCH 098/445] Remove old debug message --- InvenTree/templates/js/forms.js | 4 ++++ InvenTree/templates/js/modals.js | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index d0c0cb5424..a1937a5ef8 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -444,6 +444,10 @@ function initializeRelatedField(modal, name, field, options) { */ function renderModelData(name, model, data, paramaters, options) { + if (!data) { + return '{% trans "Searching" %}...'; + } + // TODO: Implement this function for various models var html = null; diff --git a/InvenTree/templates/js/modals.js b/InvenTree/templates/js/modals.js index 03893a47b8..75e0f3672a 100644 --- a/InvenTree/templates/js/modals.js +++ b/InvenTree/templates/js/modals.js @@ -991,8 +991,6 @@ function hideModalImage() { function showModalImage(image_url) { // Display full-screen modal image - console.log('showing modal image: ' + image_url); - var modal = $('#modal-image-dialog'); // Set image content From 4921cd47f9f8caa7fab488200dbe6476a70868e1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 25 Jun 2021 07:40:01 +0200 Subject: [PATCH 099/445] refactor for better readabilty --- InvenTree/part/templates/part/prices.html | 30 +++++++++++++---------- InvenTree/templates/js/part.js | 8 ++++++ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/InvenTree/part/templates/part/prices.html b/InvenTree/part/templates/part/prices.html index 1b8b3959cf..cf719711dc 100644 --- a/InvenTree/part/templates/part/prices.html +++ b/InvenTree/part/templates/part/prices.html @@ -340,7 +340,7 @@ borderWidth: 1 }] } - var StockPriceChart = loadStockPricingChart(document.getElementById('StockPriceChart'), pricedata) + var StockPriceChart = loadStockPricingChart($('#StockPriceChart'), pricedata) var bom_colors = randomColor({hue: 'green', count: {{ bom_parts|length }} }) var bomdata = { labels: [{% for line in bom_parts %}'{{ line.name }}',{% endfor %}], @@ -369,12 +369,14 @@ {% if show_internal_price and roles.sales_order.view %} initPriceBreakSet( $('#internal-price-break-table'), - {{part.id}}, - 'internal price break', - 'internal-price', - "{% url 'api-part-internal-price-list' %}", - $('#new-internal-price-break'), - '{% url 'internal-price-break-create' %}' + { + part_id: {{part.id}}, + pb_human_name: 'internal price break', + pb_url_slug: 'internal-price', + pb_url: '{% url 'api-part-internal-price-list' %}', + pb_new_btn: $('#new-internal-price-break'), + pb_new_url: '{% url 'internal-price-break-create' %}', + }, ); {% endif %} @@ -393,12 +395,14 @@ {% if part.salable and roles.sales_order.view %} initPriceBreakSet( $('#price-break-table'), - {{part.id}}, - 'sale price break', - 'sale-price', - "{% url 'api-part-sale-price-list' %}", - $('#new-price-break'), - '{% url 'sale-price-break-create' %}' + { + part_id: {{part.id}}, + pb_human_name: 'sale price break', + pb_url_slug: 'sale-price', + pb_url: "{% url 'api-part-sale-price-list' %}", + pb_new_btn: $('#new-price-break'), + pb_new_url: '{% url 'sale-price-break-create' %}', + }, ); {% endif %} diff --git a/InvenTree/templates/js/part.js b/InvenTree/templates/js/part.js index 82fd416e15..37fd36486b 100644 --- a/InvenTree/templates/js/part.js +++ b/InvenTree/templates/js/part.js @@ -817,6 +817,14 @@ function loadPriceBreakTable(table, options) { }); } +function initPriceBreakSet(table, options) { + + var part_id = options.part_id; + var pb_human_name = options.pb_human_name; + var pb_url_slug = options.pb_url_slug; + var pb_url = options.pb_url; + var pb_new_btn = options.pb_new_btn; + var pb_new_url = options.pb_new_url; function initPriceBreakSet(table, part_id, pb_human_name, pb_url_slug, pb_url, pb_new_btn, pb_new_url) { From d28d66795d87327536d97bc479ec4179fcb5a6d3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 25 Jun 2021 07:41:00 +0200 Subject: [PATCH 100/445] linked price break graphs --- InvenTree/InvenTree/static/css/inventree.css | 12 ++++- InvenTree/part/templates/part/prices.html | 12 ++++- InvenTree/templates/js/part.js | 46 +++++++++++++++++++- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index eed6c6ad21..7bdc6e8a9b 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -960,4 +960,14 @@ input[type="date"].form-control, input[type="time"].form-control, input[type="da .sidebar-icon { min-width: 19px; -} \ No newline at end of file +} + +.row.full-height { + display: flex; + flex-wrap: wrap; + } + +.row.full-height > [class*='col-'] { + display: flex; + flex-direction: column; + } diff --git a/InvenTree/part/templates/part/prices.html b/InvenTree/part/templates/part/prices.html index cf719711dc..1214239fe4 100644 --- a/InvenTree/part/templates/part/prices.html +++ b/InvenTree/part/templates/part/prices.html @@ -176,8 +176,11 @@

          {% trans "Internal Cost" %}

          -
          +
          +
          + +
          @@ -224,8 +227,11 @@

          {% trans "Sale Cost" %}

          -
          +
          +
          + +
          @@ -376,6 +382,7 @@ pb_url: '{% url 'api-part-internal-price-list' %}', pb_new_btn: $('#new-internal-price-break'), pb_new_url: '{% url 'internal-price-break-create' %}', + linkedGraph: $('#InternalPriceBreakChart'), }, ); {% endif %} @@ -402,6 +409,7 @@ pb_url: "{% url 'api-part-sale-price-list' %}", pb_new_btn: $('#new-price-break'), pb_new_url: '{% url 'sale-price-break-create' %}', + linkedGraph: $('#SalePriceBreakChart'), }, ); {% endif %} diff --git a/InvenTree/templates/js/part.js b/InvenTree/templates/js/part.js index 37fd36486b..75e925266a 100644 --- a/InvenTree/templates/js/part.js +++ b/InvenTree/templates/js/part.js @@ -776,6 +776,8 @@ function loadPriceBreakTable(table, options) { var name = options.name || 'pricebreak'; var human_name = options.human_name || 'price break'; + var linkedGraph = options.linkedGraph || null; + var chart = null; table.inventreeTable({ name: name, @@ -784,6 +786,31 @@ function loadPriceBreakTable(table, options) { return `{% trans "No ${human_name} information found" %}`; }, url: options.url, + onLoadSuccess: function(tableData) { + if (linkedGraph) { + var labels = Array.from(tableData, x => x.quantity); + var data = Array.from(tableData, x => parseFloat(x.price)); + + // destroy chart if exists + if (chart){ + chart.destroy(); + } + chart = loadLineChart(linkedGraph, + { + labels: labels, + datasets: [ + { + label: '{% trans "Unit Price" %}', + data: data, + backgroundColor: 'rgba(255, 206, 86, 0.2)', + borderColor: 'rgb(255, 206, 86)', + stepped: true, + fill: true, + },] + } + ); + } + }, columns: [ { field: 'pk', @@ -817,6 +844,20 @@ function loadPriceBreakTable(table, options) { }); } +function loadLineChart(context, data) { + return new Chart(context, { + type: 'line', + data: data, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: {position: 'bottom'}, + } + } + }); +} + function initPriceBreakSet(table, options) { var part_id = options.part_id; @@ -826,14 +867,15 @@ function initPriceBreakSet(table, options) { var pb_new_btn = options.pb_new_btn; var pb_new_url = options.pb_new_url; -function initPriceBreakSet(table, part_id, pb_human_name, pb_url_slug, pb_url, pb_new_btn, pb_new_url) { - + var linkedGraph = options.linkedGraph || null; + loadPriceBreakTable( table, { name: pb_url_slug, human_name: pb_human_name, url: pb_url, + linkedGraph: linkedGraph, } ); From 565631ef87696dff672024b847f6f91aecd020b7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 26 Jun 2021 14:09:35 +1000 Subject: [PATCH 101/445] More features - Custom renderers depending on specified model name - Paginate API results --- InvenTree/InvenTree/static/css/inventree.css | 7 ++ InvenTree/InvenTree/urls.py | 1 + InvenTree/templates/base.html | 1 + InvenTree/templates/js/forms.js | 73 +++++++++++++---- InvenTree/templates/js/model_renderers.js | 83 ++++++++++++++++++++ 5 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 InvenTree/templates/js/model_renderers.js diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index 573f966a41..706bc32327 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -972,4 +972,11 @@ input[type="date"].form-control, input[type="time"].form-control, input[type="da .select2-container { width: 100%; +} + +.select2-thumbnail { + max-width: 24px; + max-height: 24px; + border-radius: 4px; + margin-right: 10px; } \ No newline at end of file diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index 2ec7b02f23..6a7ae7bdfd 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -105,6 +105,7 @@ settings_urls = [ dynamic_javascript_urls = [ url(r'^api.js', DynamicJsView.as_view(template_name='js/api.js'), name='api.js'), url(r'^forms.js', DynamicJsView.as_view(template_name='js/forms.js'), name='forms.js'), + url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/model_renderers.js'), name='model_renderers.js'), url(r'^modals.js', DynamicJsView.as_view(template_name='js/modals.js'), name='modals.js'), url(r'^barcode.js', DynamicJsView.as_view(template_name='js/barcode.js'), name='barcode.js'), url(r'^bom.js', DynamicJsView.as_view(template_name='js/bom.js'), name='bom.js'), diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html index f35dd09fc8..ec7e31a7f0 100644 --- a/InvenTree/templates/base.html +++ b/InvenTree/templates/base.html @@ -150,6 +150,7 @@ + diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index a1937a5ef8..a68def10b0 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -364,7 +364,8 @@ function initializeRelatedField(modal, name, field, options) { // TODO: Add 'placeholder' support for entry select2 fields - // TODO: Add 'pagination' support for the query + // limit size for AJAX requests + var pageSize = options.pageSize || 25; select.select2({ ajax: { @@ -377,31 +378,52 @@ function initializeRelatedField(modal, name, field, options) { cache: true, // matcher: partialMatcher, data: function(params) { + + if (!params.page) { + offset = 0; + } else { + offset = (params.page - 1) * pageSize; + } + // Re-format search term into InvenTree API style return { search: params.term, + offset: offset, + limit: pageSize, }; }, - processResults: function(data) { + processResults: function(response) { // Convert the returned InvenTree data into select2-friendly format - var rows = []; - // Only ever show the first x items - for (var idx = 0; idx < data.length && idx < 50; idx++) { - var row = data[idx]; + var data = []; - // Reformat to match select2 requirements - row.id = row.id || row.pk; + var more = false; - // TODO: Fix me? - row.text = `This is ${field.api_url}${row.id}/`; + if ('count' in response && 'results' in response) { + // Response is paginated + data = response.results; - rows.push(row); + // 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; } // Ref: https://select2.org/data-sources/formats var results = { - results: rows, + results: data, + pagination: { + more: more, + } }; return results; @@ -442,7 +464,7 @@ function initializeRelatedField(modal, name, field, options) { * - parameters: The field definition (OPTIONS) request * - options: Other options provided at time of modal creation by the client */ -function renderModelData(name, model, data, paramaters, options) { +function renderModelData(name, model, data, parameters, options) { if (!data) { return '{% trans "Searching" %}...'; @@ -452,20 +474,41 @@ function renderModelData(name, model, data, paramaters, options) { var html = null; + var renderer = null; + + // Find a custom renderer switch (model) { case 'company': - html = `${data.name} - ${data.description}`; + renderer = renderCompany; + break; + case 'stockitem': + renderer = renderStockItem; + break; + case 'stocklocation': + renderer = renderStockLocation; + break; + case 'part': + renderer = renderPart; + break; + case 'partcategory': + renderer = renderPartCategory; + break; default: break; } + + if (renderer != null) { + html = renderer(name, data, parameters, options); + } if (html != null) { // Render HTML to an object var $state = $(html); return $state; } else { + console.log(`ERROR: Rendering not implemented for model '${model}'`); // Simple text rendering - return data.text; + return data.id; } } diff --git a/InvenTree/templates/js/model_renderers.js b/InvenTree/templates/js/model_renderers.js new file mode 100644 index 0000000000..924d85d35d --- /dev/null +++ b/InvenTree/templates/js/model_renderers.js @@ -0,0 +1,83 @@ +/* + * This file contains functions for rendering various InvenTree database models, + * in particular for displaying them in modal forms in a 'select2' context. + * + * Each renderer is provided with three arguments: + * + * - name: The 'name' of the model instance in the referring model + * - data: JSON data which represents the model instance. Returned via a GET request. + * - parameters: The field parameters provided via an OPTIONS request to the endpoint. + * - options: User options provided by the client + */ + + +// Renderer for "Company" model +function renderCompany(name, data, parameters, options) { + + var html = `${data.name} - ${data.description}`; + + return html; +} + + +// Renderer for "StockItem" model +function renderStockItem(name, data, parameters, options) { + + // TODO - Include part detail, location, quantity + // TODO - Include part image +} + + +// Renderer for "StockLocation" model +function renderStockLocation(name, data, parameters, options) { + + var html = `${data.name}`; + + if (data.description) { + html += ` - ${data.description}`; + } + + if (data.pathstring) { + html += `

          ${data.pathstring}

          `; + } + + return html; +} + + +// Renderer for "Part" model +function renderPart(name, data, parameters, options) { + + var image = data.image; + + if (!image) { + image = `/static/img/blank_image.png`; + } + + var html = ``; + + html += ` ${data.full_name ?? data.name}`; + + if (data.description) { + html += ` - ${data.description}`; + } + + return html; +} + + +// Renderer for "PartCategory" model +function renderPartCategory(name, data, parameters, options) { + + var html = `${data.name}`; + + if (data.description) { + html += ` - ${data.description}`; + } + + if (data.pathstring) { + html += `

          ${data.pathstring}

          `; + } + + return html; +} \ No newline at end of file From 949c7dd81bc9c691e1925cd3ea0dc025d54f8e9b Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 26 Jun 2021 14:30:14 +1000 Subject: [PATCH 102/445] Set modal form title --- InvenTree/part/api.py | 3 ++- InvenTree/templates/js/forms.js | 21 +++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 60cea121a7..8ef6902600 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -337,8 +337,9 @@ class PartDetail(generics.RetrieveUpdateDestroyAPIView): def get_serializer(self, *args, **kwargs): + # By default, include 'category_detail' information in the detail view try: - kwargs['category_detail'] = str2bool(self.request.query_params.get('category_detail', False)) + kwargs['category_detail'] = str2bool(self.request.query_params.get('category_detail', True)) except AttributeError: pass diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index a68def10b0..5996e1a1cd 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -161,17 +161,18 @@ function constructChangeForm(url, fields, options={}) { * and construct a modal form based on the response. * * arguments: - * - method: The HTTP method e.g. 'PUT', 'POST', 'DELETE', + * - url: API URL * * options: - * - method: + * - method: The HTTP method e.g. 'PUT', 'POST', 'DELETE', + * - title: The form title + * - fields: list of fields to display + * - exclude: List of fields to exclude */ -function constructForm(url, method, options={}) { +function constructForm(url, options={}) { - method = method.toUpperCase(); - - // Store the method in the options struct - options.method = method; + // Default HTTP method + options.method = options.method || 'PATCH'; // Request OPTIONS endpoint from the API getApiEndpointOptions(url, function(OPTIONS) { @@ -183,7 +184,7 @@ function constructForm(url, method, options={}) { * First we must determine if the user has the correct permissions! */ - switch (method) { + switch (options.method) { case 'POST': if (canCreate(OPTIONS)) { constructCreateForm(url, OPTIONS.actions.POST, options); @@ -322,6 +323,10 @@ function constructFormBody(url, fields, options={}) { $(modal + ' .select2-container').css('width', '100%'); modalShowSubmitButton(modal, true); + + var title = options.title || '{% trans "Form Title" %}'; + + modalSetTitle(modal, title); } From e9db72017d4ba17d0d2e65a74d0c9a24d704c611 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 26 Jun 2021 17:54:14 +1000 Subject: [PATCH 103/445] Extract field data on submit --- InvenTree/templates/js/forms.js | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 5996e1a1cd..93ab9e696e 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -223,7 +223,7 @@ function constructForm(url, options={}) { } break; default: - console.log(`constructForm() called with invalid method '${method}'`); + console.log(`constructForm() called with invalid method '${options.method}'`); break; } }); @@ -302,9 +302,10 @@ function constructFormBody(url, fields, options={}) { modalEnable(modal, true); - var title = options.title || '{% trans "Form Title" %}'; - - modalSetTitle(modal, title); + // Set the form title and button labels + modalSetTitle(modal, options.title || '{% trans "Form Title" %}'); + modalSetSubmitText(options.submitText || '{% trans "Submit" %}'); + modalSetCloseText(options.cancelText || '{% trans "Cancel" %}'); // Insert generated form content $(modal).find('.modal-form-content').html(html); @@ -324,9 +325,28 @@ function constructFormBody(url, fields, options={}) { modalShowSubmitButton(modal, true); - var title = options.title || '{% trans "Form Title" %}'; + $(modal).off('click', '#modal-form-submit'); + $(modal).on('click', '#modal-form-submit', function() { - modalSetTitle(modal, title); + var patch_data = {}; + + // Construct submit data + field_names.forEach(function(name) { + var field = fields[name] || null; + + if (field) { + var field_value = getFieldValue(name); + + patch_data[name] = field_value; + } else { + console.log(`Could not find field matching '${name}'`); + } + }) + + + console.log(patch_data); + + }); } From 9dd2765bd222058b70b7cc1bd686a0934915c9d9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 26 Jun 2021 19:11:20 +1000 Subject: [PATCH 104/445] Handle returned error messages --- InvenTree/templates/js/api.js | 5 +- InvenTree/templates/js/forms.js | 188 +++++++++++++++++++++++--------- 2 files changed, 142 insertions(+), 51 deletions(-) diff --git a/InvenTree/templates/js/api.js b/InvenTree/templates/js/api.js index b43bcc8419..aa446028a5 100644 --- a/InvenTree/templates/js/api.js +++ b/InvenTree/templates/js/api.js @@ -103,10 +103,11 @@ function inventreePut(url, data={}, options={}) { } }, error: function(xhr, ajaxOptions, thrownError) { - console.error('Error on UPDATE to ' + url); - console.error(thrownError); if (options.error) { options.error(xhr, ajaxOptions, thrownError); + } else { + console.error(`Error on ${method} to '${url}' - STATUS ${xhr.status}`); + console.error(thrownError); } }, complete: function(xhr, status) { diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 93ab9e696e..8a302bc2b1 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -79,7 +79,7 @@ function canDelete(OPTIONS) { * Get the API endpoint options at the provided URL, * using a HTTP options request. */ -function getApiEndpointOptions(url, callback, options={}) { +function getApiEndpointOptions(url, callback, options) { // Return the ajax request object $.ajax({ @@ -108,10 +108,10 @@ function getApiEndpointOptions(url, callback, options={}) { * options: * - */ -function constructCreateForm(url, fields, options={}) { +function constructCreateForm(fields, options) { // We should have enough information to create the form! - constructFormBody(url, fields, options); + constructFormBody(fields, options); } @@ -124,11 +124,11 @@ function constructCreateForm(url, fields, options={}) { * options: * - */ -function constructChangeForm(url, fields, options={}) { +function constructChangeForm(fields, options) { // Request existing data from the API endpoint $.ajax({ - url: url, + url: options.url, type: 'GET', contentType: 'application/json', dataType: 'json', @@ -145,7 +145,7 @@ function constructChangeForm(url, fields, options={}) { } } - constructFormBody(url, fields, options); + constructFormBody(fields, options); }, error: function(request, status, error) { // TODO: Handle error here @@ -160,16 +160,16 @@ function constructChangeForm(url, fields, options={}) { * Request API OPTIONS data from the server, * and construct a modal form based on the response. * - * arguments: - * - url: API URL - * * options: * - method: The HTTP method e.g. 'PUT', 'POST', 'DELETE', * - title: The form title * - fields: list of fields to display * - exclude: List of fields to exclude */ -function constructForm(url, options={}) { +function constructForm(url, options) { + + // Save the URL + options.url = url; // Default HTTP method options.method = options.method || 'PATCH'; @@ -187,7 +187,7 @@ function constructForm(url, options={}) { switch (options.method) { case 'POST': if (canCreate(OPTIONS)) { - constructCreateForm(url, OPTIONS.actions.POST, options); + constructCreateForm(OPTIONS.actions.POST, options); } else { // User does not have permission to POST to the endpoint console.log('cannot POST'); @@ -197,7 +197,7 @@ function constructForm(url, options={}) { case 'PUT': case 'PATCH': if (canChange(OPTIONS)) { - constructChangeForm(url, OPTIONS.actions.PUT, options); + constructChangeForm(OPTIONS.actions.PUT, options); } else { // User does not have permission to PUT/PATCH to the endpoint // TODO @@ -231,7 +231,7 @@ function constructForm(url, options={}) { -function constructFormBody(url, fields, options={}) { +function constructFormBody(fields, options) { var html = ''; @@ -298,7 +298,10 @@ function constructFormBody(url, fields, options={}) { // TODO: Dynamically create the modals, // so that we can have an infinite number of stacks! - var modal = '#modal-form'; + + options.modal = options.modal || '#modal-form'; + + var modal = options.modal; modalEnable(modal, true); @@ -313,12 +316,9 @@ function constructFormBody(url, fields, options={}) { $(modal).modal('show'); // Setup related fields - initializeRelatedFields(modal, url, fields, options) + initializeRelatedFields(fields, options) attachToggle(modal); - // attachSelect(modal); - - //$(modal + ' .select').select2(); $(modal + ' .select2-container').addClass('select-full-width'); $(modal + ' .select2-container').css('width', '100%'); @@ -328,29 +328,119 @@ function constructFormBody(url, fields, options={}) { $(modal).off('click', '#modal-form-submit'); $(modal).on('click', '#modal-form-submit', function() { - var patch_data = {}; - - // Construct submit data - field_names.forEach(function(name) { - var field = fields[name] || null; - - if (field) { - var field_value = getFieldValue(name); - - patch_data[name] = field_value; - } else { - console.log(`Could not find field matching '${name}'`); - } - }) - - - console.log(patch_data); - + submitFormData(fields, options); }); } -function initializeRelatedFields(modal, url, fields, options) { +/* + * Submit form data to the server. + * + */ +function submitFormData(fields, options) { + + // Data to be sent to the server + var data = {}; + + // Extract values for each field + options.field_names.forEach(function(name) { + + var field = fields[name] || null; + + if (field) { + var value = getFieldValue(name); + + // TODO - Custom parsing depending on type? + + data[name] = value; + } else { + console.log(`WARNING: Could not find field matching '${name}'`); + } + }); + + // Submit data + inventreePut( + options.url, + data, + { + method: options.method, + success: function(response, status) { + console.log('success', '->', status); + }, + error: function(xhr, status, thrownError) { + + switch (xhr.status) { + case 400: // Bad request + handleFormErrors(xhr.responseJSON, fields, options); + break; + default: + console.log(`WARNING: Unhandled response code - ${xhr.status}`); + break; + } + } + } + ); +} + + +/* + * Remove all error text items from the form + */ +function clearFormErrors(options) { + + // Remove the individual error messages + $(options.modal).find('.form-error-message').remove(); + + // Remove the "has error" class + $(options.modal).find('.has-error').removeClass('has-error'); +} + + +/* + * Display form error messages as returned from the server. + * + * arguments: + * - errors: The JSON error response from the server + * - fields: The form data object + * - options: Form options provided by the client + */ +function handleFormErrors(errors, fields, options) { + + // Remove any existing error messages from the form + clearFormErrors(options); + + for (field_name in errors) { + if (field_name in fields) { + + // Add the 'has-error' class + $(options.modal).find(`#div_id_${field_name}`).addClass('has-error'); + + var field_dom = $(options.modal).find(`#id_${field_name}`); + + var field_errors = errors[field_name]; + + // Add an entry for each returned error message + for (var idx = field_errors.length-1; idx >= 0; idx--) { + + var error_text = field_errors[idx]; + + var html = ` + + ${error_text} + `; + + $(html).insertAfter(field_dom); + } + + } else { + console.log(`WARNING: handleFormErrors found no match for field '${field_name}'`); + } + } + +} + + +function initializeRelatedFields(fields, options) { var field_names = options.field_names; @@ -368,7 +458,7 @@ function initializeRelatedFields(modal, url, fields, options) { continue; } - initializeRelatedField(modal, name, field, options); + initializeRelatedField(name, field, options); } } @@ -385,7 +475,7 @@ function initializeRelatedFields(modal, url, fields, options) { function initializeRelatedField(modal, name, field, options) { // Find the select element and attach a select2 to it - var select = $(modal).find(`#id_${name}`); + var select = $(options.modal).find(`#id_${name}`); // TODO: Add 'placeholder' support for entry select2 fields @@ -397,7 +487,7 @@ function initializeRelatedField(modal, name, field, options) { url: field.api_url, dataType: 'json', allowClear: !field.required, // Allow non required fields to be cleared - dropdownParent: $(modal), + dropdownParent: $(options.modal), dropdownAutoWidth: false, delay: 250, cache: true, @@ -555,7 +645,7 @@ function renderModelData(name, model, data, parameters, options) { * - Field description (help text) * - Field errors */ -function constructField(name, parameters, options={}) { +function constructField(name, parameters, options) { var field_name = `id_${name}`; @@ -631,7 +721,7 @@ function constructLabel(name, parameters) { * - parameters: Field parameters returned by the OPTIONS method * */ -function constructInput(name, parameters, options={}) { +function constructInput(name, parameters, options) { var html = ''; @@ -741,7 +831,7 @@ function constructInputOptions(name, classes, type, parameters) { // Construct a "checkbox" input -function constructCheckboxInput(name, parameters, options={}) { +function constructCheckboxInput(name, parameters, options) { return constructInputOptions( name, @@ -754,7 +844,7 @@ function constructCheckboxInput(name, parameters, options={}) { // Construct a "text" input -function constructTextInput(name, parameters, options={}) { +function constructTextInput(name, parameters, options) { var classes = ''; var type = ''; @@ -784,7 +874,7 @@ function constructTextInput(name, parameters, options={}) { // Construct a "number" field -function constructNumberInput(name, parameters, options={}) { +function constructNumberInput(name, parameters, options) { return constructInputOptions( name, @@ -796,7 +886,7 @@ function constructNumberInput(name, parameters, options={}) { // Construct a "choice" input -function constructChoiceInput(name, parameters, options={}) { +function constructChoiceInput(name, parameters, options) { var html = ``; @@ -849,7 +939,7 @@ function constructRelatedFieldInput(name, parameters, options={}) { * - parameters: Field parameters returned by the OPTIONS method * */ -function constructHelpText(name, parameters, options={}) { +function constructHelpText(name, parameters, options) { var html = `
          ${parameters.help_text}
          `; @@ -864,7 +954,7 @@ function constructHelpText(name, parameters, options={}) { * - name: The name of the field * - parameters: Field parameters returned by the OPTIONS method */ -function constructErrorMessage(name, parameters, options={}) { +function constructErrorMessage(name, parameters, options) { var errors_html = ''; From 2eb756568376187943ec6ee98b528660f9621d0c Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 26 Jun 2021 19:30:57 +1000 Subject: [PATCH 105/445] Callback handler for form success --- InvenTree/templates/js/forms.js | 62 ++++++++++++++------------------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 8a302bc2b1..c6d515a620 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -365,7 +365,7 @@ function submitFormData(fields, options) { { method: options.method, success: function(response, status) { - console.log('success', '->', status); + handleFormSuccess(response, options); }, error: function(xhr, status, thrownError) { @@ -383,6 +383,31 @@ function submitFormData(fields, options) { } +/* + * Handle successful form posting + * + * arguments: + * - response: The JSON response object from the server + * - options: The original options object provided by the client + */ +function handleFormSuccess(response, options) { + + // Close the modal + if (!options.preventClose) { + // TODO: Actually just *delete* the modal, + // rather than hiding it!! + $(options.modal).modal('hide'); + } + + if (response.url) { + // GOTO + window.location.href = response.url; + } + +} + + + /* * Remove all error text items from the form */ @@ -664,10 +689,6 @@ function constructField(name, parameters, options) { html += constructInput(name, parameters, options); - if (parameters.errors) { - html += constructErrorMessage(name, parameters, options); - } - if (parameters.help_text) { html += constructHelpText(name, parameters, options); } @@ -941,36 +962,7 @@ function constructRelatedFieldInput(name, parameters, options) { */ function constructHelpText(name, parameters, options) { - var html = `
          ${parameters.help_text}
          `; + var html = `
          ${parameters.help_text}
          `; return html; -} - - -/* - * Construct an 'error message' div for the field - * - * arguments: - * - name: The name of the field - * - parameters: Field parameters returned by the OPTIONS method - */ -function constructErrorMessage(name, parameters, options) { - - var errors_html = ''; - - for (var idx = 0; idx < parameters.errors.length; idx++) { - - var err = parameters.errors[idx]; - - var html = ''; - - html += ``; - html += `${err}`; - html += ``; - - errors_html += html; - - } - - return errors_html; } \ No newline at end of file From f696bb2e2a53d8828060e511276ed1deaa89d719 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 26 Jun 2021 19:49:56 +1000 Subject: [PATCH 106/445] Correctly read out boolean fields --- InvenTree/templates/js/forms.js | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index c6d515a620..b33f5048b3 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -246,6 +246,11 @@ function constructFormBody(fields, options) { ignored_fields.push('id'); } + // Provide each field object with its own name + for(field in fields) { + fields[field].name = field; + } + // Construct an ordered list of field names var field_names = []; @@ -348,9 +353,8 @@ function submitFormData(fields, options) { var field = fields[name] || null; if (field) { - var value = getFieldValue(name); - // TODO - Custom parsing depending on type? + var value = getFormFieldValue(name, field, options); data[name] = value; } else { @@ -383,6 +387,29 @@ function submitFormData(fields, options) { } +/* + * Extract and field value before sending back to the server + * + * arguments: + * - name: The name of the field + * - field: The field specification provided from the OPTIONS request + * - options: The original options object provided by the client + */ +function getFormFieldValue(name, field, options) { + + // Find the HTML element + var el = $(options.modal).find(`#id_${name}`); + + switch (field.type) { + case 'boolean': + return el.is(":checked"); + default: + return el.val(); + } +} + + + /* * Handle successful form posting * From 3f1aca9e94e49764a7aec49ac2c940a3d576f0e7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 26 Jun 2021 20:18:25 +1000 Subject: [PATCH 107/445] Translation merge (#1724) * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * updated translation base * updated translation base * updated translation base * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * updated translation base * New Crowdin updates (#1670) * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * updated translation base * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * updated translation base * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * updated translation base * updated translation base * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * updated translation base * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin * Fix: New translations django.po from Crowdin Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- InvenTree/locale/de/LC_MESSAGES/django.po | 1624 ++++++------ InvenTree/locale/en/LC_MESSAGES/django.po | 1624 ++++++------ InvenTree/locale/es/LC_MESSAGES/django.po | 1678 +++++++------ InvenTree/locale/fr/LC_MESSAGES/django.po | 1626 ++++++------ InvenTree/locale/it/LC_MESSAGES/django.po | 1626 ++++++------ InvenTree/locale/ja/LC_MESSAGES/django.po | 1626 ++++++------ InvenTree/locale/pl/LC_MESSAGES/django.po | 1630 ++++++------ InvenTree/locale/ru/LC_MESSAGES/django.po | 1626 ++++++------ InvenTree/locale/tr/LC_MESSAGES/django.po | 2768 +++++++++++---------- InvenTree/locale/zh/LC_MESSAGES/django.po | 1626 ++++++------ 10 files changed, 9447 insertions(+), 8007 deletions(-) diff --git a/InvenTree/locale/de/LC_MESSAGES/django.po b/InvenTree/locale/de/LC_MESSAGES/django.po index 9eeedee291..3ce90dc928 100644 --- a/InvenTree/locale/de/LC_MESSAGES/django.po +++ b/InvenTree/locale/de/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:41\n" +"POT-Creation-Date: 2021-06-24 21:38+0000\n" +"PO-Revision-Date: 2021-06-24 21:40\n" "Last-Translator: \n" "Language-Team: German\n" "Language: de_DE\n" @@ -77,7 +77,7 @@ msgstr "Kategorie auswählen" msgid "Duplicate serial: {n}" msgstr "Doppelte Seriennummer: {n}" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 +#: InvenTree/helpers.py:384 order/models.py:248 order/models.py:358 #: stock/views.py:1795 msgid "Invalid quantity provided" msgstr "Keine gültige Menge" @@ -122,9 +122,9 @@ msgstr "Kommentar" msgid "File comment" msgstr "Datei-Kommentar" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:2022 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1179 msgid "User" msgstr "Benutzer" @@ -132,34 +132,35 @@ msgstr "Benutzer" msgid "upload date" msgstr "Hochladedatum" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:107 InvenTree/models.py:108 company/models.py:396 +#: label/models.py:102 part/models.py:671 part/models.py:2163 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:235 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:972 msgid "Name" msgstr "Name" #: InvenTree/models.py:114 build/models.py:135 #: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: company/models.py:532 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 #: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: order/models.py:104 order/templates/order/purchase_order_detail.html:147 +#: part/models.py:695 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 +#: templates/js/build.js:833 templates/js/build.js:1101 #: templates/js/company.js:56 templates/js/order.js:183 #: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:984 +#: templates/js/stock.js:1029 msgid "Description" msgstr "Beschreibung" @@ -191,15 +192,15 @@ msgstr "Polnisch" msgid "Turkish" msgstr "Türkisch" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "Hintergrund-Prozess-Kontrolle fehlgeschlagen" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "E-Mail-Backend nicht konfiguriert" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "InvenTree Status-Überprüfung fehlgeschlagen" @@ -372,27 +373,27 @@ msgstr "Überschuss darf 100% nicht überschreiten" msgid "Overage must be an integer value or a percentage" msgstr "Überschuss muss eine Ganzzahl oder ein Prozentwert sein" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "Element löschen" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "Häkchen setzen um Löschung von Objekt zu bestätigen" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "Benutzerinformationen bearbeiten" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "Passwort eingeben" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "Passwörter stimmen nicht überein" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "Systeminformationen" @@ -445,11 +446,11 @@ msgid "Order target date" msgstr "geplantes Bestelldatum" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 order/forms.py:114 order/forms.py:149 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 +#: templates/js/build.js:880 templates/js/order.js:200 #: templates/js/order.js:298 msgid "Target Date" msgstr "Zieldatum" @@ -462,22 +463,21 @@ msgstr "Zieldatum für Bauauftrag-Fertigstellung." #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 +#: build/templates/build/detail.html:31 common/models.py:720 +#: company/forms.py:191 company/templates/company/supplier_part_pricing.html:77 +#: order/forms.py:193 order/forms.py:211 order/forms.py:246 order/forms.py:268 +#: order/forms.py:285 order/models.py:617 order/models.py:841 #: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/order_wizard/select_parts.html:34 #: order/templates/order/purchase_order_detail.html:179 #: order/templates/order/sales_order_detail.html:70 #: order/templates/order/sales_order_detail.html:77 #: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 +#: order/templates/order/sales_order_detail.html:234 part/forms.py:342 +#: part/forms.py:372 part/forms.py:388 part/forms.py:404 part/models.py:2293 +#: part/templates/part/internal_prices.html:98 +#: part/templates/part/order_prices.html:202 +#: part/templates/part/part_pricing.html:16 #: part/templates/part/sale_prices.html:85 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 @@ -486,9 +486,10 @@ msgstr "Zieldatum für Bauauftrag-Fertigstellung." #: stock/forms.py:175 stock/forms.py:308 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:571 +#: templates/js/build.js:1111 templates/js/order.js:393 +#: templates/js/part.js:796 templates/js/stock.js:1164 +#: templates/js/stock.js:1383 msgid "Quantity" msgstr "Anzahl" @@ -500,7 +501,7 @@ msgstr "Anzahl der zu bauenden Teile" msgid "Enter quantity for build output" msgstr "Menge der Endprodukte angeben" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:240 stock/forms.py:118 msgid "Serial Numbers" msgstr "Seriennummer" @@ -529,12 +530,12 @@ msgid "Mark build as complete" msgstr "Bauauftrag als vollständig markieren" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:347 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:585 templates/js/order.js:378 +#: templates/js/stock.js:643 templates/js/stock.js:1056 msgid "Location" msgstr "Lagerort" @@ -543,13 +544,13 @@ msgid "Location of completed parts" msgstr "Lagerort der Endprodukte" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:469 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:867 #: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: templates/js/stock.js:630 templates/js/stock.js:1133 +#: templates/js/stock.js:1399 msgid "Status" msgstr "Status" @@ -583,16 +584,16 @@ msgstr "Menge der BestandsObjekte für Zuordnung auswählen" #: build/models.py:66 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "Bauauftrag" #: build/models.py:67 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:57 +#: part/templates/part/navbar.html:60 templates/InvenTree/index.html:183 #: templates/InvenTree/search.html:185 #: templates/InvenTree/settings/tabs.html:34 users/models.py:43 msgid "Build Orders" @@ -602,12 +603,12 @@ msgstr "Bauaufträge" msgid "Build Order Reference" msgstr "Bauauftragsreferenz" -#: build/models.py:128 order/models.py:101 order/models.py:618 +#: build/models.py:128 order/models.py:102 order/models.py:619 #: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: order/templates/order/sales_order_detail.html:229 part/models.py:2302 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:660 templates/js/build.js:1105 msgid "Reference" msgstr "Referenz" @@ -626,27 +627,27 @@ msgstr "Bauauftrag, zu dem dieser Bauauftrag zugwiesen ist" #: build/models.py:153 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 +#: build/templates/build/detail.html:26 company/models.py:663 +#: order/models.py:661 order/models.py:717 +#: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:132 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:214 part/models.py:321 +#: part/models.py:1975 part/models.py:1987 part/models.py:2002 +#: part/models.py:2020 part/models.py:2095 part/models.py:2191 +#: part/models.py:2277 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:551 templates/js/build.js:838 +#: templates/js/build.js:1078 templates/js/company.js:140 +#: templates/js/company.js:339 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1371 msgid "Part" msgstr "Teil" @@ -710,16 +711,16 @@ msgstr "Losnummer" msgid "Batch code for this build output" msgstr "Losnummer für dieses Endprodukt" -#: build/models.py:220 order/models.py:107 part/models.py:882 +#: build/models.py:220 order/models.py:108 part/models.py:867 #: part/templates/part/detail.html:126 templates/js/order.js:293 msgid "Creation Date" msgstr "Erstelldatum" -#: build/models.py:224 order/models.py:474 +#: build/models.py:224 order/models.py:475 msgid "Target completion date" msgstr "geplantes Fertigstellungsdatum" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:228 order/models.py:221 templates/js/build.js:885 msgid "Completion Date" msgstr "Fertigstellungsdatum" @@ -736,9 +737,9 @@ msgid "User who issued this build order" msgstr "Nutzer der diesen Bauauftrag erstellt hat" #: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/templates/build/detail.html:105 order/models.py:122 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:871 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "Verantwortlicher Benutzer" @@ -757,26 +758,26 @@ msgstr "Nutzer der für diesen Bauauftrag zuständig ist" msgid "External Link" msgstr "Externer Link" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:258 part/models.py:729 stock/models.py:462 msgid "Link to external URL" msgstr "Link zu einer externen URL" #: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: company/models.py:132 company/models.py:539 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:126 +#: order/models.py:621 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:243 +#: order/templates/order/sales_order_detail.html:309 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:856 +#: part/templates/part/navbar.html:142 #: report/templates/report/inventree_build_order_base.html:173 #: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 #: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:699 msgid "Notes" msgstr "Notizen" @@ -809,11 +810,11 @@ msgstr "Bauauftragsposition muss ein Endprodukt festlegen, da der übergeordnete msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "Reserviermenge ({n}) muss kleiner Bestandsmenge ({q}) sein. Zugewiesene Anzahl ({n}) darf nicht die verfügbare ({q}) Anzahl überschreiten" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1188 order/models.py:815 msgid "StockItem is over-allocated" msgstr "Zu viele BestandsObjekt zugewiesen" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1192 order/models.py:818 msgid "Allocation quantity must be greater than zero" msgstr "Reserviermenge muss größer null sein" @@ -827,7 +828,7 @@ msgid "Selected stock item not found in BOM for part '{p}'" msgstr "Ausgewähltes BestandsObjekt nicht Stückliste für Teil '{p}' gefunden" #: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: templates/InvenTree/search.html:183 templates/js/build.js:811 #: templates/navbar.html:29 msgid "Build" msgstr "Bauauftrag" @@ -836,15 +837,13 @@ msgstr "Bauauftrag" msgid "Build to allocate parts" msgstr "Bauauftrag starten um Teile zuzuweisen" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1333 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:928 +#: templates/js/order.js:366 templates/js/order.js:371 +#: templates/js/stock.js:1115 msgid "Stock Item" msgstr "BestandsObjekt" @@ -880,7 +879,7 @@ msgstr "Lagerbestand Bauauftrag zuweisen" msgid "Auto Allocate" msgstr "Automatisch zuweisen" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:743 msgid "Unallocate stock" msgstr "Bestandszuordnung aufheben" @@ -917,15 +916,15 @@ msgstr "Dieser Bauauftrag hat keine zugeordneten Stücklisten-Einträge" #: order/templates/order/sales_order_detail.html:160 #: report/templates/report/inventree_test_report_base.html:75 #: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: templates/js/build.js:569 msgid "Serial Number" msgstr "Seriennummer" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:133 +#: part/templates/part/navbar.html:136 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "Anhänge" @@ -1037,11 +1036,10 @@ msgid "Progress" msgstr "Fortschritt" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:715 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 #: stock/templates/stock/item_base.html:279 templates/js/order.js:245 @@ -1185,7 +1183,10 @@ msgstr "Ausgangs-Lager" msgid "Stock can be taken from any available location." msgstr "Bestand kann jedem verfügbaren Lagerort entnommen werden." -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:85 order/models.py:678 +#: order/templates/order/purchase_order_detail.html:239 +#: order/templates/order/receive_parts.html:25 stock/forms.py:169 +#: stock/forms.py:375 msgid "Destination" msgstr "Ziel-Lager" @@ -1194,15 +1195,15 @@ msgid "Destination location not specified" msgstr "Ziel-Lagerort nicht angegeben" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1406 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "Losnummer" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:875 msgid "Created" msgstr "Erstellt" @@ -1210,7 +1211,7 @@ msgstr "Erstellt" msgid "No target date set" msgstr "Kein Ziel-Datum gesetzt" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:853 msgid "Completed" msgstr "Fertig" @@ -1248,9 +1249,9 @@ msgstr "Bauauftrag-details" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:17 +#: templates/js/stock.js:1044 msgid "Details" msgstr "Details" @@ -1285,8 +1286,8 @@ msgstr "Bermerkungen bearbeiten" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 +#: stock/templates/stock/item_base.html:497 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "Speichern" @@ -1411,8 +1412,8 @@ msgstr "Teil muss aktuell im Bestand sein" msgid "Stock item is over-allocated" msgstr "BestandObjekt ist zu oft zugewiesen" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:670 +#: templates/js/build.js:935 templates/js/build.js:1118 msgid "Available" msgstr "Verfügbar" @@ -1598,8 +1599,8 @@ msgstr "Aktuelle Teile-Stände" msgid "Number of recent parts to display on index page" msgstr "Anzahl der neusten Teile auf der Startseite" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 +#: common/models.py:153 part/models.py:2193 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:259 templates/js/table_filters.js:25 #: templates/js/table_filters.js:315 msgid "Template" msgstr "Vorlage" @@ -1608,7 +1609,7 @@ msgstr "Vorlage" msgid "Parts are templates by default" msgstr "Teile sind standardmäßig Vorlagen" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 +#: common/models.py:160 part/models.py:819 part/templates/part/detail.html:170 #: templates/js/table_filters.js:128 templates/js/table_filters.js:327 msgid "Assembly" msgstr "Baugruppe" @@ -1617,7 +1618,7 @@ msgstr "Baugruppe" msgid "Parts can be assembled from other components by default" msgstr "Teile können standardmäßig aus anderen Teilen angefertigt werden" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 +#: common/models.py:167 part/models.py:825 part/templates/part/detail.html:180 #: templates/js/table_filters.js:331 msgid "Component" msgstr "Komponente" @@ -1626,7 +1627,7 @@ msgstr "Komponente" msgid "Parts can be used as sub-components by default" msgstr "Teile können standardmäßig in Baugruppen benutzt werden" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:174 part/models.py:836 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "Kaufbar" @@ -1634,7 +1635,7 @@ msgstr "Kaufbar" msgid "Parts are purchaseable by default" msgstr "Artikel sind grundsätzlich kaufbar" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 +#: common/models.py:181 part/models.py:841 part/templates/part/detail.html:210 #: templates/js/table_filters.js:339 msgid "Salable" msgstr "Verkäuflich" @@ -1643,7 +1644,7 @@ msgstr "Verkäuflich" msgid "Parts are salable by default" msgstr "Artikel sind grundsätzlich verkaufbar" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 +#: common/models.py:188 part/models.py:831 part/templates/part/detail.html:190 #: templates/js/table_filters.js:33 templates/js/table_filters.js:343 msgid "Trackable" msgstr "Nachverfolgbar" @@ -1652,7 +1653,7 @@ msgstr "Nachverfolgbar" msgid "Parts are trackable by default" msgstr "Artikel sind grundsätzlich verfolgbar" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:195 part/models.py:851 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "Virtuell" @@ -1669,160 +1670,185 @@ msgstr "zeige Bestand in Eingabemasken" msgid "Display available part quantity in some forms" msgstr "Zeige den verfügbaren Bestand in einigen Eingabemasken" -#: common/models.py:209 templates/stats.html:25 +#: common/models.py:209 +msgid "Show Price in Forms" +msgstr "" + +#: common/models.py:210 +msgid "Display part price in some forms" +msgstr "" + +#: common/models.py:216 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:217 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:223 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:224 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:230 templates/stats.html:25 msgid "Debug Mode" msgstr "Entwickler-Modus" -#: common/models.py:210 +#: common/models.py:231 msgid "Generate reports in debug mode (HTML output)" msgstr "Berichte im Entwickler-Modus generieren (als HTML)" -#: common/models.py:216 +#: common/models.py:237 msgid "Page Size" msgstr "Seitengröße" -#: common/models.py:217 +#: common/models.py:238 msgid "Default page size for PDF reports" msgstr "Standardseitenformat für PDF-Bericht" -#: common/models.py:227 +#: common/models.py:248 msgid "Test Reports" msgstr "Test-Berichte" -#: common/models.py:228 +#: common/models.py:249 msgid "Enable generation of test reports" msgstr "Erstellung von Test-Berichten aktivieren" -#: common/models.py:234 +#: common/models.py:255 msgid "Stock Expiry" msgstr "Bestands-Ablauf" -#: common/models.py:235 +#: common/models.py:256 msgid "Enable stock expiry functionality" msgstr "Ablaufen von Bestand ermöglichen" -#: common/models.py:241 +#: common/models.py:262 msgid "Sell Expired Stock" msgstr "Abgelaufenen Bestand verkaufen" -#: common/models.py:242 +#: common/models.py:263 msgid "Allow sale of expired stock" msgstr "Verkauf von abgelaufenem Bestand erlaubt" -#: common/models.py:248 +#: common/models.py:269 msgid "Stock Stale Time" msgstr "Bestands-Stehzeit" -#: common/models.py:249 +#: common/models.py:270 msgid "Number of days stock items are considered stale before expiring" msgstr "Anzahl an Tagen, an denen Bestand als abgestanden markiert wird, bevor sie ablaufen" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:272 part/templates/part/detail.html:121 msgid "days" msgstr "Tage" -#: common/models.py:256 +#: common/models.py:277 msgid "Build Expired Stock" msgstr "Abgelaufenen Bestand verbauen" -#: common/models.py:257 +#: common/models.py:278 msgid "Allow building with expired stock" msgstr "Verbauen von abgelaufenen Bestand erlaubt" -#: common/models.py:263 +#: common/models.py:284 msgid "Stock Ownership Control" msgstr "Bestands-Eigentümerkontrolle" -#: common/models.py:264 +#: common/models.py:285 msgid "Enable ownership control over stock locations and items" msgstr "Eigentümerkontrolle für Lagerorte und Teile aktivieren" -#: common/models.py:270 +#: common/models.py:291 msgid "Group by Part" msgstr "Gruppieren nach Teil" -#: common/models.py:271 +#: common/models.py:292 msgid "Group stock items by part reference in table views" msgstr "Bestand in Tabellen anhand von Teil-Referenz gruppieren" -#: common/models.py:277 +#: common/models.py:298 msgid "Recent Stock Count" msgstr "aktueller Bestand" -#: common/models.py:278 +#: common/models.py:299 msgid "Number of recent stock items to display on index page" msgstr "Anzahl des geänderten Bestands auf der Startseite" -#: common/models.py:284 +#: common/models.py:305 msgid "Build Order Reference Prefix" msgstr "Bauauftrag-Referenz Präfix" -#: common/models.py:285 +#: common/models.py:306 msgid "Prefix value for build order reference" msgstr "Präfix für Bauauftrag-Referenz" -#: common/models.py:290 +#: common/models.py:311 msgid "Build Order Reference Regex" msgstr "Bauauftrag-Referenz RegEx" -#: common/models.py:291 +#: common/models.py:312 msgid "Regular expression pattern for matching build order reference" msgstr "RegEx Muster für die Zuordnung von Bauauftrag-Referenzen" -#: common/models.py:295 +#: common/models.py:316 msgid "Sales Order Reference Prefix" msgstr "Auftrags-Referenz Präfix" -#: common/models.py:296 +#: common/models.py:317 msgid "Prefix value for sales order reference" msgstr "Präfix für Auftrags-Referenz" -#: common/models.py:301 +#: common/models.py:322 msgid "Purchase Order Reference Prefix" msgstr "Bestellungs-Referenz Präfix" -#: common/models.py:302 +#: common/models.py:323 msgid "Prefix value for purchase order reference" msgstr "Präfix für Bestellungs-Referenz" -#: common/models.py:525 +#: common/models.py:546 msgid "Settings key (must be unique - case insensitive" msgstr "Einstellungs-Schlüssel (muss einzigartig sein, Groß-/ Kleinschreibung wird nicht beachtet)" -#: common/models.py:527 +#: common/models.py:548 msgid "Settings value" msgstr "Einstellungs-Wert" -#: common/models.py:562 +#: common/models.py:583 msgid "Must be an integer value" msgstr "Nur Ganzzahl eingeben" -#: common/models.py:585 +#: common/models.py:606 msgid "Value must be a boolean value" msgstr "Wahrheitswert erforderlich" -#: common/models.py:596 +#: common/models.py:617 msgid "Value must be an integer value" msgstr "Nur Ganzzahl eingeben" -#: common/models.py:619 +#: common/models.py:640 msgid "Key string must be unique" msgstr "Schlüsseltext muss eindeutig sein" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:721 company/forms.py:192 msgid "Price break quantity" msgstr "Preisstaffelungs Anzahl" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 +#: common/models.py:729 company/templates/company/supplier_part_pricing.html:82 +#: part/templates/part/internal_prices.html:103 #: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 msgid "Price" msgstr "Preis" -#: common/models.py:709 +#: common/models.py:730 msgid "Unit price at specified quantity" msgstr "Stückpreis für die angegebene Anzahl" -#: common/models.py:798 +#: common/models.py:822 msgid "Default" msgstr "Standard" @@ -1843,7 +1869,9 @@ msgid "Supplied value must be a boolean" msgstr "Angegebener Wert muss ein Wahrheitswert sein" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:582 +#: part/templates/part/bom_upload/upload_file.html:27 msgid "Upload File" msgstr "Datei hochgeladen" @@ -1877,29 +1905,29 @@ msgstr "URL" msgid "Image URL" msgstr "Bild-URL" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:133 templates/js/part.js:787 msgid "Single Price" msgstr "Einzelpreis" -#: company/forms.py:120 +#: company/forms.py:135 msgid "Single quantity price" msgstr "Preis für eine Einheit" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:143 company/models.py:321 msgid "Select manufacturer" msgstr "Hersteller auswählen" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:149 company/models.py:328 msgid "Manufacturer Part Number" msgstr "Hersteller-Teilenummer" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:151 company/models.py:327 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 #: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:408 msgid "MPN" msgstr "MPN" @@ -1952,11 +1980,11 @@ msgstr "Kontakt" msgid "Point of contact" msgstr "Anlaufstelle" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:121 company/models.py:333 company/models.py:526 +#: order/models.py:106 part/models.py:728 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:188 templates/js/company.js:419 +#: templates/js/part.js:498 msgid "Link" msgstr "Link" @@ -1964,7 +1992,7 @@ msgstr "Link" msgid "Link to external company information" msgstr "Link auf externe Firmeninformation" -#: company/models.py:129 part/models.py:753 +#: company/models.py:129 part/models.py:738 msgid "Image" msgstr "Bild" @@ -1992,12 +2020,12 @@ msgstr "ist Hersteller" msgid "Does this company manufacture parts?" msgstr "Produziert diese Firma Teile?" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:305 company/models.py:497 stock/models.py:407 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "Basisteil" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:309 company/models.py:501 order/views.py:1597 msgid "Select part" msgstr "Teil auswählen" @@ -2008,7 +2036,7 @@ msgstr "Teil auswählen" #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 #: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:390 msgid "Manufacturer" msgstr "Hersteller" @@ -2020,87 +2048,112 @@ msgstr "Externe URL für das Herstellerteil" msgid "Manufacturer part description" msgstr "Teilbeschreibung des Herstellers" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:390 company/models.py:520 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "Herstellerteil" + +#: company/models.py:397 +msgid "Parameter name" +msgstr "" + +#: company/models.py:403 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:241 templates/js/stock.js:137 +msgid "Value" +msgstr "Wert" + +#: company/models.py:404 +msgid "Parameter value" +msgstr "" + +#: company/models.py:410 part/models.py:813 part/models.py:2165 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:247 +msgid "Units" +msgstr "Einheiten" + +#: company/models.py:411 +msgid "Parameter units" +msgstr "" + +#: company/models.py:507 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:193 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:48 templates/js/company.js:364 #: templates/js/order.js:170 msgid "Supplier" msgstr "Zulieferer" -#: company/models.py:467 +#: company/models.py:508 msgid "Select supplier" msgstr "Zulieferer auswählen" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:513 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 #: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "SKU (Lagerbestandseinheit)" -#: company/models.py:473 +#: company/models.py:514 msgid "Supplier stock keeping unit" msgstr "Lagerbestandseinheit (SKU) des Zulieferers" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "Herstellerteil" - -#: company/models.py:480 +#: company/models.py:521 msgid "Select manufacturer part" msgstr "Herstellerteil auswählen" -#: company/models.py:486 +#: company/models.py:527 msgid "URL for external supplier part link" msgstr "Teil-URL des Zulieferers" -#: company/models.py:492 +#: company/models.py:533 msgid "Supplier part description" msgstr "Zuliefererbeschreibung des Teils" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:538 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2305 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "Notiz" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "base cost" msgstr "Basiskosten" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "Minimum charge (e.g. stocking fee)" msgstr "Mindestpreis" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 +#: company/models.py:544 company/templates/company/supplier_part_base.html:109 #: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: templates/js/stock.js:695 msgid "Packaging" msgstr "Verpackungen" -#: company/models.py:503 +#: company/models.py:544 msgid "Part packaging" msgstr "Teile-Verpackungen" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:546 part/models.py:1608 msgid "multiple" msgstr "Vielfache" -#: company/models.py:505 +#: company/models.py:546 msgid "Order multiple" msgstr "Mehrere bestellen" #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:562 msgid "Assigned Stock" msgstr "Zugeordneter Bestand" @@ -2166,11 +2219,11 @@ msgstr "Keine Website angegeben" msgid "Uses default currency" msgstr "verwendet Standard-Währung" -#: company/templates/company/detail.html:67 order/models.py:463 +#: company/templates/company/detail.html:67 order/models.py:464 #: order/templates/order/sales_order_base.html:94 stock/models.py:449 #: stock/models.py:450 stock/templates/stock/item_base.html:262 #: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: templates/js/stock.js:1097 msgid "Customer" msgstr "Kunde" @@ -2216,7 +2269,7 @@ msgstr "Teile löschen" #: company/templates/company/detail_manufacturer_part.html:66 #: company/templates/company/detail_supplier_part.html:66 #: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: templates/js/stock.js:1312 msgid "New Part" msgstr "Neues Teil" @@ -2249,13 +2302,12 @@ msgstr "Exportieren" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "Zuliefererteile" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 +#: order/templates/order/order_wizard/select_parts.html:44 #: order/templates/order/purchase_order_detail.html:50 msgid "Create new supplier part" msgstr "Neues Zuliefererteil anlegen" @@ -2263,12 +2315,12 @@ msgstr "Neues Zuliefererteil anlegen" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 #: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/supplier.html:17 templates/js/stock.js:1318 msgid "New Supplier Part" msgstr "Neues Zuliefererteil" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 +#: company/templates/company/manufacturer_part_suppliers.html:82 #: company/views.py:64 order/templates/order/purchase_orders.html:185 #: part/templates/part/supplier.html:50 msgid "New Supplier" @@ -2320,8 +2372,9 @@ msgid "There are %(count)s suppliers defined for this manufacturer part. If you msgstr "Für dieses Herstellerteil sind %(count)s Lieferanten definiert. Wenn Sie es löschen, werden die folgenden Lieferantenteile ebenfalls gelöscht:" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:63 part/templates/part/navbar.html:86 +#: part/templates/part/navbar.html:89 templates/InvenTree/search.html:316 #: templates/navbar.html:35 msgid "Suppliers" msgstr "Zulieferer" @@ -2333,13 +2386,13 @@ msgstr "Herstellerteil-Bestand" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:38 stock/api.py:54 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "Lagerbestand" @@ -2361,11 +2414,25 @@ msgstr "Zuliefererteil entfernen" #: company/templates/company/manufacturer_part_suppliers.html:22 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:1002 users/models.py:191 msgid "Delete" msgstr "Löschen" -#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:34 +#: part/templates/part/category_navbar.html:37 +#: part/templates/part/navbar.html:24 +msgid "Parameters" +msgstr "Parameter" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:48 +msgid "New Parameter" +msgstr "Neuer Parameter" + +#: company/templates/company/manufacturer_part_suppliers.html:83 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "Neuen Zulieferer anlegen" @@ -2380,13 +2447,13 @@ msgstr "Hergestellte Teile" msgid "Supplied Parts" msgstr "Zuliefererteile" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:35 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 +#: templates/InvenTree/search.html:198 templates/js/stock.js:996 #: templates/stats.html:93 templates/stats.html:102 users/models.py:42 msgid "Stock Items" msgstr "Teilbestand" @@ -2397,7 +2464,7 @@ msgstr "Teilbestand" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 +#: part/templates/part/navbar.html:112 part/templates/part/navbar.html:115 #: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 @@ -2409,7 +2476,7 @@ msgstr "Aufträge" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 +#: part/templates/part/navbar.html:92 part/templates/part/navbar.html:95 #: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 @@ -2443,7 +2510,7 @@ msgstr "Neuer Auftrag" #: company/templates/company/supplier_part_base.html:7 #: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:380 msgid "Supplier Part" msgstr "Zuliefererteil" @@ -2491,8 +2558,8 @@ msgstr "Teil bestellen" msgid "Pricing Information" msgstr "Preisinformationen ansehen" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 company/views.py:855 +#: part/templates/part/sale_prices.html:17 part/views.py:2751 msgid "Add Price Break" msgstr "Preisstaffel hinzufügen" @@ -2511,8 +2578,8 @@ msgstr "Preisstaffel bearbeiten" msgid "Delete price break" msgstr "Preisstaffel löschen" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 +#: company/views.py:70 part/templates/part/navbar.html:80 +#: part/templates/part/navbar.html:83 templates/InvenTree/search.html:306 #: templates/navbar.html:36 msgid "Manufacturers" msgstr "Hersteller" @@ -2534,20 +2601,20 @@ msgstr "Firmen" msgid "New Company" msgstr "Neue Firma" -#: company/views.py:169 part/views.py:937 +#: company/views.py:169 part/views.py:948 msgid "Download Image" msgstr "Bild herunterladen" -#: company/views.py:198 part/views.py:969 +#: company/views.py:198 part/views.py:980 msgid "Image size exceeds maximum allowable size for download" msgstr "Bildgröße überschreitet maximal-erlaubte Größe für Downloads" -#: company/views.py:205 part/views.py:976 +#: company/views.py:205 part/views.py:987 #, python-brace-format msgid "Invalid response: {code}" msgstr "Ungültige Antwort {code}" -#: company/views.py:214 part/views.py:985 +#: company/views.py:214 part/views.py:996 msgid "Supplied URL is not a valid image file" msgstr "Angegebene URL ist kein gültiges Bild" @@ -2595,27 +2662,35 @@ msgstr "Neues Herstellerteil anlegen" msgid "Delete Manufacturer Part" msgstr "Herstellerteil löschen" -#: company/views.py:528 +#: company/views.py:514 +msgid "Add Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:548 +msgid "Edit Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:588 msgid "Edit Supplier Part" msgstr "Zuliefererteil bearbeiten" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:639 templates/js/stock.js:1319 msgid "Create new Supplier Part" msgstr "Neues Zuliefererteil anlegen" -#: company/views.py:722 +#: company/views.py:783 msgid "Delete Supplier Part" msgstr "Zuliefererteil entfernen" -#: company/views.py:799 part/views.py:2737 +#: company/views.py:860 part/views.py:2755 msgid "Added new price break" msgstr "neue Preisstaffel hinzufügt" -#: company/views.py:855 part/views.py:2781 +#: company/views.py:916 part/views.py:2799 msgid "Edit Price Break" msgstr "Preisstaffel bearbeiten" -#: company/views.py:870 part/views.py:2795 +#: company/views.py:931 part/views.py:2813 msgid "Delete Price Break" msgstr "Preisstaffel löschen" @@ -2639,7 +2714,7 @@ msgstr "Label" msgid "Label template file" msgstr "Label-Vorlage-Datei" -#: label/models.py:124 report/models.py:274 +#: label/models.py:124 report/models.py:297 msgid "Enabled" msgstr "Aktiviert" @@ -2663,7 +2738,7 @@ msgstr "Höhe [mm]" msgid "Label height, specified in mm" msgstr "Label-Höhe in mm" -#: label/models.py:144 +#: label/models.py:144 report/models.py:290 msgid "Filename Pattern" msgstr "Dateinamen-Muster" @@ -2675,8 +2750,8 @@ msgstr "Muster für die Erstellung von Label-Dateinamen" msgid "Query filters (comma-separated list of key=value pairs" msgstr "Abfragefilter (kommagetrennte Liste mit Schlüssel=Wert-Paaren)" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:245 label/models.py:298 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "Filter" @@ -2697,237 +2772,239 @@ msgstr "Bestellung stornieren" msgid "Ship order" msgstr "Bestellung versenden" -#: order/forms.py:82 +#: order/forms.py:86 msgid "Receive parts to this location" msgstr "Teile in diesen Lagerort empfangen" -#: order/forms.py:103 +#: order/forms.py:108 msgid "Purchase Order reference" msgstr "Bestellungs-Referenz" -#: order/forms.py:110 +#: order/forms.py:115 msgid "Target date for order delivery. Order will be overdue after this date." msgstr "Zieldatum für Auftrags-Lieferung." -#: order/forms.py:138 +#: order/forms.py:143 msgid "Enter sales order number" msgstr "Auftrag-Nummer eingeben" -#: order/forms.py:145 order/models.py:475 +#: order/forms.py:150 order/models.py:476 msgid "Target date for order completion. Order will be overdue after this date." msgstr "Zieldatum für Auftrags-Fertigstellung." -#: order/forms.py:236 +#: order/forms.py:242 msgid "Enter stock item serial numbers" msgstr "Seriennummern für BestandsObjekt eingeben" -#: order/forms.py:242 +#: order/forms.py:248 msgid "Enter quantity of stock items" msgstr "Menge der BestandsObjekt eingeben" -#: order/models.py:101 +#: order/models.py:102 msgid "Order reference" msgstr "Bestell-Referenz" -#: order/models.py:103 +#: order/models.py:104 msgid "Order description" msgstr "Bestellungs-Beschreibung" -#: order/models.py:105 +#: order/models.py:106 msgid "Link to external page" msgstr "Link auf externe Seite" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:114 part/templates/part/detail.html:132 msgid "Created By" msgstr "Erstellt von" -#: order/models.py:120 +#: order/models.py:121 msgid "User or group responsible for this order" msgstr "Nutzer oder Gruppe der/die für diesen Auftrag zuständig ist/sind" -#: order/models.py:125 +#: order/models.py:126 msgid "Order notes" msgstr "Bestell-Notizen" -#: order/models.py:184 order/models.py:468 +#: order/models.py:185 order/models.py:469 msgid "Purchase order status" msgstr "Bestellungs-Status" -#: order/models.py:193 +#: order/models.py:194 msgid "Company from which the items are being ordered" msgstr "Firma bei der die Teile bestellt werden" -#: order/models.py:196 order/templates/order/order_base.html:98 +#: order/models.py:197 order/templates/order/order_base.html:98 #: templates/js/order.js:179 msgid "Supplier Reference" msgstr "Zulieferer-Referenz" -#: order/models.py:196 +#: order/models.py:197 msgid "Supplier order reference code" msgstr "Zulieferer Bestellreferenz" -#: order/models.py:203 +#: order/models.py:204 msgid "received by" msgstr "Empfangen von" -#: order/models.py:208 +#: order/models.py:209 msgid "Issue Date" msgstr "Aufgabedatum" -#: order/models.py:209 +#: order/models.py:210 msgid "Date order was issued" msgstr "Datum an dem die Bestellung aufgegeben wurde" -#: order/models.py:214 +#: order/models.py:215 msgid "Target Delivery Date" msgstr "Ziel-Versanddatum" -#: order/models.py:215 +#: order/models.py:216 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "Geplantes Lieferdatum für Auftrag." -#: order/models.py:221 +#: order/models.py:222 msgid "Date order was completed" msgstr "Datum an dem der Auftrag fertigstellt wurde" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 +#: order/models.py:246 part/views.py:1686 stock/models.py:304 #: stock/models.py:1020 msgid "Quantity must be greater than zero" msgstr "Anzahl muss größer Null sein" -#: order/models.py:250 +#: order/models.py:251 msgid "Part supplier must match PO supplier" msgstr "Teile-Zulieferer muss dem Zulieferer der Bestellung entsprechen" -#: order/models.py:348 +#: order/models.py:349 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "Nur Teile aufgegebener Bestllungen können empfangen werden" -#: order/models.py:352 +#: order/models.py:353 msgid "Quantity must be an integer" msgstr "Anzahl muss eine Ganzzahl sein" -#: order/models.py:354 +#: order/models.py:355 msgid "Quantity must be a positive number" msgstr "Anzahl muss eine positive Zahl sein" -#: order/models.py:464 +#: order/models.py:465 msgid "Company to which the items are being sold" msgstr "Firma an die die Teile verkauft werden" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer Reference " msgstr "Kundenreferenz" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer order reference code" msgstr "Bestellreferenz" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:479 templates/js/order.js:303 msgid "Shipment Date" msgstr "Versanddatum" -#: order/models.py:485 +#: order/models.py:486 msgid "shipped by" msgstr "Versand von" -#: order/models.py:529 +#: order/models.py:530 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "Bestellung kann nicht versendet werden weil er nicht anhängig ist" -#: order/models.py:616 +#: order/models.py:617 msgid "Item quantity" msgstr "Anzahl" -#: order/models.py:618 +#: order/models.py:619 msgid "Line item reference" msgstr "Position - Referenz" -#: order/models.py:620 +#: order/models.py:621 msgid "Line item notes" msgstr "Position - Notizen" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:647 order/models.py:715 templates/js/order.js:353 msgid "Order" msgstr "Bestellung" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:648 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 #: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: templates/js/stock.js:669 templates/js/stock.js:1078 msgid "Purchase Order" msgstr "Bestellung" -#: order/models.py:661 +#: order/models.py:662 msgid "Supplier part" msgstr "Zuliefererteil" -#: order/models.py:664 order/templates/order/order_base.html:131 +#: order/models.py:665 order/templates/order/order_base.html:131 #: order/templates/order/purchase_order_detail.html:219 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "Empfangen" -#: order/models.py:664 +#: order/models.py:665 msgid "Number of items received" msgstr "Empfangene Objekt-Anzahl" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:672 stock/models.py:542 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:690 msgid "Purchase Price" msgstr "Preis" -#: order/models.py:672 +#: order/models.py:673 msgid "Unit purchase price" msgstr "Preis pro Einheit" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:681 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "Wo möchte der Käufer diesen Artikel gelagert haben?" + +#: order/models.py:724 part/templates/part/navbar.html:109 +#: part/templates/part/order_prices.html:107 +#: part/templates/part/part_pricing.html:97 msgid "Sale Price" msgstr "Verkaufspreis" -#: order/models.py:701 +#: order/models.py:725 msgid "Unit sale price" msgstr "Stückverkaufspreis" -#: order/models.py:776 order/models.py:778 +#: order/models.py:800 order/models.py:802 msgid "Stock item has not been assigned" msgstr "BestandsObjekt wurde nicht zugewiesen" -#: order/models.py:782 +#: order/models.py:806 msgid "Cannot allocate stock item to a line with a different part" msgstr "Kann BestandsObjekt keiner Zeile mit einem anderen Teil hinzufügen" -#: order/models.py:784 +#: order/models.py:808 msgid "Cannot allocate stock to a line without a part" msgstr "Kann BestandsObjekt keiner Zeile ohne Teil hinzufügen" -#: order/models.py:787 +#: order/models.py:811 msgid "Allocation quantity cannot exceed stock quantity" msgstr "Die zugeordnete Anzahl darf nicht die verfügbare Anzahl überschreiten" -#: order/models.py:797 +#: order/models.py:821 msgid "Quantity must be 1 for serialized stock item" msgstr "Anzahl für BestandsObjekt mit Seriennummer muss 1 sein" -#: order/models.py:802 +#: order/models.py:826 msgid "Line" msgstr "Position" -#: order/models.py:813 +#: order/models.py:837 msgid "Item" msgstr "Position" -#: order/models.py:814 +#: order/models.py:838 msgid "Select stock item to allocate" msgstr "BestandsObjekt für Zuordnung auswählen" -#: order/models.py:817 +#: order/models.py:841 msgid "Enter stock allocation quantity" msgstr "Anzahl für Bestandszuordnung eingeben" @@ -2956,7 +3033,7 @@ msgid "Export order to file" msgstr "Exportiere Bestellung in Datei" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "Bestellungs-Details" @@ -2978,8 +3055,8 @@ msgstr "Aufgegeben" #: order/templates/order/order_base.html:180 #: order/templates/order/purchase_order_detail.html:100 #: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: stock/templates/stock/location.html:191 templates/js/stock.js:736 +#: templates/js/stock.js:1324 msgid "New Location" msgstr "Neuer Lagerort" @@ -3082,28 +3159,32 @@ msgstr "Schritt %(step)s von %(count)s" msgid "Order is already processed. Files cannot be uploaded." msgstr "Bestellung ist bereits verarbeitet. Dateien können nicht hochgeladen werden." -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "Schritt 1 von 2 - Zulieferer auswählen" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "Zulieferer auswählen" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "Keine kaufbaren Teile ausgewählt" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "Zulieferer auswählen" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "Zulieferer auswählen für %(name)s" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "Teil entfernen" @@ -3136,15 +3217,20 @@ msgid "Select a purchase order for %(name)s" msgstr "Bestellung für %(name)s auswählen" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "Bestellungs-Anhänge" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +#: order/templates/order/so_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "Sind Sie sicher, dass Sie diese Position löschen möchten?" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "BestandsObjekte empfangen" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "Empfangene Teile" @@ -3154,8 +3240,8 @@ msgid "Purchase Order Items" msgstr "Bestellungs-Positionen" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/sales_order_detail.html:22 order/views.py:1321 +#: order/views.py:1404 msgid "Add Line Item" msgstr "Position hinzufügen" @@ -3163,25 +3249,31 @@ msgstr "Position hinzufügen" msgid "No line items found" msgstr "Keine Positionen gefunden" +#: order/templates/order/purchase_order_detail.html:142 +#: order/templates/order/sales_order_detail.html:223 +msgid "Total" +msgstr "Summe" + #: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/sales_order_detail.html:246 msgid "Unit Price" msgstr "Stück-Preis" #: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/sales_order_detail.html:253 msgid "Total price" -msgstr "" +msgstr "Gesamtpreis" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:255 +#: order/templates/order/sales_order_detail.html:359 msgid "Edit line item" msgstr "Position bearbeiten" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:256 msgid "Delete line item" msgstr "Position löschen" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:261 msgid "Receive line item" msgstr "Position empfangen" @@ -3202,7 +3294,7 @@ msgstr "Ausstehende Teile für %(order)s - %(desc)s empfangen" #: part/templates/part/category_navbar.html:29 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 #: users/models.py:40 msgid "Parts" @@ -3217,7 +3309,7 @@ msgid "Order Code" msgstr "Bestellnummer" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "Bestellt" @@ -3225,11 +3317,11 @@ msgstr "Bestellt" msgid "Receive" msgstr "Empfangen" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "Fehler: verknüpftes Teil wurde gelöscht" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "Position entfernen" @@ -3266,17 +3358,17 @@ msgid "Sales Order Items" msgstr "Auftrags-Positionen" #: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: templates/js/build.js:724 templates/js/build.js:1141 msgid "Actions" msgstr "Aktionen" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:610 +#: templates/js/build.js:946 msgid "Edit stock allocation" msgstr "Bestands-Zuordnung bearbeiten" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:612 +#: templates/js/build.js:947 msgid "Delete stock allocation" msgstr "Bestands-Zuordnung löschen" @@ -3284,50 +3376,50 @@ msgstr "Bestands-Zuordnung löschen" msgid "No matching line items" msgstr "Keine passenden Positionen gefunden" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:206 msgid "ID" msgstr "ID" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:274 templates/js/build.js:675 +#: templates/js/build.js:942 msgid "Allocated" msgstr "Zugeordnet" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:276 msgid "Fulfilled" msgstr "Erledigt" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:313 msgid "PO" msgstr "PO" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:343 msgid "Allocate serial numbers" msgstr "Seriennummern zuweisen" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:346 templates/js/build.js:738 msgid "Allocate stock" msgstr "Lagerbestand zuweisen" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:349 msgid "Purchase stock" msgstr "Lagerbestand kaufen" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:353 templates/js/build.js:731 +#: templates/js/build.js:1149 msgid "Build stock" msgstr "Lagerbestand bauen" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:356 +#: order/templates/order/sales_order_detail.html:465 msgid "Calculate price" msgstr "Preis berechnen" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:360 msgid "Delete line item " msgstr "Position löschen " -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:471 msgid "Update Unit Price" msgstr "Stückpreis aktualisieren" @@ -3368,10 +3460,6 @@ msgstr "Diese Aktion wird die folgenden BestandsObjekt vom Auftrag entfernen" msgid "Sales Order Attachments" msgstr "Auftrags-Anhänge" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "Sind Sie sicher, dass Sie diese Position löschen möchten?" - #: order/views.py:104 msgid "Add Purchase Order Attachment" msgstr "Bestellungs-Anhang hinzufügen" @@ -3472,90 +3560,94 @@ msgstr "Anzahl kleiner null empfangen" msgid "No lines specified" msgstr "Keine Zeilen angegeben" -#: order/views.py:1260 +#: order/views.py:1012 +msgid "Update prices" +msgstr "" + +#: order/views.py:1270 #, python-brace-format msgid "Ordered {n} parts" msgstr "{n} Teile bestellt" -#: order/views.py:1320 +#: order/views.py:1330 msgid "Supplier part must be specified" msgstr "Zuliefererteil muss ausgewählt werden" -#: order/views.py:1326 +#: order/views.py:1336 msgid "Supplier must match for Part and Order" msgstr "Zulieferer muss zu Teil und Bestellung passen" -#: order/views.py:1457 order/views.py:1475 +#: order/views.py:1467 order/views.py:1485 msgid "Edit Line Item" msgstr "Position bearbeiten" -#: order/views.py:1491 order/views.py:1503 +#: order/views.py:1501 order/views.py:1513 msgid "Delete Line Item" msgstr "Position löschen" -#: order/views.py:1496 order/views.py:1508 +#: order/views.py:1506 order/views.py:1518 msgid "Deleted line item" msgstr "Position gelöscht" -#: order/views.py:1521 +#: order/views.py:1531 msgid "Allocate Serial Numbers" msgstr "Seriennummern zuweisen" -#: order/views.py:1566 +#: order/views.py:1576 #, python-brace-format msgid "Allocated {n} items" msgstr "{n} Positionen zugeordnet" -#: order/views.py:1582 +#: order/views.py:1592 msgid "Select line item" msgstr "Position auswählen" -#: order/views.py:1613 +#: order/views.py:1623 #, python-brace-format msgid "No matching item for serial {serial}" msgstr "Kein passends Teil für Seriennummer {serial} gefunden" -#: order/views.py:1623 +#: order/views.py:1633 #, python-brace-format msgid "{serial} is not in stock" msgstr "{serial} ist nicht auf Lager" -#: order/views.py:1631 +#: order/views.py:1641 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "{serial} bereits einem Auftrag zugeordnet" -#: order/views.py:1685 +#: order/views.py:1695 msgid "Allocate Stock to Order" msgstr "Lagerbestand dem Auftrag zuweisen" -#: order/views.py:1759 +#: order/views.py:1769 msgid "Edit Allocation Quantity" msgstr "Zuordnung bearbeiten" -#: order/views.py:1774 +#: order/views.py:1784 msgid "Remove allocation" msgstr "Zuordnung entfernen" -#: order/views.py:1846 +#: order/views.py:1856 msgid "Sales order not found" msgstr "Auftrag nicht gefunden" -#: order/views.py:1852 +#: order/views.py:1862 msgid "Price not found" msgstr "Preis nicht gefunden" -#: order/views.py:1855 +#: order/views.py:1865 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "Stückpreis für {part} auf {price} aktualisiert" -#: order/views.py:1860 +#: order/views.py:1870 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "{part} Stückpreis auf {price} und Menge auf {qty} aktualisiert" -#: part/bom.py:138 part/models.py:72 part/models.py:762 +#: part/bom.py:138 part/models.py:72 part/models.py:747 #: part/templates/part/category.html:66 part/templates/part/detail.html:90 msgid "Default Location" msgstr "Standard-Lagerort" @@ -3633,7 +3725,7 @@ msgstr "Zulieferer einschließen" msgid "Include part supplier data in exported BOM" msgstr "Zulieferer-Daten in Stückliste-Export einschließen" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:122 part/models.py:2191 msgid "Parent Part" msgstr "Ausgangsteil" @@ -3709,7 +3801,7 @@ msgstr "Parameter-Vorlage zu Kategorien dieser Ebene hinzufügen" msgid "Add parameter template to all categories" msgstr "Parameter-Vorlage zu allen Kategorien hinzufügen" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:344 part/models.py:2286 msgid "Sub part" msgstr "Untergeordnetes Teil" @@ -3729,7 +3821,7 @@ msgstr "Standard Stichwörter" msgid "Default keywords for parts in this category" msgstr "Standard-Stichworte für Teile dieser Kategorie" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:82 part/models.py:2237 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "Teil-Kategorie" @@ -3740,366 +3832,361 @@ msgstr "Teil-Kategorie" msgid "Part Categories" msgstr "Teil-Kategorien" -#: part/models.py:446 part/models.py:458 +#: part/models.py:448 part/models.py:460 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "Teil '{p1}' wird in Stückliste für Teil '{p2}' benutzt (rekursiv)" -#: part/models.py:555 +#: part/models.py:557 msgid "Next available serial numbers are" msgstr "Nächste verfügbare Seriennummern wären" -#: part/models.py:559 +#: part/models.py:561 msgid "Next available serial number is" msgstr "Nächste verfügbare Seriennummer ist" -#: part/models.py:564 +#: part/models.py:566 msgid "Most recent serial number is" msgstr "Die neuste Seriennummer ist" -#: part/models.py:643 +#: part/models.py:645 msgid "Duplicate IPN not allowed in part settings" msgstr "Doppelte IPN in den Teil-Einstellungen nicht erlaubt" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "Namen, Teile- und Revisionsnummern müssen eindeutig sein" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:670 part/templates/part/detail.html:22 msgid "Part name" msgstr "Name des Teils" -#: part/models.py:692 +#: part/models.py:677 msgid "Is Template" msgstr "Ist eine Vorlage" -#: part/models.py:693 +#: part/models.py:678 msgid "Is this part a template part?" msgstr "Ist dieses Teil eine Vorlage?" -#: part/models.py:704 +#: part/models.py:689 msgid "Is this part a variant of another part?" msgstr "Ist dieses Teil eine Variante eines anderen Teils?" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:690 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "Variante von" -#: part/models.py:711 +#: part/models.py:696 msgid "Part description" msgstr "Beschreibung des Teils" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:701 part/templates/part/category.html:73 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "Schlüsselwörter" -#: part/models.py:717 +#: part/models.py:702 msgid "Part keywords to improve visibility in search results" msgstr "Schlüsselworte um die Sichtbarkeit in Suchergebnissen zu verbessern" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:709 part/models.py:2236 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "Kategorie" -#: part/models.py:725 +#: part/models.py:710 msgid "Part category" msgstr "Teile-Kategorie" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:715 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "IPN (Interne Produktnummer)" -#: part/models.py:731 +#: part/models.py:716 msgid "Internal Part Number" msgstr "Interne Teilenummer" -#: part/models.py:737 +#: part/models.py:722 msgid "Part revision or version number" msgstr "Revisions- oder Versionsnummer" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:723 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "Revision" -#: part/models.py:760 +#: part/models.py:745 msgid "Where is this item normally stored?" msgstr "Wo wird dieses Teil normalerweise gelagert?" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:792 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "Standard Zulieferer" -#: part/models.py:808 +#: part/models.py:793 msgid "Default supplier part" msgstr "Standard Zuliefererteil" -#: part/models.py:815 +#: part/models.py:800 msgid "Default Expiry" msgstr "Standard Ablaufzeit" -#: part/models.py:816 +#: part/models.py:801 msgid "Expiry time (in days) for stock items of this part" msgstr "Ablauf-Zeit (in Tagen) für Lagerbestand dieses Teils" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:806 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "Minimaler Lagerbestand" -#: part/models.py:822 +#: part/models.py:807 msgid "Minimum allowed stock level" msgstr "Minimal zulässiger Lagerbestand" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "Einheiten" - -#: part/models.py:829 +#: part/models.py:814 msgid "Stock keeping units for this part" msgstr "Stock Keeping Units (SKU) für dieses Teil" -#: part/models.py:835 +#: part/models.py:820 msgid "Can this part be built from other parts?" msgstr "Kann dieses Teil aus anderen Teilen angefertigt werden?" -#: part/models.py:841 +#: part/models.py:826 msgid "Can this part be used to build other parts?" msgstr "Kann dieses Teil zum Bauauftrag von anderen genutzt werden?" -#: part/models.py:847 +#: part/models.py:832 msgid "Does this part have tracking for unique items?" msgstr "Hat dieses Teil Tracking für einzelne Objekte?" -#: part/models.py:852 +#: part/models.py:837 msgid "Can this part be purchased from external suppliers?" msgstr "Kann dieses Teil von externen Zulieferern gekauft werden?" -#: part/models.py:857 +#: part/models.py:842 msgid "Can this part be sold to customers?" msgstr "Kann dieses Teil an Kunden verkauft werden?" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:846 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 #: templates/js/table_filters.js:241 templates/js/table_filters.js:310 msgid "Active" msgstr "Aktiv" -#: part/models.py:862 +#: part/models.py:847 msgid "Is this part active?" msgstr "Ist dieses Teil aktiv?" -#: part/models.py:867 +#: part/models.py:852 msgid "Is this a virtual part, such as a software product or license?" msgstr "Ist dieses Teil virtuell, wie zum Beispiel eine Software oder Lizenz?" -#: part/models.py:872 +#: part/models.py:857 msgid "Part notes - supports Markdown formatting" msgstr "Bemerkungen - unterstüzt Markdown-Formatierung" -#: part/models.py:875 +#: part/models.py:860 msgid "BOM checksum" msgstr "Prüfsumme der Stückliste" -#: part/models.py:875 +#: part/models.py:860 msgid "Stored BOM checksum" msgstr "Prüfsumme der Stückliste gespeichert" -#: part/models.py:878 +#: part/models.py:863 msgid "BOM checked by" msgstr "Stückliste kontrolliert von" -#: part/models.py:880 +#: part/models.py:865 msgid "BOM checked date" msgstr "BOM Kontrolldatum" -#: part/models.py:884 +#: part/models.py:869 msgid "Creation User" msgstr "Erstellungs-Nutzer" -#: part/models.py:1616 +#: part/models.py:1608 msgid "Sell multiple" msgstr "Mehrere verkaufen" -#: part/models.py:2040 +#: part/models.py:2063 msgid "Test templates can only be created for trackable parts" msgstr "Test-Vorlagen können nur für verfolgbare Teile angelegt werden" -#: part/models.py:2057 +#: part/models.py:2080 msgid "Test with this name already exists for this part" msgstr "Ein Test mit diesem Namen besteht bereits für dieses Teil" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2100 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "Test-Name" -#: part/models.py:2078 +#: part/models.py:2101 msgid "Enter a name for the test" msgstr "Namen für diesen Test eingeben" -#: part/models.py:2083 +#: part/models.py:2106 msgid "Test Description" msgstr "Test-Beschreibung" -#: part/models.py:2084 +#: part/models.py:2107 msgid "Enter description for this test" msgstr "Beschreibung für diesen Test eingeben" -#: part/models.py:2089 templates/js/part.js:725 +#: part/models.py:2112 templates/js/part.js:726 #: templates/js/table_filters.js:227 msgid "Required" msgstr "Benötigt" -#: part/models.py:2090 +#: part/models.py:2113 msgid "Is this test required to pass?" msgstr "Muss dieser Test erfolgreich sein?" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2118 templates/js/part.js:734 msgid "Requires Value" msgstr "Erfordert Wert" -#: part/models.py:2096 +#: part/models.py:2119 msgid "Does this test require a value when adding a test result?" msgstr "Muss für diesen Test ein Wert für das Test-Ergebnis eingetragen werden?" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2124 templates/js/part.js:741 msgid "Requires Attachment" msgstr "Anhang muss eingegeben werden" -#: part/models.py:2102 +#: part/models.py:2125 msgid "Does this test require a file attachment when adding a test result?" msgstr "Muss für diesen Test ein Anhang für das Test-Ergebnis hinzugefügt werden?" -#: part/models.py:2135 +#: part/models.py:2158 msgid "Parameter template name must be unique" msgstr "Vorlagen-Name des Parameters muss eindeutig sein" -#: part/models.py:2140 +#: part/models.py:2163 msgid "Parameter Name" msgstr "Name des Parameters" -#: part/models.py:2142 +#: part/models.py:2165 msgid "Parameter Units" msgstr "Einheit des Parameters" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2193 part/models.py:2242 part/models.py:2243 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "Parameter Vorlage" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Data" msgstr "Wert" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Parameter Value" msgstr "Parameter Wert" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2247 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "Standard-Wert" -#: part/models.py:2225 +#: part/models.py:2248 msgid "Default Parameter Value" msgstr "Standard Parameter Wert" -#: part/models.py:2255 +#: part/models.py:2278 msgid "Select parent part" msgstr "Ausgangsteil auswählen" -#: part/models.py:2264 +#: part/models.py:2287 msgid "Select part to be used in BOM" msgstr "Teil für die Nutzung in der Stückliste auswählen" -#: part/models.py:2270 +#: part/models.py:2293 msgid "BOM quantity for this BOM item" msgstr "Stücklisten-Anzahl für dieses Stücklisten-Teil" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2295 templates/js/bom.js:216 templates/js/bom.js:285 msgid "Optional" msgstr "Optional" -#: part/models.py:2272 +#: part/models.py:2295 msgid "This BOM item is optional" msgstr "Diese Stücklisten-Position ist optional" -#: part/models.py:2275 +#: part/models.py:2298 msgid "Overage" msgstr "Überschuss" -#: part/models.py:2276 +#: part/models.py:2299 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "Geschätzter Ausschuss (absolut oder prozentual)" -#: part/models.py:2279 +#: part/models.py:2302 msgid "BOM item reference" msgstr "Referenz der Postion auf der Stückliste" -#: part/models.py:2282 +#: part/models.py:2305 msgid "BOM item notes" msgstr "Notizen zur Stücklisten-Position" -#: part/models.py:2284 +#: part/models.py:2307 msgid "Checksum" msgstr "Prüfsumme" -#: part/models.py:2284 +#: part/models.py:2307 msgid "BOM line checksum" msgstr "Prüfsumme der Stückliste" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2311 templates/js/bom.js:302 templates/js/bom.js:309 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "Geerbt" -#: part/models.py:2289 +#: part/models.py:2312 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "Diese Stücklisten-Position wird in die Stücklisten von Teil-Varianten vererbt" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2317 templates/js/bom.js:294 msgid "Allow Variants" msgstr "Varianten zulassen" -#: part/models.py:2295 +#: part/models.py:2318 msgid "Stock items for variant parts can be used for this BOM item" msgstr "Lagerbestand von Varianten kann für diese Stücklisten-Position verwendet werden" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 +#: part/models.py:2394 part/views.py:1692 part/views.py:1744 #: stock/models.py:294 msgid "Quantity must be integer value for trackable parts" msgstr "Menge muss eine Ganzzahl sein" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2403 part/models.py:2405 msgid "Sub part must be specified" msgstr "Zuliefererteil muss festgelegt sein" -#: part/models.py:2385 +#: part/models.py:2408 msgid "BOM Item" msgstr "Stücklisten-Position" -#: part/models.py:2502 +#: part/models.py:2527 msgid "Part 1" msgstr "Teil 1" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Part 2" msgstr "Teil 2" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Select Related Part" msgstr "verknüpftes Teil auswählen" -#: part/models.py:2538 +#: part/models.py:2563 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "Fehler bei Verwandschaft: Ist das Teil mit sich selbst verwandt oder ist das die Verwandtschaft nicht eindeutig?" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" -msgstr "Teil-Bestandszuordnungen" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" +msgstr "" #: part/templates/part/attachments.html:10 msgid "Part Attachments" @@ -4113,8 +4200,8 @@ msgstr "Sind Sie sicher, dass Sie diese Stücklisten-Position löschen wollen?" msgid "Deleting this entry will remove the BOM row from the following part" msgstr "Die Löschung dieses Eintrags wird das Stücklisten-Position vom folgenden Teil entfernen" -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:50 +#: part/templates/part/navbar.html:53 msgid "Bill of Materials" msgstr "Stückliste" @@ -4161,7 +4248,7 @@ msgstr "Stückliste bearbeiten" msgid "Validate Bill of Materials" msgstr "Stückliste kontrollieren" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:1987 msgid "Export Bill of Materials" msgstr "Stückliste exportieren" @@ -4178,7 +4265,7 @@ msgid "All selected BOM items will be deleted" msgstr "Alle ausgewählte Stücklistenpositionen werden gelöscht" #: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: templates/js/stock.js:1313 msgid "Create New Part" msgstr "Neues Teil anlegen" @@ -4259,7 +4346,7 @@ msgstr "Neuen Bauauftrag beginnen" msgid "All parts" msgstr "Alle Teile" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:29 part/views.py:2397 msgid "Create new part category" msgstr "Teil-Kategorie anlegen" @@ -4319,7 +4406,7 @@ msgid "View grid display" msgstr "Rasteransicht anzeigen" #: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: stock/templates/stock/location.html:192 templates/js/stock.js:737 msgid "Create new location" msgstr "Neuen Lagerort anlegen" @@ -4374,14 +4461,8 @@ msgstr "Wenn diese Kat. gelöscht wird, werden diese Teile in die übergeordnete msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "Wenn diese Kat. gelöscht wird, werden diese Teile in die oberste Kat. verschoben" -#: part/templates/part/category_navbar.html:34 -#: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" -msgstr "Parameter" - #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:21 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "Teilparameter" @@ -4409,7 +4490,7 @@ msgstr "Teil evtl. Duplikat dieser Teile" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "%(full_name)s - %(desc)s (%(match_per)s%% übereinstimmend)" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:13 msgid "Part Details" msgstr "Teil Details" @@ -4489,6 +4570,36 @@ msgstr "Teil ist aktiv" msgid "Part is not active" msgstr "Teil ist nicht aktiv" +#: part/templates/part/internal_prices.html:11 +#: part/templates/part/navbar.html:100 +msgid "Internal Price Information" +msgstr "" + +#: part/templates/part/internal_prices.html:19 part/views.py:2822 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/internal_prices.html:28 templates/403.html:5 +#: templates/403.html:11 +msgid "Permission Denied" +msgstr "Zugriff verweigert" + +#: part/templates/part/internal_prices.html:31 templates/403.html:14 +msgid "You do not have permission to view this page." +msgstr "Keine Berechtigung zum Anzeigen dieser Seite." + +#: part/templates/part/internal_prices.html:59 +msgid "No internal price break information found" +msgstr "" + +#: part/templates/part/internal_prices.html:110 +msgid "Edit internal price break" +msgstr "" + +#: part/templates/part/internal_prices.html:111 +msgid "Delete internal price break" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "Teil-Hersteller" @@ -4502,127 +4613,141 @@ msgstr "Herstellerteile löschen" msgid "Create new manufacturer" msgstr "Neuen Hersteller anlegen" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:28 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "Teil Varianten" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:31 msgid "Variants" msgstr "Varianten" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:42 msgid "Allocated Stock" msgstr "Lagerbestand zuweisen" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:45 msgid "Allocations" msgstr "Zuweisungen" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:66 part/templates/part/navbar.html:69 msgid "Used In" msgstr "Benutzt in" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 +#: part/templates/part/navbar.html:74 part/templates/part/order_prices.html:12 msgid "Order Price Information" msgstr "Bestellpreisinformationen" -#: part/templates/part/navbar.html:75 +#: part/templates/part/navbar.html:77 msgid "Order Price" msgstr "Bestellpreis" -#: part/templates/part/navbar.html:98 +#: part/templates/part/navbar.html:103 part/templates/part/order_prices.html:93 +#: part/templates/part/part_pricing.html:82 +msgid "Internal Price" +msgstr "Interner Preis" + +#: part/templates/part/navbar.html:106 msgid "Sales Price Information" msgstr "Preisinformationen ansehen" -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:120 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "Teil Test-Vorlagen" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:123 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "Tests" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:127 part/templates/part/navbar.html:130 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "Verknüpfte Teile" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:139 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "Teil-Bemerkungen" -#: part/templates/part/order_prices.html:21 +#: part/templates/part/order_prices.html:24 +#: part/templates/part/part_base.html:282 +msgid "Calculate" +msgstr "Berechnen" + +#: part/templates/part/order_prices.html:31 msgid "Pricing ranges" msgstr "Preisspannen" -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 +#: part/templates/part/order_prices.html:36 +#: part/templates/part/part_pricing.html:22 msgid "Supplier Pricing" msgstr "Zulieferer-Preise" -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 +#: part/templates/part/order_prices.html:37 +#: part/templates/part/order_prices.html:62 +#: part/templates/part/order_prices.html:94 +#: part/templates/part/order_prices.html:108 +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 msgid "Unit Cost" msgstr "Stückpreis" -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 +#: part/templates/part/order_prices.html:44 +#: part/templates/part/order_prices.html:69 +#: part/templates/part/order_prices.html:99 +#: part/templates/part/order_prices.html:113 +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 msgid "Total Cost" msgstr "Gesamtkosten" -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 +#: part/templates/part/order_prices.html:52 +#: part/templates/part/part_pricing.html:40 msgid "No supplier pricing available" msgstr "Keine Zulieferer-Preise verfügbar" -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 +#: part/templates/part/order_prices.html:61 +#: part/templates/part/order_prices.html:128 +#: part/templates/part/part_pricing.html:48 msgid "BOM Pricing" msgstr "Stücklistenpreise" -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 +#: part/templates/part/order_prices.html:77 +#: part/templates/part/part_pricing.html:66 msgid "Note: BOM pricing is incomplete for this part" msgstr "Anmerkung: Stücklistenbepreisung für dieses Teil ist unvollständig" -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 +#: part/templates/part/order_prices.html:84 +#: part/templates/part/part_pricing.html:73 msgid "No BOM pricing available" msgstr "Keine Stücklisten-Preise verfügbar" -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 +#: part/templates/part/order_prices.html:122 +#: part/templates/part/part_pricing.html:113 msgid "No pricing information is available for this part." msgstr "Keine Preise für dieses Teil verfügbar" -#: part/templates/part/order_prices.html:113 +#: part/templates/part/order_prices.html:138 msgid "Stock Pricing" msgstr "Bestandspreise" -#: part/templates/part/order_prices.html:121 +#: part/templates/part/order_prices.html:146 msgid "No stock pricing history is available for this part." msgstr "Für dieses Teil sind keine Bestandspreise verfügbar." -#: part/templates/part/order_prices.html:140 +#: part/templates/part/order_prices.html:165 #, python-format msgid "Single Price - %(currency)s" msgstr "Einzelpreis - %(currency)s" -#: part/templates/part/order_prices.html:152 +#: part/templates/part/order_prices.html:177 #, python-format msgid "Single Price Difference - %(currency)s" msgstr "Einzelpreisdifferenz - %(currency)s" -#: part/templates/part/order_prices.html:163 +#: part/templates/part/order_prices.html:189 #, python-format msgid "Part Single Price - %(currency)s" msgstr "Einzelpreis für Zuliefererteil- %(currency)s" @@ -4631,19 +4756,6 @@ msgstr "Einzelpreis für Zuliefererteil- %(currency)s" msgid "Add new parameter" msgstr "Parameter hinzufügen" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "Neuer Parameter" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "Wert" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "Bearbeiten" @@ -4661,7 +4773,7 @@ msgid "Part List" msgstr "Teileliste" #: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: templates/js/company.js:355 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "Inaktiv" @@ -4741,14 +4853,10 @@ msgid "Can Build" msgstr "Herstellbar" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "Im Bau" -#: part/templates/part/part_base.html:265 -msgid "Calculate" -msgstr "Berechnen" - #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "Test Vorlage hinzufügen" @@ -4817,7 +4925,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "Lagerbestand aller Varianten von %(full_name)s" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "Kein Bestand" @@ -4854,7 +4962,7 @@ msgstr "Neue Variante anlegen" msgid "New Variant" msgstr "neue Variante anlegen" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "Unbekannte Datenbank" @@ -4923,227 +5031,239 @@ msgstr "Übereinstimmung gefunden - Teil trotzdem anlegen" msgid "Created new part" msgstr "Neues Teil angelegt" -#: part/views.py:914 +#: part/views.py:925 msgid "Part QR Code" msgstr "Teil-QR-Code" -#: part/views.py:1016 +#: part/views.py:1027 msgid "Upload Part Image" msgstr "Teilbild hochladen" -#: part/views.py:1022 part/views.py:1057 +#: part/views.py:1033 part/views.py:1068 msgid "Updated part image" msgstr "Teilbild aktualisiert" -#: part/views.py:1031 +#: part/views.py:1042 msgid "Select Part Image" msgstr "Teilbild auswählen" -#: part/views.py:1060 +#: part/views.py:1071 msgid "Part image not found" msgstr "Teilbild nicht gefunden" -#: part/views.py:1071 +#: part/views.py:1082 msgid "Edit Part Properties" msgstr "Teileigenschaften bearbeiten" -#: part/views.py:1106 +#: part/views.py:1117 msgid "Duplicate BOM" msgstr "Stückliste duplizieren" -#: part/views.py:1136 +#: part/views.py:1147 msgid "Confirm duplication of BOM from parent" msgstr "bestätige Duplizierung Stückliste von übergeordneter Stückliste" -#: part/views.py:1157 +#: part/views.py:1168 msgid "Validate BOM" msgstr "Stückliste überprüfen" -#: part/views.py:1178 +#: part/views.py:1189 msgid "Confirm that the BOM is valid" msgstr "Bestätigen, dass Stückliste korrekt ist" -#: part/views.py:1189 +#: part/views.py:1200 msgid "Validated Bill of Materials" msgstr "überprüfte Stückliste" -#: part/views.py:1323 +#: part/views.py:1334 msgid "No BOM file provided" msgstr "Keine Stückliste angegeben" -#: part/views.py:1684 +#: part/views.py:1695 msgid "Enter a valid quantity" msgstr "Bitte eine gültige Anzahl eingeben" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1720 part/views.py:1723 msgid "Select valid part" msgstr "Bitte ein gültiges Teil auswählen" -#: part/views.py:1718 +#: part/views.py:1729 msgid "Duplicate part selected" msgstr "Teil doppelt ausgewählt" -#: part/views.py:1756 +#: part/views.py:1767 msgid "Select a part" msgstr "Teil auswählen" -#: part/views.py:1762 +#: part/views.py:1773 msgid "Selected part creates a circular BOM" msgstr "gewähltes Teil erzeugt rekursive Stückliste" -#: part/views.py:1766 +#: part/views.py:1777 msgid "Specify quantity" msgstr "Anzahl angeben" -#: part/views.py:2028 +#: part/views.py:2039 msgid "Confirm Part Deletion" msgstr "Löschen des Teils bestätigen" -#: part/views.py:2035 +#: part/views.py:2046 msgid "Part was deleted" msgstr "Teil wurde gelöscht" -#: part/views.py:2044 +#: part/views.py:2055 msgid "Part Pricing" msgstr "Teilbepreisung" -#: part/views.py:2178 +#: part/views.py:2196 msgid "Create Part Parameter Template" msgstr "Teilparametervorlage anlegen" -#: part/views.py:2188 +#: part/views.py:2206 msgid "Edit Part Parameter Template" msgstr "Teilparametervorlage bearbeiten" -#: part/views.py:2195 +#: part/views.py:2213 msgid "Delete Part Parameter Template" msgstr "Teilparametervorlage löschen" -#: part/views.py:2203 +#: part/views.py:2221 msgid "Create Part Parameter" msgstr "Teilparameter anlegen" -#: part/views.py:2253 +#: part/views.py:2271 msgid "Edit Part Parameter" msgstr "Teilparameter bearbeiten" -#: part/views.py:2267 +#: part/views.py:2285 msgid "Delete Part Parameter" msgstr "Teilparameter löschen" -#: part/views.py:2327 +#: part/views.py:2345 msgid "Edit Part Category" msgstr "Teil-Kategorie bearbeiten" -#: part/views.py:2365 +#: part/views.py:2383 msgid "Delete Part Category" msgstr "Teil-Kategorie löschen" -#: part/views.py:2371 +#: part/views.py:2389 msgid "Part category was deleted" msgstr "Teil-Kategorie wurde gelöscht" -#: part/views.py:2423 +#: part/views.py:2441 msgid "Create Category Parameter Template" msgstr "Kategorieparametervorlage anlegen" -#: part/views.py:2524 +#: part/views.py:2542 msgid "Edit Category Parameter Template" msgstr "Kategorieparametervorlage bearbeiten" -#: part/views.py:2580 +#: part/views.py:2598 msgid "Delete Category Parameter Template" msgstr "Kategorieparametervorlage löschen" -#: part/views.py:2599 +#: part/views.py:2617 msgid "Create BOM Item" msgstr "Stücklisten-Position anlegen" -#: part/views.py:2669 +#: part/views.py:2687 msgid "Edit BOM item" msgstr "Stücklisten-Position bearbeiten" -#: part/views.py:2725 +#: part/views.py:2743 msgid "Confim BOM item deletion" msgstr "löschen von Stücklisten-Position bestätigen" -#: report/models.py:180 +#: part/views.py:2831 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2839 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "Vorlagen Name" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "Bericht-Vorlage Datei" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "Bericht-Vorlage Beschreibung" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "Bericht Revisionsnummer (autom. erhöht)" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "Muster für die Erstellung von Berichtsdateinamen" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "Bericht-Vorlage ist ein" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "BestandsObjekte-Abfragefilter (kommagetrennte Liste mit Schlüssel=Wert-Paaren)" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "einfügen Installiert in Tests" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "Test-Ergebnisse für BestandsObjekte in Baugruppen einschließen" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "Bauauftrag Filter" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "Bau-Abfragefilter (kommagetrennte Liste mit Schlüssel=Wert-Paaren)" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "Teil Filter" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "Teile-Abfragefilter (kommagetrennte Liste mit Schlüssel=Wert-Paaren)" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "Bestellungs-Abfragefilter" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "Auftrags-Abfragefilter" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "Snippet" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "Berichts-Snippet" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "Snippet-Beschreibung" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "Ressource" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "Berichts-Ressource" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "Ressource-Beschreibung" @@ -5175,7 +5295,7 @@ msgid "Result" msgstr "Ergebnis" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:195 templates/js/stock.js:1012 msgid "Date" msgstr "Datum" @@ -5198,7 +5318,7 @@ msgid "Moved {n} parts to {loc}" msgstr "{n} Teile nach {loc} bewegt" #: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "Ablaufdatum" @@ -5484,12 +5604,12 @@ msgid "Stock Item Attachments" msgstr "BestandsObjekt-Anhang" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "abgelaufen" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "überfällig" @@ -5619,7 +5739,7 @@ msgstr "Dieses BestandsObjekt wird automatisch gelöscht wenn der Lagerbestand a msgid "Stock Item Details" msgstr "BestandsObjekt-Details" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:593 msgid "No location set" msgstr "Kein Lagerort gesetzt" @@ -5631,25 +5751,29 @@ msgstr "Barcode-Bezeichner" msgid "Parent Item" msgstr "Elternposition" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "Dieses BestandsObjekt lief am %(item.expiry_date)s ab" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "Dieses BestandsObjekt läuft am %(item.expiry_date)s ab" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "Zuletzt aktualisiert" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "Letzte Inventur" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "Keine Inventur ausgeführt" @@ -5946,7 +6070,7 @@ msgstr "Entfernen" msgid "Add Stock Items" msgstr "BestandsObjekte hinzufügen" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:1001 users/models.py:187 msgid "Add" msgstr "Hinzufügen" @@ -6012,7 +6136,7 @@ msgstr "BestandsObjekt bearbeiten" msgid "Serialize Stock" msgstr "Lagerbestand erfassen" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1575 templates/js/build.js:326 msgid "Create new Stock Item" msgstr "Neues BestandsObjekt hinzufügen" @@ -6044,14 +6168,6 @@ msgstr "Lagerbestands-Tracking-Eintrag bearbeiten" msgid "Add Stock Tracking Entry" msgstr "Lagerbestands-Tracking-Eintrag hinzufügen" -#: templates/403.html:5 templates/403.html:11 -msgid "Permission Denied" -msgstr "Zugriff verweigert" - -#: templates/403.html:14 -msgid "You do not have permission to view this page." -msgstr "Keine Berechtigung zum Anzeigen dieser Seite." - #: templates/404.html:5 templates/404.html:11 msgid "Page Not Found" msgstr "Seite nicht gefunden" @@ -6120,11 +6236,11 @@ msgstr "Suchergebnisse" msgid "Enter a search query" msgstr "Eine Sucheanfrage eingeben" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "an Kunde versand" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "Kein Lagerort gesetzt" @@ -6172,12 +6288,12 @@ msgid "No category parameter templates found" msgstr "Keine Kategorie-Parametervorlagen gefunden" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:85 msgid "Edit Template" msgstr "Vorlage bearbeiten" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:86 msgid "Delete Template" msgstr "Vorlage löschen" @@ -6225,11 +6341,11 @@ msgstr "Teil-Einstellungen" msgid "Part Options" msgstr "Teil-Optionen" -#: templates/InvenTree/settings/part.html:40 +#: templates/InvenTree/settings/part.html:44 msgid "Part Parameter Templates" msgstr "Teil-Parametervorlage" -#: templates/InvenTree/settings/part.html:61 +#: templates/InvenTree/settings/part.html:65 msgid "No part parameter templates found" msgstr "Keine Teilparametervorlagen gefunden" @@ -6345,47 +6461,51 @@ msgid "API Version" msgstr "API-Version" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "Django-Version" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "Commit-Hash" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "Commit-Datum" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "InvenTree-Dokumentation" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "Code auf GitHub ansehen" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "Danksagung" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "Mobile App" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "Fehlerbericht senden" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "In die Zwischenablage kopieren" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "Versionsinformationen kopieren" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 +#: templates/about.html:100 templates/js/modals.js:568 +#: templates/js/modals.js:861 templates/modals.html:29 templates/modals.html:54 #: templates/modals.html:97 msgid "Close" msgstr "Schliessen" @@ -6446,7 +6566,7 @@ msgstr "Server-Fehler" msgid "Unknown response from server" msgstr "Unbekannte Antwort von Server erhalten" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:921 msgid "Invalid server response" msgstr "Ungültige Antwort von Server" @@ -6510,7 +6630,7 @@ msgstr "In Lagerorten buchen" msgid "Barcode does not match a valid location" msgstr "Barcode entspricht keinem Lagerort" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1091 msgid "Open subassembly" msgstr "Unterbaugruppe öffnen" @@ -6546,7 +6666,7 @@ msgstr "Stücklisten-Position bearbeiten" msgid "Delete BOM Item" msgstr "Stücklisten-Position löschen" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:470 templates/js/build.js:423 templates/js/build.js:1189 msgid "No BOM items found" msgstr "Keine Stücklisten-Position(en) gefunden" @@ -6566,37 +6686,45 @@ msgstr "Endprodukt fertigstellen" msgid "Delete build output" msgstr "Endprodukt entfernen" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:382 +msgid "Location not specified" +msgstr "Standort nicht angegeben" + +#: templates/js/build.js:325 templates/stock_table.html:20 msgid "New Stock Item" msgstr "Neues BestandsObjekt" -#: templates/js/build.js:559 +#: templates/js/build.js:644 msgid "Required Part" msgstr "benötigtes Teil" -#: templates/js/build.js:580 +#: templates/js/build.js:665 msgid "Quantity Per" msgstr "Anzahl pro" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:735 templates/js/build.js:1153 #: templates/stock_table.html:59 msgid "Order stock" msgstr "Bestand bestellen" -#: templates/js/build.js:701 +#: templates/js/build.js:788 msgid "No builds matching query" msgstr "Keine Bauaufträge passen zur Anfrage" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:805 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:966 msgid "Select" msgstr "Auswählen" -#: templates/js/build.js:738 +#: templates/js/build.js:825 msgid "Build order is overdue" msgstr "Bauauftrag ist überfällig" -#: templates/js/build.js:837 +#: templates/js/build.js:924 msgid "No parts allocated for" msgstr "Keine Teile zugeordnet zu" @@ -6616,17 +6744,29 @@ msgstr "Keine Firmeninformation gefunden" msgid "No manufacturer parts found" msgstr "Keine Herstellerteile gefunden" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:148 templates/js/company.js:347 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "Vorlagenteil" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:152 templates/js/company.js:351 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "Baugruppe" -#: templates/js/company.js:227 +#: templates/js/company.js:226 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:262 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:263 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:328 msgid "No supplier parts found" msgstr "Keine Zuliefererteile gefunden" @@ -6714,76 +6854,76 @@ msgstr "abbrechen" msgid "Loading Data" msgstr "Lade Daten" -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:567 templates/js/modals.js:860 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "Abschicken" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Invalid response from server" msgstr "ungültige Antwort vom Server" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Form data missing from server response" msgstr "Formulardaten fehlen bei Serverantwort" -#: templates/js/modals.js:810 +#: templates/js/modals.js:824 msgid "Error posting form data" msgstr "Formulardaten fehlerhaft" -#: templates/js/modals.js:901 +#: templates/js/modals.js:921 msgid "JSON response missing form data" msgstr "JSON Antwort enthält keine Formulardaten" -#: templates/js/modals.js:911 +#: templates/js/modals.js:931 msgid "No Response" msgstr "Keine Antwort" -#: templates/js/modals.js:912 +#: templates/js/modals.js:932 msgid "No response from the InvenTree server" msgstr "keine Antwort vom InvenTree Server" -#: templates/js/modals.js:916 +#: templates/js/modals.js:936 msgid "Error 400: Bad Request" msgstr "Fehler 400: Ungültige Anfrage" -#: templates/js/modals.js:917 +#: templates/js/modals.js:937 msgid "Server returned error code 400" msgstr "Fehler 400 von Server erhalten" -#: templates/js/modals.js:921 +#: templates/js/modals.js:941 msgid "Error 401: Not Authenticated" msgstr "Fehler 401: Nicht Angemeldet" -#: templates/js/modals.js:922 +#: templates/js/modals.js:942 msgid "Authentication credentials not supplied" msgstr "Authentication Kredentials nicht angegeben" -#: templates/js/modals.js:926 +#: templates/js/modals.js:946 msgid "Error 403: Permission Denied" msgstr "Fehler 403: keine Berechtigung" -#: templates/js/modals.js:927 +#: templates/js/modals.js:947 msgid "You do not have the required permissions to access this function" msgstr "Fehlende Berechtigung für diese Aktion" -#: templates/js/modals.js:931 +#: templates/js/modals.js:951 msgid "Error 404: Resource Not Found" msgstr "Fehler 404: Ressource nicht gefunden" -#: templates/js/modals.js:932 +#: templates/js/modals.js:952 msgid "The requested resource could not be located on the server" msgstr "Die angefragte Ressource kann auf diesem Server nicht gefunden werden" -#: templates/js/modals.js:936 +#: templates/js/modals.js:956 msgid "Error 408: Timeout" msgstr "Fehler 408: Zeitüberschreitung" -#: templates/js/modals.js:937 +#: templates/js/modals.js:957 msgid "Connection timeout while requesting data from server" msgstr "Verbindungszeitüberschreitung bei der Datenanforderung" -#: templates/js/modals.js:940 +#: templates/js/modals.js:960 msgid "Error requesting form data" msgstr "Fehler bei Formulardaten-Anfrage" @@ -6799,6 +6939,10 @@ msgstr "Bestellung überfällig" msgid "No sales orders found" msgstr "Keine Aufträge gefunden" +#: templates/js/order.js:343 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "JA" @@ -6827,39 +6971,39 @@ msgstr "Verkäufliches Teil" msgid "No variants found" msgstr "Keine Varianten gefunden" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "Keine Teile gefunden" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "Keine Kategorie" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:323 msgid "Low stock" msgstr "Bestand niedrig" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:990 msgid "Path" msgstr "Pfad" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "Keine zur Anfrage passenden Testvorlagen" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "Testergebnis bearbeiten" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "Testergebnis löschen" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "Dieses Testergebnis ist für ein Hauptteil" -#: templates/js/part.js:805 +#: templates/js/part.js:806 msgid "Single Price Difference" msgstr "Einzelpreisdifferenz" @@ -6957,155 +7101,155 @@ msgstr "Keine Testergebnisse gefunden" msgid "Test Date" msgstr "Testdatum" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "In Arbeit" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "In BestandsObjekt installiert" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "Auftrag zugewiesen" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "Keine zur Anfrage passenden BestandsObjekte" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "Teile" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "lose" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "Lagerorte" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "unbekannter Lagerort" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "BestandsObjekt wird produziert" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "BestandsObjekt wurde Auftrag zugewiesen" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "BestandsObjekt wurde Kunden zugewiesen" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "BestandsObjekt ist abgelaufen" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "BestandsObjekt läuft demnächst ab" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "BestandsObjekt zugewiesen" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "BestandsObjekt in anderem Element verbaut" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "BestandsObjekt abgewiesen" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "BestandsObjekt verloren" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "BestandsObjekt zerstört" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "gelöscht" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "Inventur" -#: templates/js/stock.js:828 +#: templates/js/stock.js:853 msgid "Stock Status" msgstr "Status" -#: templates/js/stock.js:843 +#: templates/js/stock.js:868 msgid "Set Stock Status" msgstr "Status setzen" -#: templates/js/stock.js:857 +#: templates/js/stock.js:882 msgid "Select Status Code" msgstr "Status Code setzen" -#: templates/js/stock.js:858 +#: templates/js/stock.js:883 msgid "Status code must be selected" msgstr "Status Code muss ausgewählt werden" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1022 msgid "Invalid date" msgstr "Ungültiges Datum" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1069 msgid "Location no longer exists" msgstr "Standort nicht mehr vorhanden" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1088 msgid "Purchase order no longer exists" msgstr "Bestellung existiert nicht mehr" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1107 msgid "Customer no longer exists" msgstr "Kunde existiert nicht mehr" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1125 msgid "Stock item no longer exists" msgstr "Lagerbestand existiert nicht mehr" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1148 msgid "Added" msgstr "Hinzugefügt" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1156 msgid "Removed" msgstr "Entfernt" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1188 msgid "No user information" msgstr "Keine Benutzerinformation" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1200 msgid "Edit tracking entry" msgstr "Tracking-Eintrag bearbeiten" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1201 msgid "Delete tracking entry" msgstr "Tracking-Eintrag löschen" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1325 msgid "Create New Location" msgstr "Neuen Lagerort anlegen" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1366 msgid "No installed items" msgstr "Keine installierten Elemente" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1389 msgid "Serial" msgstr "Seriennummer" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1417 msgid "Uninstall Stock Item" msgstr "Lagerbestand entfernen" @@ -7271,56 +7415,56 @@ msgstr "Favorit" msgid "Purchasable" msgstr "Käuflich" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "Lade Daten" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "Zeilen pro Seite" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "zeige" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "bis" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "von" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "Zeilen" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "Suche" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "Keine passenden Ergebnisse gefunden" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "Zeige/Verstecke Pagination" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "Neu laden" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "umschalten" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "Spalten" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "Alle" @@ -7564,35 +7708,35 @@ msgstr "Berechtigungen" msgid "Important dates" msgstr "wichtige Daten" -#: users/models.py:170 +#: users/models.py:174 msgid "Permission set" msgstr "Berechtigung geändert" -#: users/models.py:178 +#: users/models.py:182 msgid "Group" msgstr "Gruppe" -#: users/models.py:181 +#: users/models.py:185 msgid "View" msgstr "Ansicht" -#: users/models.py:181 +#: users/models.py:185 msgid "Permission to view items" msgstr "Berechtigung Einträge anzuzeigen" -#: users/models.py:183 +#: users/models.py:187 msgid "Permission to add items" msgstr "Berechtigung Einträge zu erstellen" -#: users/models.py:185 +#: users/models.py:189 msgid "Change" msgstr "Ändern" -#: users/models.py:185 +#: users/models.py:189 msgid "Permissions to edit items" msgstr "Berechtigungen Einträge zu ändern" -#: users/models.py:187 +#: users/models.py:191 msgid "Permission to delete items" msgstr "Berechtigung Einträge zu löschen" diff --git a/InvenTree/locale/en/LC_MESSAGES/django.po b/InvenTree/locale/en/LC_MESSAGES/django.po index ab3c93408d..792cf22fc2 100644 --- a/InvenTree/locale/en/LC_MESSAGES/django.po +++ b/InvenTree/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" +"POT-Creation-Date: 2021-06-24 21:38+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -78,7 +78,7 @@ msgstr "" msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 +#: InvenTree/helpers.py:384 order/models.py:248 order/models.py:358 #: stock/views.py:1795 msgid "Invalid quantity provided" msgstr "" @@ -123,9 +123,9 @@ msgstr "" msgid "File comment" msgstr "" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:2022 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1179 msgid "User" msgstr "" @@ -133,34 +133,35 @@ msgstr "" msgid "upload date" msgstr "" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:107 InvenTree/models.py:108 company/models.py:396 +#: label/models.py:102 part/models.py:671 part/models.py:2163 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:235 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:972 msgid "Name" msgstr "" #: InvenTree/models.py:114 build/models.py:135 #: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: company/models.py:532 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 #: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: order/models.py:104 order/templates/order/purchase_order_detail.html:147 +#: part/models.py:695 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 +#: templates/js/build.js:833 templates/js/build.js:1101 #: templates/js/company.js:56 templates/js/order.js:183 #: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:984 +#: templates/js/stock.js:1029 msgid "Description" msgstr "" @@ -192,15 +193,15 @@ msgstr "" msgid "Turkish" msgstr "" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "" @@ -373,27 +374,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "" @@ -446,11 +447,11 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 order/forms.py:114 order/forms.py:149 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 +#: templates/js/build.js:880 templates/js/order.js:200 #: templates/js/order.js:298 msgid "Target Date" msgstr "" @@ -463,22 +464,21 @@ msgstr "" #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 +#: build/templates/build/detail.html:31 common/models.py:720 +#: company/forms.py:191 company/templates/company/supplier_part_pricing.html:77 +#: order/forms.py:193 order/forms.py:211 order/forms.py:246 order/forms.py:268 +#: order/forms.py:285 order/models.py:617 order/models.py:841 #: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/order_wizard/select_parts.html:34 #: order/templates/order/purchase_order_detail.html:179 #: order/templates/order/sales_order_detail.html:70 #: order/templates/order/sales_order_detail.html:77 #: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 +#: order/templates/order/sales_order_detail.html:234 part/forms.py:342 +#: part/forms.py:372 part/forms.py:388 part/forms.py:404 part/models.py:2293 +#: part/templates/part/internal_prices.html:98 +#: part/templates/part/order_prices.html:202 +#: part/templates/part/part_pricing.html:16 #: part/templates/part/sale_prices.html:85 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 @@ -487,9 +487,10 @@ msgstr "" #: stock/forms.py:175 stock/forms.py:308 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:571 +#: templates/js/build.js:1111 templates/js/order.js:393 +#: templates/js/part.js:796 templates/js/stock.js:1164 +#: templates/js/stock.js:1383 msgid "Quantity" msgstr "" @@ -501,7 +502,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:240 stock/forms.py:118 msgid "Serial Numbers" msgstr "" @@ -530,12 +531,12 @@ msgid "Mark build as complete" msgstr "" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:347 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:585 templates/js/order.js:378 +#: templates/js/stock.js:643 templates/js/stock.js:1056 msgid "Location" msgstr "" @@ -544,13 +545,13 @@ msgid "Location of completed parts" msgstr "" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:469 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:867 #: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: templates/js/stock.js:630 templates/js/stock.js:1133 +#: templates/js/stock.js:1399 msgid "Status" msgstr "" @@ -584,16 +585,16 @@ msgstr "" #: build/models.py:66 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "" #: build/models.py:67 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:57 +#: part/templates/part/navbar.html:60 templates/InvenTree/index.html:183 #: templates/InvenTree/search.html:185 #: templates/InvenTree/settings/tabs.html:34 users/models.py:43 msgid "Build Orders" @@ -603,12 +604,12 @@ msgstr "" msgid "Build Order Reference" msgstr "" -#: build/models.py:128 order/models.py:101 order/models.py:618 +#: build/models.py:128 order/models.py:102 order/models.py:619 #: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: order/templates/order/sales_order_detail.html:229 part/models.py:2302 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:660 templates/js/build.js:1105 msgid "Reference" msgstr "" @@ -627,27 +628,27 @@ msgstr "" #: build/models.py:153 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 +#: build/templates/build/detail.html:26 company/models.py:663 +#: order/models.py:661 order/models.py:717 +#: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:132 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:214 part/models.py:321 +#: part/models.py:1975 part/models.py:1987 part/models.py:2002 +#: part/models.py:2020 part/models.py:2095 part/models.py:2191 +#: part/models.py:2277 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:551 templates/js/build.js:838 +#: templates/js/build.js:1078 templates/js/company.js:140 +#: templates/js/company.js:339 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1371 msgid "Part" msgstr "" @@ -711,16 +712,16 @@ msgstr "" msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 +#: build/models.py:220 order/models.py:108 part/models.py:867 #: part/templates/part/detail.html:126 templates/js/order.js:293 msgid "Creation Date" msgstr "" -#: build/models.py:224 order/models.py:474 +#: build/models.py:224 order/models.py:475 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:228 order/models.py:221 templates/js/build.js:885 msgid "Completion Date" msgstr "" @@ -737,9 +738,9 @@ msgid "User who issued this build order" msgstr "" #: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/templates/build/detail.html:105 order/models.py:122 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:871 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "" @@ -758,26 +759,26 @@ msgstr "" msgid "External Link" msgstr "" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:258 part/models.py:729 stock/models.py:462 msgid "Link to external URL" msgstr "" #: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: company/models.py:132 company/models.py:539 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:126 +#: order/models.py:621 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:243 +#: order/templates/order/sales_order_detail.html:309 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:856 +#: part/templates/part/navbar.html:142 #: report/templates/report/inventree_build_order_base.html:173 #: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 #: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:699 msgid "Notes" msgstr "" @@ -810,11 +811,11 @@ msgstr "" msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1188 order/models.py:815 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1192 order/models.py:818 msgid "Allocation quantity must be greater than zero" msgstr "" @@ -828,7 +829,7 @@ msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" #: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: templates/InvenTree/search.html:183 templates/js/build.js:811 #: templates/navbar.html:29 msgid "Build" msgstr "" @@ -837,15 +838,13 @@ msgstr "" msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1333 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:928 +#: templates/js/order.js:366 templates/js/order.js:371 +#: templates/js/stock.js:1115 msgid "Stock Item" msgstr "" @@ -881,7 +880,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:743 msgid "Unallocate stock" msgstr "" @@ -918,15 +917,15 @@ msgstr "" #: order/templates/order/sales_order_detail.html:160 #: report/templates/report/inventree_test_report_base.html:75 #: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: templates/js/build.js:569 msgid "Serial Number" msgstr "" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:133 +#: part/templates/part/navbar.html:136 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "" @@ -1038,11 +1037,10 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:715 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 #: stock/templates/stock/item_base.html:279 templates/js/order.js:245 @@ -1186,7 +1184,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:85 order/models.py:678 +#: order/templates/order/purchase_order_detail.html:239 +#: order/templates/order/receive_parts.html:25 stock/forms.py:169 +#: stock/forms.py:375 msgid "Destination" msgstr "" @@ -1195,15 +1196,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1406 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:875 msgid "Created" msgstr "" @@ -1211,7 +1212,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:853 msgid "Completed" msgstr "" @@ -1249,9 +1250,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:17 +#: templates/js/stock.js:1044 msgid "Details" msgstr "" @@ -1286,8 +1287,8 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 +#: stock/templates/stock/item_base.html:497 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "" @@ -1412,8 +1413,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:670 +#: templates/js/build.js:935 templates/js/build.js:1118 msgid "Available" msgstr "" @@ -1599,8 +1600,8 @@ msgstr "" msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 +#: common/models.py:153 part/models.py:2193 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:259 templates/js/table_filters.js:25 #: templates/js/table_filters.js:315 msgid "Template" msgstr "" @@ -1609,7 +1610,7 @@ msgstr "" msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 +#: common/models.py:160 part/models.py:819 part/templates/part/detail.html:170 #: templates/js/table_filters.js:128 templates/js/table_filters.js:327 msgid "Assembly" msgstr "" @@ -1618,7 +1619,7 @@ msgstr "" msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 +#: common/models.py:167 part/models.py:825 part/templates/part/detail.html:180 #: templates/js/table_filters.js:331 msgid "Component" msgstr "" @@ -1627,7 +1628,7 @@ msgstr "" msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:174 part/models.py:836 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" @@ -1635,7 +1636,7 @@ msgstr "" msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 +#: common/models.py:181 part/models.py:841 part/templates/part/detail.html:210 #: templates/js/table_filters.js:339 msgid "Salable" msgstr "" @@ -1644,7 +1645,7 @@ msgstr "" msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 +#: common/models.py:188 part/models.py:831 part/templates/part/detail.html:190 #: templates/js/table_filters.js:33 templates/js/table_filters.js:343 msgid "Trackable" msgstr "" @@ -1653,7 +1654,7 @@ msgstr "" msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:195 part/models.py:851 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" @@ -1670,160 +1671,185 @@ msgstr "" msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" +#: common/models.py:209 +msgid "Show Price in Forms" msgstr "" #: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" +msgid "Display part price in some forms" msgstr "" #: common/models.py:216 -msgid "Page Size" +msgid "Internal Prices" msgstr "" #: common/models.py:217 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:223 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:224 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:230 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:231 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:237 +msgid "Page Size" +msgstr "" + +#: common/models.py:238 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:248 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:249 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:255 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:256 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:262 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:263 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:269 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:270 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:272 part/templates/part/detail.html:121 msgid "days" msgstr "" -#: common/models.py:256 +#: common/models.py:277 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:278 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:284 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:285 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:291 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:292 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:298 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:299 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:305 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:306 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:311 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:312 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:316 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:317 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:322 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:323 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:546 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:548 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:583 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:606 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:617 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:640 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:721 company/forms.py:192 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 +#: common/models.py:729 company/templates/company/supplier_part_pricing.html:82 +#: part/templates/part/internal_prices.html:103 #: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:730 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:822 msgid "Default" msgstr "" @@ -1844,7 +1870,9 @@ msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:582 +#: part/templates/part/bom_upload/upload_file.html:27 msgid "Upload File" msgstr "" @@ -1878,29 +1906,29 @@ msgstr "" msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:133 templates/js/part.js:787 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:135 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:143 company/models.py:321 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:149 company/models.py:328 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:151 company/models.py:327 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 #: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:408 msgid "MPN" msgstr "" @@ -1953,11 +1981,11 @@ msgstr "" msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:121 company/models.py:333 company/models.py:526 +#: order/models.py:106 part/models.py:728 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:188 templates/js/company.js:419 +#: templates/js/part.js:498 msgid "Link" msgstr "" @@ -1965,7 +1993,7 @@ msgstr "" msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:129 part/models.py:738 msgid "Image" msgstr "" @@ -1993,12 +2021,12 @@ msgstr "" msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:305 company/models.py:497 stock/models.py:407 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:309 company/models.py:501 order/views.py:1597 msgid "Select part" msgstr "" @@ -2009,7 +2037,7 @@ msgstr "" #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 #: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:390 msgid "Manufacturer" msgstr "" @@ -2021,87 +2049,112 @@ msgstr "" msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:390 company/models.py:520 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:397 +msgid "Parameter name" +msgstr "" + +#: company/models.py:403 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:241 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:404 +msgid "Parameter value" +msgstr "" + +#: company/models.py:410 part/models.py:813 part/models.py:2165 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:247 +msgid "Units" +msgstr "" + +#: company/models.py:411 +msgid "Parameter units" +msgstr "" + +#: company/models.py:507 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:193 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:48 templates/js/company.js:364 #: templates/js/order.js:170 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:508 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:513 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 #: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:514 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:521 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:527 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:533 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:538 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2305 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 +#: company/models.py:544 company/templates/company/supplier_part_base.html:109 #: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: templates/js/stock.js:695 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:544 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:546 part/models.py:1608 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:546 msgid "Order multiple" msgstr "" #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:562 msgid "Assigned Stock" msgstr "" @@ -2167,11 +2220,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 +#: company/templates/company/detail.html:67 order/models.py:464 #: order/templates/order/sales_order_base.html:94 stock/models.py:449 #: stock/models.py:450 stock/templates/stock/item_base.html:262 #: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: templates/js/stock.js:1097 msgid "Customer" msgstr "" @@ -2217,7 +2270,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:66 #: company/templates/company/detail_supplier_part.html:66 #: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: templates/js/stock.js:1312 msgid "New Part" msgstr "" @@ -2250,13 +2303,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 +#: order/templates/order/order_wizard/select_parts.html:44 #: order/templates/order/purchase_order_detail.html:50 msgid "Create new supplier part" msgstr "" @@ -2264,12 +2316,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 #: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/supplier.html:17 templates/js/stock.js:1318 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 +#: company/templates/company/manufacturer_part_suppliers.html:82 #: company/views.py:64 order/templates/order/purchase_orders.html:185 #: part/templates/part/supplier.html:50 msgid "New Supplier" @@ -2321,8 +2373,9 @@ msgid "There are %(count)s suppliers defined for this manufacturer part. If you msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:63 part/templates/part/navbar.html:86 +#: part/templates/part/navbar.html:89 templates/InvenTree/search.html:316 #: templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2334,13 +2387,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:38 stock/api.py:54 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2362,11 +2415,25 @@ msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:1002 users/models.py:191 msgid "Delete" msgstr "" -#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:34 +#: part/templates/part/category_navbar.html:37 +#: part/templates/part/navbar.html:24 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:48 +msgid "New Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:83 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" @@ -2381,13 +2448,13 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:35 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 +#: templates/InvenTree/search.html:198 templates/js/stock.js:996 #: templates/stats.html:93 templates/stats.html:102 users/models.py:42 msgid "Stock Items" msgstr "" @@ -2398,7 +2465,7 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 +#: part/templates/part/navbar.html:112 part/templates/part/navbar.html:115 #: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 @@ -2410,7 +2477,7 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 +#: part/templates/part/navbar.html:92 part/templates/part/navbar.html:95 #: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 @@ -2444,7 +2511,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:7 #: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:380 msgid "Supplier Part" msgstr "" @@ -2492,8 +2559,8 @@ msgstr "" msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 company/views.py:855 +#: part/templates/part/sale_prices.html:17 part/views.py:2751 msgid "Add Price Break" msgstr "" @@ -2512,8 +2579,8 @@ msgstr "" msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 +#: company/views.py:70 part/templates/part/navbar.html:80 +#: part/templates/part/navbar.html:83 templates/InvenTree/search.html:306 #: templates/navbar.html:36 msgid "Manufacturers" msgstr "" @@ -2535,20 +2602,20 @@ msgstr "" msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:169 part/views.py:948 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:198 part/views.py:980 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:205 part/views.py:987 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:214 part/views.py:996 msgid "Supplied URL is not a valid image file" msgstr "" @@ -2596,27 +2663,35 @@ msgstr "" msgid "Delete Manufacturer Part" msgstr "" -#: company/views.py:528 +#: company/views.py:514 +msgid "Add Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:548 +msgid "Edit Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:588 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:639 templates/js/stock.js:1319 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:783 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 +#: company/views.py:860 part/views.py:2755 msgid "Added new price break" msgstr "" -#: company/views.py:855 part/views.py:2781 +#: company/views.py:916 part/views.py:2799 msgid "Edit Price Break" msgstr "" -#: company/views.py:870 part/views.py:2795 +#: company/views.py:931 part/views.py:2813 msgid "Delete Price Break" msgstr "" @@ -2640,7 +2715,7 @@ msgstr "" msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:124 report/models.py:297 msgid "Enabled" msgstr "" @@ -2664,7 +2739,7 @@ msgstr "" msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:144 report/models.py:290 msgid "Filename Pattern" msgstr "" @@ -2676,8 +2751,8 @@ msgstr "" msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:245 label/models.py:298 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" @@ -2698,237 +2773,239 @@ msgstr "" msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:86 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 +#: order/forms.py:108 msgid "Purchase Order reference" msgstr "" -#: order/forms.py:110 +#: order/forms.py:115 msgid "Target date for order delivery. Order will be overdue after this date." msgstr "" -#: order/forms.py:138 +#: order/forms.py:143 msgid "Enter sales order number" msgstr "" -#: order/forms.py:145 order/models.py:475 +#: order/forms.py:150 order/models.py:476 msgid "Target date for order completion. Order will be overdue after this date." msgstr "" -#: order/forms.py:236 +#: order/forms.py:242 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:248 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 +#: order/models.py:102 msgid "Order reference" msgstr "" -#: order/models.py:103 +#: order/models.py:104 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:106 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:114 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:121 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:126 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:185 order/models.py:469 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:194 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 +#: order/models.py:197 order/templates/order/order_base.html:98 #: templates/js/order.js:179 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:197 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:204 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:209 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:210 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:215 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:216 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:222 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 +#: order/models.py:246 part/views.py:1686 stock/models.py:304 #: stock/models.py:1020 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:251 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:349 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:353 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:355 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:465 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:479 templates/js/order.js:303 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:486 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:530 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:617 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:619 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:621 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:647 order/models.py:715 templates/js/order.js:353 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:648 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 #: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: templates/js/stock.js:669 templates/js/stock.js:1078 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:662 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 +#: order/models.py:665 order/templates/order/order_base.html:131 #: order/templates/order/purchase_order_detail.html:219 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:665 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:672 stock/models.py:542 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:690 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:673 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:681 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:724 part/templates/part/navbar.html:109 +#: part/templates/part/order_prices.html:107 +#: part/templates/part/part_pricing.html:97 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:725 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:800 order/models.py:802 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:806 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:808 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:811 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:821 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:826 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:837 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:838 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:841 msgid "Enter stock allocation quantity" msgstr "" @@ -2957,7 +3034,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2979,8 +3056,8 @@ msgstr "" #: order/templates/order/order_base.html:180 #: order/templates/order/purchase_order_detail.html:100 #: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: stock/templates/stock/location.html:191 templates/js/stock.js:736 +#: templates/js/stock.js:1324 msgid "New Location" msgstr "" @@ -3083,28 +3160,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3137,15 +3218,20 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +#: order/templates/order/so_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3155,8 +3241,8 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/sales_order_detail.html:22 order/views.py:1321 +#: order/views.py:1404 msgid "Add Line Item" msgstr "" @@ -3164,25 +3250,31 @@ msgstr "" msgid "No line items found" msgstr "" +#: order/templates/order/purchase_order_detail.html:142 +#: order/templates/order/sales_order_detail.html:223 +msgid "Total" +msgstr "" + #: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/sales_order_detail.html:246 msgid "Unit Price" msgstr "" #: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/sales_order_detail.html:253 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:255 +#: order/templates/order/sales_order_detail.html:359 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:256 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:261 msgid "Receive line item" msgstr "" @@ -3203,7 +3295,7 @@ msgstr "" #: part/templates/part/category_navbar.html:29 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 #: users/models.py:40 msgid "Parts" @@ -3218,7 +3310,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3226,11 +3318,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3267,17 +3359,17 @@ msgid "Sales Order Items" msgstr "" #: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: templates/js/build.js:724 templates/js/build.js:1141 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:610 +#: templates/js/build.js:946 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:612 +#: templates/js/build.js:947 msgid "Delete stock allocation" msgstr "" @@ -3285,50 +3377,50 @@ msgstr "" msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:206 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:274 templates/js/build.js:675 +#: templates/js/build.js:942 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:276 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:313 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:343 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:346 templates/js/build.js:738 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:349 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:353 templates/js/build.js:731 +#: templates/js/build.js:1149 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:356 +#: order/templates/order/sales_order_detail.html:465 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:360 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:471 msgid "Update Unit Price" msgstr "" @@ -3369,10 +3461,6 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - #: order/views.py:104 msgid "Add Purchase Order Attachment" msgstr "" @@ -3473,90 +3561,94 @@ msgstr "" msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:1012 +msgid "Update prices" +msgstr "" + +#: order/views.py:1270 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 +#: order/views.py:1330 msgid "Supplier part must be specified" msgstr "" -#: order/views.py:1326 +#: order/views.py:1336 msgid "Supplier must match for Part and Order" msgstr "" -#: order/views.py:1457 order/views.py:1475 +#: order/views.py:1467 order/views.py:1485 msgid "Edit Line Item" msgstr "" -#: order/views.py:1491 order/views.py:1503 +#: order/views.py:1501 order/views.py:1513 msgid "Delete Line Item" msgstr "" -#: order/views.py:1496 order/views.py:1508 +#: order/views.py:1506 order/views.py:1518 msgid "Deleted line item" msgstr "" -#: order/views.py:1521 +#: order/views.py:1531 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1576 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1592 msgid "Select line item" msgstr "" -#: order/views.py:1613 -#, python-brace-format -msgid "No matching item for serial {serial}" -msgstr "" - #: order/views.py:1623 #, python-brace-format +msgid "No matching item for serial {serial}" +msgstr "" + +#: order/views.py:1633 +#, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1641 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1695 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1769 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1784 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1856 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1862 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1865 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1870 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 +#: part/bom.py:138 part/models.py:72 part/models.py:747 #: part/templates/part/category.html:66 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3634,7 +3726,7 @@ msgstr "" msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:122 part/models.py:2191 msgid "Parent Part" msgstr "" @@ -3710,7 +3802,7 @@ msgstr "" msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:344 part/models.py:2286 msgid "Sub part" msgstr "" @@ -3730,7 +3822,7 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:82 part/models.py:2237 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" @@ -3741,365 +3833,360 @@ msgstr "" msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:448 part/models.py:460 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:557 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:561 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:566 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:645 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:670 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:677 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:678 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:689 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:690 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:696 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:701 part/templates/part/category.html:73 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:702 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:709 part/models.py:2236 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:710 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:715 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "" -#: part/models.py:731 +#: part/models.py:716 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:722 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:723 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:745 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:792 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:793 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:800 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:801 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:806 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:807 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:814 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:820 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:826 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:832 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:837 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:842 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:846 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 #: templates/js/table_filters.js:241 templates/js/table_filters.js:310 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:847 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:852 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:857 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:863 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:865 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:869 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1608 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2063 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2080 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2100 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2101 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2106 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2107 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 +#: part/models.py:2112 templates/js/part.js:726 #: templates/js/table_filters.js:227 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2113 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2118 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2119 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2124 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2125 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2158 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2163 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2165 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2193 part/models.py:2242 part/models.py:2243 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2247 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2248 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2278 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2287 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2293 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2295 templates/js/bom.js:216 templates/js/bom.js:285 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2295 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2298 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2299 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2302 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2305 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2311 templates/js/bom.js:302 templates/js/bom.js:309 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2312 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2317 templates/js/bom.js:294 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2318 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 +#: part/models.py:2394 part/views.py:1692 part/views.py:1744 #: stock/models.py:294 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2403 part/models.py:2405 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2408 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2527 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2563 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 @@ -4114,8 +4201,8 @@ msgstr "" msgid "Deleting this entry will remove the BOM row from the following part" msgstr "" -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:50 +#: part/templates/part/navbar.html:53 msgid "Bill of Materials" msgstr "" @@ -4162,7 +4249,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:1987 msgid "Export Bill of Materials" msgstr "" @@ -4179,7 +4266,7 @@ msgid "All selected BOM items will be deleted" msgstr "" #: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: templates/js/stock.js:1313 msgid "Create New Part" msgstr "" @@ -4260,7 +4347,7 @@ msgstr "" msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:29 part/views.py:2397 msgid "Create new part category" msgstr "" @@ -4320,7 +4407,7 @@ msgid "View grid display" msgstr "" #: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: stock/templates/stock/location.html:192 templates/js/stock.js:737 msgid "Create new location" msgstr "" @@ -4375,14 +4462,8 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 -#: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" -msgstr "" - #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:21 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" @@ -4410,7 +4491,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:13 msgid "Part Details" msgstr "" @@ -4490,6 +4571,36 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/internal_prices.html:11 +#: part/templates/part/navbar.html:100 +msgid "Internal Price Information" +msgstr "" + +#: part/templates/part/internal_prices.html:19 part/views.py:2822 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/internal_prices.html:28 templates/403.html:5 +#: templates/403.html:11 +msgid "Permission Denied" +msgstr "" + +#: part/templates/part/internal_prices.html:31 templates/403.html:14 +msgid "You do not have permission to view this page." +msgstr "" + +#: part/templates/part/internal_prices.html:59 +msgid "No internal price break information found" +msgstr "" + +#: part/templates/part/internal_prices.html:110 +msgid "Edit internal price break" +msgstr "" + +#: part/templates/part/internal_prices.html:111 +msgid "Delete internal price break" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4503,127 +4614,141 @@ msgstr "" msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:28 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:31 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:42 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:45 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:66 part/templates/part/navbar.html:69 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 +#: part/templates/part/navbar.html:74 part/templates/part/order_prices.html:12 msgid "Order Price Information" msgstr "" -#: part/templates/part/navbar.html:75 +#: part/templates/part/navbar.html:77 msgid "Order Price" msgstr "" -#: part/templates/part/navbar.html:98 +#: part/templates/part/navbar.html:103 part/templates/part/order_prices.html:93 +#: part/templates/part/part_pricing.html:82 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/navbar.html:106 msgid "Sales Price Information" msgstr "" -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:120 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:123 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:127 part/templates/part/navbar.html:130 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:139 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 +#: part/templates/part/order_prices.html:24 +#: part/templates/part/part_base.html:282 +msgid "Calculate" +msgstr "" + +#: part/templates/part/order_prices.html:31 msgid "Pricing ranges" msgstr "" -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 +#: part/templates/part/order_prices.html:36 +#: part/templates/part/part_pricing.html:22 msgid "Supplier Pricing" msgstr "" -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 +#: part/templates/part/order_prices.html:37 +#: part/templates/part/order_prices.html:62 +#: part/templates/part/order_prices.html:94 +#: part/templates/part/order_prices.html:108 +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 msgid "Unit Cost" msgstr "" -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 +#: part/templates/part/order_prices.html:44 +#: part/templates/part/order_prices.html:69 +#: part/templates/part/order_prices.html:99 +#: part/templates/part/order_prices.html:113 +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 msgid "Total Cost" msgstr "" -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 +#: part/templates/part/order_prices.html:52 +#: part/templates/part/part_pricing.html:40 msgid "No supplier pricing available" msgstr "" -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 +#: part/templates/part/order_prices.html:61 +#: part/templates/part/order_prices.html:128 +#: part/templates/part/part_pricing.html:48 msgid "BOM Pricing" msgstr "" -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 +#: part/templates/part/order_prices.html:77 +#: part/templates/part/part_pricing.html:66 msgid "Note: BOM pricing is incomplete for this part" msgstr "" -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 +#: part/templates/part/order_prices.html:84 +#: part/templates/part/part_pricing.html:73 msgid "No BOM pricing available" msgstr "" -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 +#: part/templates/part/order_prices.html:122 +#: part/templates/part/part_pricing.html:113 msgid "No pricing information is available for this part." msgstr "" -#: part/templates/part/order_prices.html:113 +#: part/templates/part/order_prices.html:138 msgid "Stock Pricing" msgstr "" -#: part/templates/part/order_prices.html:121 +#: part/templates/part/order_prices.html:146 msgid "No stock pricing history is available for this part." msgstr "" -#: part/templates/part/order_prices.html:140 +#: part/templates/part/order_prices.html:165 #, python-format msgid "Single Price - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:152 +#: part/templates/part/order_prices.html:177 #, python-format msgid "Single Price Difference - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:163 +#: part/templates/part/order_prices.html:189 #, python-format msgid "Part Single Price - %(currency)s" msgstr "" @@ -4632,19 +4757,6 @@ msgstr "" msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4662,7 +4774,7 @@ msgid "Part List" msgstr "" #: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: templates/js/company.js:355 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4742,14 +4854,10 @@ msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 -msgid "Calculate" -msgstr "" - #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" @@ -4818,7 +4926,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4855,7 +4963,7 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" @@ -4924,227 +5032,239 @@ msgstr "" msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:925 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 +#: part/views.py:1027 msgid "Upload Part Image" msgstr "" -#: part/views.py:1022 part/views.py:1057 +#: part/views.py:1033 part/views.py:1068 msgid "Updated part image" msgstr "" -#: part/views.py:1031 +#: part/views.py:1042 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1071 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1082 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1117 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1147 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1168 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1189 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1200 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1334 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1695 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1720 part/views.py:1723 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1729 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1767 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1773 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1777 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2039 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2046 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2055 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2196 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2206 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2213 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2221 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2271 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2285 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 +#: part/views.py:2345 msgid "Edit Part Category" msgstr "" -#: part/views.py:2365 +#: part/views.py:2383 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2389 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2441 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2542 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2598 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2617 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2687 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 +#: part/views.py:2743 msgid "Confim BOM item deletion" msgstr "" -#: report/models.py:180 +#: part/views.py:2831 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2839 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5176,7 +5296,7 @@ msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:195 templates/js/stock.js:1012 msgid "Date" msgstr "" @@ -5199,7 +5319,7 @@ msgid "Moved {n} parts to {loc}" msgstr "" #: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" @@ -5485,12 +5605,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5620,7 +5740,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:593 msgid "No location set" msgstr "" @@ -5632,25 +5752,29 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" @@ -5947,7 +6071,7 @@ msgstr "" msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:1001 users/models.py:187 msgid "Add" msgstr "" @@ -6013,7 +6137,7 @@ msgstr "" msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1575 templates/js/build.js:326 msgid "Create new Stock Item" msgstr "" @@ -6045,14 +6169,6 @@ msgstr "" msgid "Add Stock Tracking Entry" msgstr "" -#: templates/403.html:5 templates/403.html:11 -msgid "Permission Denied" -msgstr "" - -#: templates/403.html:14 -msgid "You do not have permission to view this page." -msgstr "" - #: templates/404.html:5 templates/404.html:11 msgid "Page Not Found" msgstr "" @@ -6121,11 +6237,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6171,12 +6287,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:85 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:86 msgid "Delete Template" msgstr "" @@ -6224,11 +6340,11 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 +#: templates/InvenTree/settings/part.html:44 msgid "Part Parameter Templates" msgstr "" -#: templates/InvenTree/settings/part.html:61 +#: templates/InvenTree/settings/part.html:65 msgid "No part parameter templates found" msgstr "" @@ -6344,47 +6460,51 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 +#: templates/about.html:100 templates/js/modals.js:568 +#: templates/js/modals.js:861 templates/modals.html:29 templates/modals.html:54 #: templates/modals.html:97 msgid "Close" msgstr "" @@ -6445,7 +6565,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:921 msgid "Invalid server response" msgstr "" @@ -6509,7 +6629,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1091 msgid "Open subassembly" msgstr "" @@ -6545,7 +6665,7 @@ msgstr "" msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:470 templates/js/build.js:423 templates/js/build.js:1189 msgid "No BOM items found" msgstr "" @@ -6565,37 +6685,45 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:382 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:325 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:644 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:665 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:735 templates/js/build.js:1153 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:788 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:805 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:966 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:825 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:924 msgid "No parts allocated for" msgstr "" @@ -6615,17 +6743,29 @@ msgstr "" msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:148 templates/js/company.js:347 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:152 templates/js/company.js:351 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:226 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:262 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:263 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:328 msgid "No supplier parts found" msgstr "" @@ -6713,76 +6853,76 @@ msgstr "" msgid "Loading Data" msgstr "" -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:567 templates/js/modals.js:860 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:824 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:921 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 +#: templates/js/modals.js:931 msgid "No Response" msgstr "" -#: templates/js/modals.js:912 +#: templates/js/modals.js:932 msgid "No response from the InvenTree server" msgstr "" -#: templates/js/modals.js:916 +#: templates/js/modals.js:936 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:937 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 +#: templates/js/modals.js:941 msgid "Error 401: Not Authenticated" msgstr "" -#: templates/js/modals.js:922 +#: templates/js/modals.js:942 msgid "Authentication credentials not supplied" msgstr "" -#: templates/js/modals.js:926 +#: templates/js/modals.js:946 msgid "Error 403: Permission Denied" msgstr "" -#: templates/js/modals.js:927 +#: templates/js/modals.js:947 msgid "You do not have the required permissions to access this function" msgstr "" -#: templates/js/modals.js:931 +#: templates/js/modals.js:951 msgid "Error 404: Resource Not Found" msgstr "" -#: templates/js/modals.js:932 +#: templates/js/modals.js:952 msgid "The requested resource could not be located on the server" msgstr "" -#: templates/js/modals.js:936 +#: templates/js/modals.js:956 msgid "Error 408: Timeout" msgstr "" -#: templates/js/modals.js:937 +#: templates/js/modals.js:957 msgid "Connection timeout while requesting data from server" msgstr "" -#: templates/js/modals.js:940 +#: templates/js/modals.js:960 msgid "Error requesting form data" msgstr "" @@ -6798,6 +6938,10 @@ msgstr "" msgid "No sales orders found" msgstr "" +#: templates/js/order.js:343 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6826,39 +6970,39 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:323 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:990 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:806 msgid "Single Price Difference" msgstr "" @@ -6956,155 +7100,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:853 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:868 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:882 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:883 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1022 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1069 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1088 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1107 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1125 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1148 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1156 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1188 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1200 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1201 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1325 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1366 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1389 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1417 msgid "Uninstall Stock Item" msgstr "" @@ -7270,56 +7414,56 @@ msgstr "" msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" @@ -7563,34 +7707,34 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:174 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:182 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:187 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:191 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/es/LC_MESSAGES/django.po b/InvenTree/locale/es/LC_MESSAGES/django.po index 6d0f3375c4..1bbb282835 100644 --- a/InvenTree/locale/es/LC_MESSAGES/django.po +++ b/InvenTree/locale/es/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:40\n" +"POT-Creation-Date: 2021-06-24 21:38+0000\n" +"PO-Revision-Date: 2021-06-25 14:06\n" "Last-Translator: \n" "Language-Team: Spanish\n" "Language: es_ES\n" @@ -19,19 +19,19 @@ msgstr "" #: InvenTree/api.py:64 msgid "API endpoint not found" -msgstr "" +msgstr "endpoint API no encontrado" #: InvenTree/api.py:110 msgid "No action specified" -msgstr "" +msgstr "No se especificó ninguna acción" #: InvenTree/api.py:124 msgid "No matching action found" -msgstr "" +msgstr "No se encontró ninguna acción coincidente" #: InvenTree/fields.py:44 msgid "Enter date" -msgstr "" +msgstr "Ingrese la fecha" #: InvenTree/forms.py:112 build/forms.py:102 build/forms.py:123 #: build/forms.py:145 build/forms.py:169 build/forms.py:185 build/forms.py:227 @@ -42,19 +42,19 @@ msgstr "Confirmar" #: InvenTree/forms.py:128 msgid "Confirm delete" -msgstr "" +msgstr "Confirmar eliminación" #: InvenTree/forms.py:129 msgid "Confirm item deletion" -msgstr "" +msgstr "Confirmar borrado de artículo" #: InvenTree/forms.py:161 templates/registration/login.html:76 msgid "Enter password" -msgstr "" +msgstr "Introduzca contraseña" #: InvenTree/forms.py:162 msgid "Enter new password" -msgstr "" +msgstr "Ingrese su nueva contraseña" #: InvenTree/forms.py:169 msgid "Confirm password" @@ -66,21 +66,21 @@ msgstr "Confirmar contraseña nueva" #: InvenTree/forms.py:205 msgid "Apply Theme" -msgstr "" +msgstr "Aplicar tema" #: InvenTree/forms.py:235 msgid "Select Category" -msgstr "" +msgstr "Seleccionar Categoría" #: InvenTree/helpers.py:377 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 +#: InvenTree/helpers.py:384 order/models.py:248 order/models.py:358 #: stock/views.py:1795 msgid "Invalid quantity provided" -msgstr "" +msgstr "Cantidad proporcionada no válida" #: InvenTree/helpers.py:387 msgid "Empty serial number string" @@ -90,7 +90,7 @@ msgstr "" #: InvenTree/helpers.py:440 #, python-brace-format msgid "Invalid group: {g}" -msgstr "" +msgstr "Grupo no válido: un {g}" #: InvenTree/helpers.py:445 #, python-brace-format @@ -99,7 +99,7 @@ msgstr "" #: InvenTree/helpers.py:453 msgid "No serial numbers found" -msgstr "" +msgstr "Numeros de serie no encontrados" #: InvenTree/helpers.py:457 #, python-brace-format @@ -122,9 +122,9 @@ msgstr "Comentario" msgid "File comment" msgstr "" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:2022 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1179 msgid "User" msgstr "Usuario" @@ -132,34 +132,35 @@ msgstr "Usuario" msgid "upload date" msgstr "" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:107 InvenTree/models.py:108 company/models.py:396 +#: label/models.py:102 part/models.py:671 part/models.py:2163 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:235 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:972 msgid "Name" msgstr "Nombre" #: InvenTree/models.py:114 build/models.py:135 #: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: company/models.py:532 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 #: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: order/models.py:104 order/templates/order/purchase_order_detail.html:147 +#: part/models.py:695 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 +#: templates/js/build.js:833 templates/js/build.js:1101 #: templates/js/company.js:56 templates/js/order.js:183 #: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:984 +#: templates/js/stock.js:1029 msgid "Description" msgstr "Descripción" @@ -191,26 +192,26 @@ msgstr "Polaco" msgid "Turkish" msgstr "Turco" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "" #: InvenTree/status_codes.py:104 InvenTree/status_codes.py:145 #: InvenTree/status_codes.py:314 msgid "Pending" -msgstr "" +msgstr "Pendiente" #: InvenTree/status_codes.py:105 msgid "Placed" -msgstr "" +msgstr "Colocado" #: InvenTree/status_codes.py:106 InvenTree/status_codes.py:317 msgid "Complete" @@ -234,7 +235,7 @@ msgstr "" #: InvenTree/status_codes.py:146 #: order/templates/order/sales_order_base.html:126 msgid "Shipped" -msgstr "" +msgstr "Enviado" #: InvenTree/status_codes.py:186 msgid "OK" @@ -254,7 +255,7 @@ msgstr "Destruido" #: InvenTree/status_codes.py:191 msgid "Rejected" -msgstr "" +msgstr "Rechazado" #: InvenTree/status_codes.py:272 msgid "Legacy stock tracking entry" @@ -262,31 +263,31 @@ msgstr "" #: InvenTree/status_codes.py:274 msgid "Stock item created" -msgstr "" +msgstr "Artículo de stock creado" #: InvenTree/status_codes.py:276 msgid "Edited stock item" -msgstr "" +msgstr "Elemento de stock editado" #: InvenTree/status_codes.py:277 msgid "Assigned serial number" -msgstr "" +msgstr "Número de serie asignado" #: InvenTree/status_codes.py:279 msgid "Stock counted" -msgstr "" +msgstr "Stock contado" #: InvenTree/status_codes.py:280 msgid "Stock manually added" -msgstr "" +msgstr "Stock añadido manualmente" #: InvenTree/status_codes.py:281 msgid "Stock manually removed" -msgstr "" +msgstr "Stock eliminado manualmente" #: InvenTree/status_codes.py:283 msgid "Location changed" -msgstr "" +msgstr "Ubicación cambiada" #: InvenTree/status_codes.py:285 msgid "Installed into assembly" @@ -326,11 +327,11 @@ msgstr "" #: InvenTree/status_codes.py:298 msgid "Build order output completed" -msgstr "" +msgstr "Construir orden de salida completado" #: InvenTree/status_codes.py:300 msgid "Received against purchase order" -msgstr "" +msgstr "Recibido contra la orden de compra" #: InvenTree/status_codes.py:315 msgid "Production" @@ -372,27 +373,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "Eliminar elemento" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "Configurar Contraseña" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "Información del sistema" @@ -445,11 +446,11 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 order/forms.py:114 order/forms.py:149 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 +#: templates/js/build.js:880 templates/js/order.js:200 #: templates/js/order.js:298 msgid "Target Date" msgstr "" @@ -462,22 +463,21 @@ msgstr "" #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 +#: build/templates/build/detail.html:31 common/models.py:720 +#: company/forms.py:191 company/templates/company/supplier_part_pricing.html:77 +#: order/forms.py:193 order/forms.py:211 order/forms.py:246 order/forms.py:268 +#: order/forms.py:285 order/models.py:617 order/models.py:841 #: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/order_wizard/select_parts.html:34 #: order/templates/order/purchase_order_detail.html:179 #: order/templates/order/sales_order_detail.html:70 #: order/templates/order/sales_order_detail.html:77 #: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 +#: order/templates/order/sales_order_detail.html:234 part/forms.py:342 +#: part/forms.py:372 part/forms.py:388 part/forms.py:404 part/models.py:2293 +#: part/templates/part/internal_prices.html:98 +#: part/templates/part/order_prices.html:202 +#: part/templates/part/part_pricing.html:16 #: part/templates/part/sale_prices.html:85 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 @@ -486,9 +486,10 @@ msgstr "" #: stock/forms.py:175 stock/forms.py:308 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:571 +#: templates/js/build.js:1111 templates/js/order.js:393 +#: templates/js/part.js:796 templates/js/stock.js:1164 +#: templates/js/stock.js:1383 msgid "Quantity" msgstr "Cantidad" @@ -500,7 +501,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:240 stock/forms.py:118 msgid "Serial Numbers" msgstr "Números de serie" @@ -529,12 +530,12 @@ msgid "Mark build as complete" msgstr "" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:347 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:585 templates/js/order.js:378 +#: templates/js/stock.js:643 templates/js/stock.js:1056 msgid "Location" msgstr "Unicación" @@ -543,13 +544,13 @@ msgid "Location of completed parts" msgstr "" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:469 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:867 #: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: templates/js/stock.js:630 templates/js/stock.js:1133 +#: templates/js/stock.js:1399 msgid "Status" msgstr "Estado" @@ -583,16 +584,16 @@ msgstr "" #: build/models.py:66 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "" #: build/models.py:67 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:57 +#: part/templates/part/navbar.html:60 templates/InvenTree/index.html:183 #: templates/InvenTree/search.html:185 #: templates/InvenTree/settings/tabs.html:34 users/models.py:43 msgid "Build Orders" @@ -602,12 +603,12 @@ msgstr "" msgid "Build Order Reference" msgstr "" -#: build/models.py:128 order/models.py:101 order/models.py:618 +#: build/models.py:128 order/models.py:102 order/models.py:619 #: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: order/templates/order/sales_order_detail.html:229 part/models.py:2302 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:660 templates/js/build.js:1105 msgid "Reference" msgstr "Referencia" @@ -626,27 +627,27 @@ msgstr "" #: build/models.py:153 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 +#: build/templates/build/detail.html:26 company/models.py:663 +#: order/models.py:661 order/models.py:717 +#: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:132 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:214 part/models.py:321 +#: part/models.py:1975 part/models.py:1987 part/models.py:2002 +#: part/models.py:2020 part/models.py:2095 part/models.py:2191 +#: part/models.py:2277 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:551 templates/js/build.js:838 +#: templates/js/build.js:1078 templates/js/company.js:140 +#: templates/js/company.js:339 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1371 msgid "Part" msgstr "Parte" @@ -710,16 +711,16 @@ msgstr "" msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 +#: build/models.py:220 order/models.py:108 part/models.py:867 #: part/templates/part/detail.html:126 templates/js/order.js:293 msgid "Creation Date" msgstr "" -#: build/models.py:224 order/models.py:474 +#: build/models.py:224 order/models.py:475 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:228 order/models.py:221 templates/js/build.js:885 msgid "Completion Date" msgstr "" @@ -736,9 +737,9 @@ msgid "User who issued this build order" msgstr "" #: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/templates/build/detail.html:105 order/models.py:122 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:871 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "Responsable" @@ -757,26 +758,26 @@ msgstr "" msgid "External Link" msgstr "" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:258 part/models.py:729 stock/models.py:462 msgid "Link to external URL" msgstr "" #: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: company/models.py:132 company/models.py:539 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:126 +#: order/models.py:621 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:243 +#: order/templates/order/sales_order_detail.html:309 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:856 +#: part/templates/part/navbar.html:142 #: report/templates/report/inventree_build_order_base.html:173 #: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 #: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:699 msgid "Notes" msgstr "Notas" @@ -809,11 +810,11 @@ msgstr "" msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1188 order/models.py:815 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1192 order/models.py:818 msgid "Allocation quantity must be greater than zero" msgstr "" @@ -827,7 +828,7 @@ msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" #: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: templates/InvenTree/search.html:183 templates/js/build.js:811 #: templates/navbar.html:29 msgid "Build" msgstr "" @@ -836,15 +837,13 @@ msgstr "" msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1333 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:928 +#: templates/js/order.js:366 templates/js/order.js:371 +#: templates/js/stock.js:1115 msgid "Stock Item" msgstr "" @@ -880,7 +879,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:743 msgid "Unallocate stock" msgstr "" @@ -917,15 +916,15 @@ msgstr "" #: order/templates/order/sales_order_detail.html:160 #: report/templates/report/inventree_test_report_base.html:75 #: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: templates/js/build.js:569 msgid "Serial Number" msgstr "Número de serie" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:133 +#: part/templates/part/navbar.html:136 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "" @@ -1037,11 +1036,10 @@ msgid "Progress" msgstr "Progreso" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:715 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 #: stock/templates/stock/item_base.html:279 templates/js/order.js:245 @@ -1185,7 +1183,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:85 order/models.py:678 +#: order/templates/order/purchase_order_detail.html:239 +#: order/templates/order/receive_parts.html:25 stock/forms.py:169 +#: stock/forms.py:375 msgid "Destination" msgstr "Destinación" @@ -1194,15 +1195,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1406 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "Lote" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:875 msgid "Created" msgstr "" @@ -1210,7 +1211,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:853 msgid "Completed" msgstr "Completados" @@ -1248,9 +1249,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:17 +#: templates/js/stock.js:1044 msgid "Details" msgstr "Detalles" @@ -1285,8 +1286,8 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 +#: stock/templates/stock/item_base.html:497 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "Guardar" @@ -1411,8 +1412,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:670 +#: templates/js/build.js:935 templates/js/build.js:1118 msgid "Available" msgstr "" @@ -1598,8 +1599,8 @@ msgstr "" msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 +#: common/models.py:153 part/models.py:2193 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:259 templates/js/table_filters.js:25 #: templates/js/table_filters.js:315 msgid "Template" msgstr "" @@ -1608,7 +1609,7 @@ msgstr "" msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 +#: common/models.py:160 part/models.py:819 part/templates/part/detail.html:170 #: templates/js/table_filters.js:128 templates/js/table_filters.js:327 msgid "Assembly" msgstr "" @@ -1617,7 +1618,7 @@ msgstr "" msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 +#: common/models.py:167 part/models.py:825 part/templates/part/detail.html:180 #: templates/js/table_filters.js:331 msgid "Component" msgstr "" @@ -1626,7 +1627,7 @@ msgstr "" msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:174 part/models.py:836 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" @@ -1634,7 +1635,7 @@ msgstr "" msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 +#: common/models.py:181 part/models.py:841 part/templates/part/detail.html:210 #: templates/js/table_filters.js:339 msgid "Salable" msgstr "" @@ -1643,7 +1644,7 @@ msgstr "" msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 +#: common/models.py:188 part/models.py:831 part/templates/part/detail.html:190 #: templates/js/table_filters.js:33 templates/js/table_filters.js:343 msgid "Trackable" msgstr "" @@ -1652,7 +1653,7 @@ msgstr "" msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:195 part/models.py:851 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" @@ -1669,160 +1670,185 @@ msgstr "" msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" +#: common/models.py:209 +msgid "Show Price in Forms" msgstr "" #: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" +msgid "Display part price in some forms" msgstr "" #: common/models.py:216 -msgid "Page Size" +msgid "Internal Prices" msgstr "" #: common/models.py:217 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:223 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:224 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:230 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:231 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:237 +msgid "Page Size" +msgstr "" + +#: common/models.py:238 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:248 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:249 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:255 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:256 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:262 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:263 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:269 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:270 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:272 part/templates/part/detail.html:121 msgid "days" msgstr "días" -#: common/models.py:256 +#: common/models.py:277 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:278 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:284 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:285 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:291 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:292 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:298 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:299 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:305 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:306 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:311 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:312 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:316 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:317 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:322 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:323 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:546 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:548 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:583 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:606 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:617 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:640 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:721 company/forms.py:192 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 +#: common/models.py:729 company/templates/company/supplier_part_pricing.html:82 +#: part/templates/part/internal_prices.html:103 #: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:730 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:822 msgid "Default" msgstr "" @@ -1843,7 +1869,9 @@ msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:582 +#: part/templates/part/bom_upload/upload_file.html:27 msgid "Upload File" msgstr "" @@ -1877,29 +1905,29 @@ msgstr "" msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:133 templates/js/part.js:787 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:135 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:143 company/models.py:321 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:149 company/models.py:328 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:151 company/models.py:327 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 #: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:408 msgid "MPN" msgstr "" @@ -1952,11 +1980,11 @@ msgstr "Contacto" msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:121 company/models.py:333 company/models.py:526 +#: order/models.py:106 part/models.py:728 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:188 templates/js/company.js:419 +#: templates/js/part.js:498 msgid "Link" msgstr "" @@ -1964,7 +1992,7 @@ msgstr "" msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:129 part/models.py:738 msgid "Image" msgstr "" @@ -1992,12 +2020,12 @@ msgstr "" msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:305 company/models.py:497 stock/models.py:407 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:309 company/models.py:501 order/views.py:1597 msgid "Select part" msgstr "" @@ -2008,7 +2036,7 @@ msgstr "" #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 #: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:390 msgid "Manufacturer" msgstr "Fabricante" @@ -2020,87 +2048,112 @@ msgstr "" msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:390 company/models.py:520 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:397 +msgid "Parameter name" +msgstr "" + +#: company/models.py:403 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:241 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:404 +msgid "Parameter value" +msgstr "" + +#: company/models.py:410 part/models.py:813 part/models.py:2165 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:247 +msgid "Units" +msgstr "" + +#: company/models.py:411 +msgid "Parameter units" +msgstr "" + +#: company/models.py:507 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:193 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:48 templates/js/company.js:364 #: templates/js/order.js:170 msgid "Supplier" msgstr "Proveedor" -#: company/models.py:467 +#: company/models.py:508 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:513 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 #: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:514 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:521 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:527 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:533 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:538 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2305 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "Nota" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 +#: company/models.py:544 company/templates/company/supplier_part_base.html:109 #: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: templates/js/stock.js:695 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:544 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:546 part/models.py:1608 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:546 msgid "Order multiple" msgstr "" #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:562 msgid "Assigned Stock" msgstr "" @@ -2165,11 +2218,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 +#: company/templates/company/detail.html:67 order/models.py:464 #: order/templates/order/sales_order_base.html:94 stock/models.py:449 #: stock/models.py:450 stock/templates/stock/item_base.html:262 #: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: templates/js/stock.js:1097 msgid "Customer" msgstr "Cliente" @@ -2215,7 +2268,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:66 #: company/templates/company/detail_supplier_part.html:66 #: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: templates/js/stock.js:1312 msgid "New Part" msgstr "" @@ -2248,13 +2301,12 @@ msgstr "Exportar" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 +#: order/templates/order/order_wizard/select_parts.html:44 #: order/templates/order/purchase_order_detail.html:50 msgid "Create new supplier part" msgstr "" @@ -2262,12 +2314,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 #: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/supplier.html:17 templates/js/stock.js:1318 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 +#: company/templates/company/manufacturer_part_suppliers.html:82 #: company/views.py:64 order/templates/order/purchase_orders.html:185 #: part/templates/part/supplier.html:50 msgid "New Supplier" @@ -2319,8 +2371,9 @@ msgid "There are %(count)s suppliers defined for this manufacturer part. If you msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:63 part/templates/part/navbar.html:86 +#: part/templates/part/navbar.html:89 templates/InvenTree/search.html:316 #: templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,13 +2385,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:38 stock/api.py:54 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2360,11 +2413,25 @@ msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:1002 users/models.py:191 msgid "Delete" msgstr "Eliminar" -#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:34 +#: part/templates/part/category_navbar.html:37 +#: part/templates/part/navbar.html:24 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:48 +msgid "New Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:83 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" @@ -2379,13 +2446,13 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:35 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 +#: templates/InvenTree/search.html:198 templates/js/stock.js:996 #: templates/stats.html:93 templates/stats.html:102 users/models.py:42 msgid "Stock Items" msgstr "" @@ -2396,7 +2463,7 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 +#: part/templates/part/navbar.html:112 part/templates/part/navbar.html:115 #: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 @@ -2408,7 +2475,7 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 +#: part/templates/part/navbar.html:92 part/templates/part/navbar.html:95 #: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 @@ -2442,7 +2509,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:7 #: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:380 msgid "Supplier Part" msgstr "" @@ -2490,8 +2557,8 @@ msgstr "" msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 company/views.py:855 +#: part/templates/part/sale_prices.html:17 part/views.py:2751 msgid "Add Price Break" msgstr "" @@ -2510,8 +2577,8 @@ msgstr "" msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 +#: company/views.py:70 part/templates/part/navbar.html:80 +#: part/templates/part/navbar.html:83 templates/InvenTree/search.html:306 #: templates/navbar.html:36 msgid "Manufacturers" msgstr "Fabricantes" @@ -2533,20 +2600,20 @@ msgstr "" msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:169 part/views.py:948 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:198 part/views.py:980 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:205 part/views.py:987 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:214 part/views.py:996 msgid "Supplied URL is not a valid image file" msgstr "" @@ -2594,27 +2661,35 @@ msgstr "" msgid "Delete Manufacturer Part" msgstr "" -#: company/views.py:528 +#: company/views.py:514 +msgid "Add Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:548 +msgid "Edit Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:588 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:639 templates/js/stock.js:1319 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:783 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 +#: company/views.py:860 part/views.py:2755 msgid "Added new price break" msgstr "" -#: company/views.py:855 part/views.py:2781 +#: company/views.py:916 part/views.py:2799 msgid "Edit Price Break" msgstr "" -#: company/views.py:870 part/views.py:2795 +#: company/views.py:931 part/views.py:2813 msgid "Delete Price Break" msgstr "" @@ -2638,7 +2713,7 @@ msgstr "" msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:124 report/models.py:297 msgid "Enabled" msgstr "" @@ -2662,7 +2737,7 @@ msgstr "" msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:144 report/models.py:290 msgid "Filename Pattern" msgstr "" @@ -2674,8 +2749,8 @@ msgstr "" msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:245 label/models.py:298 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" @@ -2696,237 +2771,239 @@ msgstr "" msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:86 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 +#: order/forms.py:108 msgid "Purchase Order reference" msgstr "" -#: order/forms.py:110 +#: order/forms.py:115 msgid "Target date for order delivery. Order will be overdue after this date." msgstr "" -#: order/forms.py:138 +#: order/forms.py:143 msgid "Enter sales order number" msgstr "" -#: order/forms.py:145 order/models.py:475 +#: order/forms.py:150 order/models.py:476 msgid "Target date for order completion. Order will be overdue after this date." msgstr "" -#: order/forms.py:236 +#: order/forms.py:242 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:248 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 +#: order/models.py:102 msgid "Order reference" msgstr "" -#: order/models.py:103 +#: order/models.py:104 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:106 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:114 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:121 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:126 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:185 order/models.py:469 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:194 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 +#: order/models.py:197 order/templates/order/order_base.html:98 #: templates/js/order.js:179 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:197 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:204 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:209 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:210 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:215 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:216 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:222 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 +#: order/models.py:246 part/views.py:1686 stock/models.py:304 #: stock/models.py:1020 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:251 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:349 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:353 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:355 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:465 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:479 templates/js/order.js:303 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:486 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:530 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:617 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:619 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:621 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:647 order/models.py:715 templates/js/order.js:353 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:648 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 #: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: templates/js/stock.js:669 templates/js/stock.js:1078 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:662 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 +#: order/models.py:665 order/templates/order/order_base.html:131 #: order/templates/order/purchase_order_detail.html:219 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:665 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:672 stock/models.py:542 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:690 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:673 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:681 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:724 part/templates/part/navbar.html:109 +#: part/templates/part/order_prices.html:107 +#: part/templates/part/part_pricing.html:97 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:725 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:800 order/models.py:802 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:806 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:808 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:811 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:821 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:826 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:837 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:838 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:841 msgid "Enter stock allocation quantity" msgstr "" @@ -2955,7 +3032,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2977,8 +3054,8 @@ msgstr "" #: order/templates/order/order_base.html:180 #: order/templates/order/purchase_order_detail.html:100 #: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: stock/templates/stock/location.html:191 templates/js/stock.js:736 +#: templates/js/stock.js:1324 msgid "New Location" msgstr "" @@ -3081,28 +3158,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3135,15 +3216,20 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +#: order/templates/order/so_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,8 +3239,8 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/sales_order_detail.html:22 order/views.py:1321 +#: order/views.py:1404 msgid "Add Line Item" msgstr "" @@ -3162,25 +3248,31 @@ msgstr "" msgid "No line items found" msgstr "" +#: order/templates/order/purchase_order_detail.html:142 +#: order/templates/order/sales_order_detail.html:223 +msgid "Total" +msgstr "" + #: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/sales_order_detail.html:246 msgid "Unit Price" msgstr "" #: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/sales_order_detail.html:253 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:255 +#: order/templates/order/sales_order_detail.html:359 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:256 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:261 msgid "Receive line item" msgstr "" @@ -3201,7 +3293,7 @@ msgstr "" #: part/templates/part/category_navbar.html:29 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 #: users/models.py:40 msgid "Parts" @@ -3216,7 +3308,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3316,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3265,17 +3357,17 @@ msgid "Sales Order Items" msgstr "" #: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: templates/js/build.js:724 templates/js/build.js:1141 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:610 +#: templates/js/build.js:946 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:612 +#: templates/js/build.js:947 msgid "Delete stock allocation" msgstr "" @@ -3283,50 +3375,50 @@ msgstr "" msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:206 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:274 templates/js/build.js:675 +#: templates/js/build.js:942 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:276 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:313 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:343 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:346 templates/js/build.js:738 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:349 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:353 templates/js/build.js:731 +#: templates/js/build.js:1149 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:356 +#: order/templates/order/sales_order_detail.html:465 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:360 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:471 msgid "Update Unit Price" msgstr "" @@ -3367,10 +3459,6 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - #: order/views.py:104 msgid "Add Purchase Order Attachment" msgstr "" @@ -3471,90 +3559,94 @@ msgstr "" msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:1012 +msgid "Update prices" +msgstr "" + +#: order/views.py:1270 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 +#: order/views.py:1330 msgid "Supplier part must be specified" msgstr "" -#: order/views.py:1326 +#: order/views.py:1336 msgid "Supplier must match for Part and Order" msgstr "" -#: order/views.py:1457 order/views.py:1475 +#: order/views.py:1467 order/views.py:1485 msgid "Edit Line Item" msgstr "" -#: order/views.py:1491 order/views.py:1503 +#: order/views.py:1501 order/views.py:1513 msgid "Delete Line Item" msgstr "" -#: order/views.py:1496 order/views.py:1508 +#: order/views.py:1506 order/views.py:1518 msgid "Deleted line item" msgstr "" -#: order/views.py:1521 +#: order/views.py:1531 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1576 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1592 msgid "Select line item" msgstr "" -#: order/views.py:1613 -#, python-brace-format -msgid "No matching item for serial {serial}" -msgstr "" - #: order/views.py:1623 #, python-brace-format +msgid "No matching item for serial {serial}" +msgstr "" + +#: order/views.py:1633 +#, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1641 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1695 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1769 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1784 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1856 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1862 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1865 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1870 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 +#: part/bom.py:138 part/models.py:72 part/models.py:747 #: part/templates/part/category.html:66 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3632,7 +3724,7 @@ msgstr "" msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:122 part/models.py:2191 msgid "Parent Part" msgstr "" @@ -3708,7 +3800,7 @@ msgstr "" msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:344 part/models.py:2286 msgid "Sub part" msgstr "" @@ -3728,7 +3820,7 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:82 part/models.py:2237 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" @@ -3739,365 +3831,360 @@ msgstr "" msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:448 part/models.py:460 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:557 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:561 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:566 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:645 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:670 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:677 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:678 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:689 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:690 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:696 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:701 part/templates/part/category.html:73 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:702 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:709 part/models.py:2236 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:710 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:715 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "" -#: part/models.py:731 +#: part/models.py:716 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:722 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:723 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:745 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:792 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:793 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:800 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:801 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:806 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:807 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:814 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:820 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:826 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:832 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:837 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:842 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:846 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 #: templates/js/table_filters.js:241 templates/js/table_filters.js:310 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:847 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:852 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:857 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:863 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:865 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:869 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1608 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2063 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2080 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2100 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2101 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2106 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2107 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 +#: part/models.py:2112 templates/js/part.js:726 #: templates/js/table_filters.js:227 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2113 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2118 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2119 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2124 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2125 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2158 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2163 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2165 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2193 part/models.py:2242 part/models.py:2243 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2247 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2248 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2278 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2287 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2293 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2295 templates/js/bom.js:216 templates/js/bom.js:285 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2295 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2298 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2299 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2302 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2305 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2311 templates/js/bom.js:302 templates/js/bom.js:309 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2312 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2317 templates/js/bom.js:294 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2318 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 +#: part/models.py:2394 part/views.py:1692 part/views.py:1744 #: stock/models.py:294 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2403 part/models.py:2405 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2408 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2527 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2563 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 @@ -4112,8 +4199,8 @@ msgstr "" msgid "Deleting this entry will remove the BOM row from the following part" msgstr "" -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:50 +#: part/templates/part/navbar.html:53 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4247,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:1987 msgid "Export Bill of Materials" msgstr "" @@ -4177,7 +4264,7 @@ msgid "All selected BOM items will be deleted" msgstr "" #: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: templates/js/stock.js:1313 msgid "Create New Part" msgstr "" @@ -4258,7 +4345,7 @@ msgstr "" msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:29 part/views.py:2397 msgid "Create new part category" msgstr "" @@ -4318,7 +4405,7 @@ msgid "View grid display" msgstr "" #: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: stock/templates/stock/location.html:192 templates/js/stock.js:737 msgid "Create new location" msgstr "" @@ -4373,14 +4460,8 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 -#: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" -msgstr "" - #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:21 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" @@ -4408,7 +4489,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:13 msgid "Part Details" msgstr "" @@ -4488,6 +4569,36 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/internal_prices.html:11 +#: part/templates/part/navbar.html:100 +msgid "Internal Price Information" +msgstr "" + +#: part/templates/part/internal_prices.html:19 part/views.py:2822 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/internal_prices.html:28 templates/403.html:5 +#: templates/403.html:11 +msgid "Permission Denied" +msgstr "" + +#: part/templates/part/internal_prices.html:31 templates/403.html:14 +msgid "You do not have permission to view this page." +msgstr "" + +#: part/templates/part/internal_prices.html:59 +msgid "No internal price break information found" +msgstr "" + +#: part/templates/part/internal_prices.html:110 +msgid "Edit internal price break" +msgstr "" + +#: part/templates/part/internal_prices.html:111 +msgid "Delete internal price break" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4501,127 +4612,141 @@ msgstr "" msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:28 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:31 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:42 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:45 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:66 part/templates/part/navbar.html:69 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 +#: part/templates/part/navbar.html:74 part/templates/part/order_prices.html:12 msgid "Order Price Information" msgstr "" -#: part/templates/part/navbar.html:75 +#: part/templates/part/navbar.html:77 msgid "Order Price" msgstr "" -#: part/templates/part/navbar.html:98 +#: part/templates/part/navbar.html:103 part/templates/part/order_prices.html:93 +#: part/templates/part/part_pricing.html:82 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/navbar.html:106 msgid "Sales Price Information" msgstr "" -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:120 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:123 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:127 part/templates/part/navbar.html:130 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:139 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 +#: part/templates/part/order_prices.html:24 +#: part/templates/part/part_base.html:282 +msgid "Calculate" +msgstr "" + +#: part/templates/part/order_prices.html:31 msgid "Pricing ranges" msgstr "" -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 +#: part/templates/part/order_prices.html:36 +#: part/templates/part/part_pricing.html:22 msgid "Supplier Pricing" msgstr "" -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 +#: part/templates/part/order_prices.html:37 +#: part/templates/part/order_prices.html:62 +#: part/templates/part/order_prices.html:94 +#: part/templates/part/order_prices.html:108 +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 msgid "Unit Cost" msgstr "" -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 +#: part/templates/part/order_prices.html:44 +#: part/templates/part/order_prices.html:69 +#: part/templates/part/order_prices.html:99 +#: part/templates/part/order_prices.html:113 +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 msgid "Total Cost" msgstr "" -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 +#: part/templates/part/order_prices.html:52 +#: part/templates/part/part_pricing.html:40 msgid "No supplier pricing available" msgstr "" -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 +#: part/templates/part/order_prices.html:61 +#: part/templates/part/order_prices.html:128 +#: part/templates/part/part_pricing.html:48 msgid "BOM Pricing" msgstr "" -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 +#: part/templates/part/order_prices.html:77 +#: part/templates/part/part_pricing.html:66 msgid "Note: BOM pricing is incomplete for this part" msgstr "" -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 +#: part/templates/part/order_prices.html:84 +#: part/templates/part/part_pricing.html:73 msgid "No BOM pricing available" msgstr "" -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 +#: part/templates/part/order_prices.html:122 +#: part/templates/part/part_pricing.html:113 msgid "No pricing information is available for this part." msgstr "" -#: part/templates/part/order_prices.html:113 +#: part/templates/part/order_prices.html:138 msgid "Stock Pricing" msgstr "" -#: part/templates/part/order_prices.html:121 +#: part/templates/part/order_prices.html:146 msgid "No stock pricing history is available for this part." msgstr "" -#: part/templates/part/order_prices.html:140 +#: part/templates/part/order_prices.html:165 #, python-format msgid "Single Price - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:152 +#: part/templates/part/order_prices.html:177 #, python-format msgid "Single Price Difference - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:163 +#: part/templates/part/order_prices.html:189 #, python-format msgid "Part Single Price - %(currency)s" msgstr "" @@ -4630,19 +4755,6 @@ msgstr "" msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4660,7 +4772,7 @@ msgid "Part List" msgstr "" #: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: templates/js/company.js:355 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4740,14 +4852,10 @@ msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 -msgid "Calculate" -msgstr "" - #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" @@ -4816,7 +4924,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,7 +4961,7 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" @@ -4922,227 +5030,239 @@ msgstr "" msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:925 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 +#: part/views.py:1027 msgid "Upload Part Image" msgstr "" -#: part/views.py:1022 part/views.py:1057 +#: part/views.py:1033 part/views.py:1068 msgid "Updated part image" msgstr "" -#: part/views.py:1031 +#: part/views.py:1042 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1071 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1082 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1117 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1147 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1168 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1189 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1200 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1334 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1695 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1720 part/views.py:1723 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1729 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1767 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1773 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1777 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2039 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2046 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2055 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2196 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2206 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2213 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2221 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2271 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2285 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 +#: part/views.py:2345 msgid "Edit Part Category" msgstr "" -#: part/views.py:2365 +#: part/views.py:2383 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2389 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2441 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2542 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2598 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2617 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2687 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 +#: part/views.py:2743 msgid "Confim BOM item deletion" msgstr "" -#: report/models.py:180 +#: part/views.py:2831 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2839 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5174,7 +5294,7 @@ msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:195 templates/js/stock.js:1012 msgid "Date" msgstr "" @@ -5197,7 +5317,7 @@ msgid "Moved {n} parts to {loc}" msgstr "" #: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" @@ -5483,12 +5603,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5738,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:593 msgid "No location set" msgstr "" @@ -5630,25 +5750,29 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" @@ -5945,7 +6069,7 @@ msgstr "" msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:1001 users/models.py:187 msgid "Add" msgstr "" @@ -6011,7 +6135,7 @@ msgstr "" msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1575 templates/js/build.js:326 msgid "Create new Stock Item" msgstr "" @@ -6043,14 +6167,6 @@ msgstr "" msgid "Add Stock Tracking Entry" msgstr "" -#: templates/403.html:5 templates/403.html:11 -msgid "Permission Denied" -msgstr "" - -#: templates/403.html:14 -msgid "You do not have permission to view this page." -msgstr "" - #: templates/404.html:5 templates/404.html:11 msgid "Page Not Found" msgstr "" @@ -6119,11 +6235,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6284,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:85 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:86 msgid "Delete Template" msgstr "" @@ -6221,11 +6337,11 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 +#: templates/InvenTree/settings/part.html:44 msgid "Part Parameter Templates" msgstr "" -#: templates/InvenTree/settings/part.html:61 +#: templates/InvenTree/settings/part.html:65 msgid "No part parameter templates found" msgstr "" @@ -6341,47 +6457,51 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 +#: templates/about.html:100 templates/js/modals.js:568 +#: templates/js/modals.js:861 templates/modals.html:29 templates/modals.html:54 #: templates/modals.html:97 msgid "Close" msgstr "" @@ -6442,7 +6562,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:921 msgid "Invalid server response" msgstr "" @@ -6506,7 +6626,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1091 msgid "Open subassembly" msgstr "" @@ -6542,7 +6662,7 @@ msgstr "" msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:470 templates/js/build.js:423 templates/js/build.js:1189 msgid "No BOM items found" msgstr "" @@ -6562,37 +6682,45 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:382 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:325 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:644 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:665 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:735 templates/js/build.js:1153 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:788 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:805 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:966 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:825 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:924 msgid "No parts allocated for" msgstr "" @@ -6612,17 +6740,29 @@ msgstr "" msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:148 templates/js/company.js:347 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:152 templates/js/company.js:351 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:226 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:262 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:263 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:328 msgid "No supplier parts found" msgstr "" @@ -6710,76 +6850,76 @@ msgstr "" msgid "Loading Data" msgstr "" -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:567 templates/js/modals.js:860 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:824 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:921 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 +#: templates/js/modals.js:931 msgid "No Response" msgstr "" -#: templates/js/modals.js:912 +#: templates/js/modals.js:932 msgid "No response from the InvenTree server" msgstr "" -#: templates/js/modals.js:916 +#: templates/js/modals.js:936 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:937 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 +#: templates/js/modals.js:941 msgid "Error 401: Not Authenticated" msgstr "" -#: templates/js/modals.js:922 +#: templates/js/modals.js:942 msgid "Authentication credentials not supplied" msgstr "" -#: templates/js/modals.js:926 +#: templates/js/modals.js:946 msgid "Error 403: Permission Denied" msgstr "" -#: templates/js/modals.js:927 +#: templates/js/modals.js:947 msgid "You do not have the required permissions to access this function" msgstr "" -#: templates/js/modals.js:931 +#: templates/js/modals.js:951 msgid "Error 404: Resource Not Found" msgstr "" -#: templates/js/modals.js:932 +#: templates/js/modals.js:952 msgid "The requested resource could not be located on the server" msgstr "" -#: templates/js/modals.js:936 +#: templates/js/modals.js:956 msgid "Error 408: Timeout" msgstr "" -#: templates/js/modals.js:937 +#: templates/js/modals.js:957 msgid "Connection timeout while requesting data from server" msgstr "" -#: templates/js/modals.js:940 +#: templates/js/modals.js:960 msgid "Error requesting form data" msgstr "" @@ -6795,6 +6935,10 @@ msgstr "" msgid "No sales orders found" msgstr "" +#: templates/js/order.js:343 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +6967,39 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:323 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:990 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:806 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7097,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:853 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:868 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:882 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:883 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1022 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1069 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1088 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1107 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1125 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1148 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1156 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1188 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1200 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1201 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1325 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1366 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1389 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1417 msgid "Uninstall Stock Item" msgstr "" @@ -7267,56 +7411,56 @@ msgstr "" msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" @@ -7560,35 +7704,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:174 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:182 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:187 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:191 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/fr/LC_MESSAGES/django.po b/InvenTree/locale/fr/LC_MESSAGES/django.po index 97617764a4..61f43d466b 100644 --- a/InvenTree/locale/fr/LC_MESSAGES/django.po +++ b/InvenTree/locale/fr/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:40\n" +"POT-Creation-Date: 2021-06-24 21:38+0000\n" +"PO-Revision-Date: 2021-06-24 21:40\n" "Last-Translator: \n" "Language-Team: French\n" "Language: fr_FR\n" @@ -77,7 +77,7 @@ msgstr "Sélectionnez une catégorie" msgid "Duplicate serial: {n}" msgstr "Dupliquer le numéro de série: {n}" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 +#: InvenTree/helpers.py:384 order/models.py:248 order/models.py:358 #: stock/views.py:1795 msgid "Invalid quantity provided" msgstr "Quantité fournie invalide" @@ -122,9 +122,9 @@ msgstr "Commentaire" msgid "File comment" msgstr "Commentaire du fichier" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:2022 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1179 msgid "User" msgstr "Utilisateur" @@ -132,34 +132,35 @@ msgstr "Utilisateur" msgid "upload date" msgstr "date de chargement" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:107 InvenTree/models.py:108 company/models.py:396 +#: label/models.py:102 part/models.py:671 part/models.py:2163 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:235 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:972 msgid "Name" msgstr "Nom" #: InvenTree/models.py:114 build/models.py:135 #: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: company/models.py:532 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 #: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: order/models.py:104 order/templates/order/purchase_order_detail.html:147 +#: part/models.py:695 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 +#: templates/js/build.js:833 templates/js/build.js:1101 #: templates/js/company.js:56 templates/js/order.js:183 #: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:984 +#: templates/js/stock.js:1029 msgid "Description" msgstr "Description" @@ -191,15 +192,15 @@ msgstr "Polonais" msgid "Turkish" msgstr "Turc" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "Échec de la vérification du processus d'arrière-plan" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "Backend d'email non configuré" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "Échec des contrôles de santé du système" @@ -372,27 +373,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "Supprimer cet élément" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "Modifier les informations utilisateur" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "Informations système" @@ -445,11 +446,11 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 order/forms.py:114 order/forms.py:149 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 +#: templates/js/build.js:880 templates/js/order.js:200 #: templates/js/order.js:298 msgid "Target Date" msgstr "" @@ -462,22 +463,21 @@ msgstr "" #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 +#: build/templates/build/detail.html:31 common/models.py:720 +#: company/forms.py:191 company/templates/company/supplier_part_pricing.html:77 +#: order/forms.py:193 order/forms.py:211 order/forms.py:246 order/forms.py:268 +#: order/forms.py:285 order/models.py:617 order/models.py:841 #: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/order_wizard/select_parts.html:34 #: order/templates/order/purchase_order_detail.html:179 #: order/templates/order/sales_order_detail.html:70 #: order/templates/order/sales_order_detail.html:77 #: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 +#: order/templates/order/sales_order_detail.html:234 part/forms.py:342 +#: part/forms.py:372 part/forms.py:388 part/forms.py:404 part/models.py:2293 +#: part/templates/part/internal_prices.html:98 +#: part/templates/part/order_prices.html:202 +#: part/templates/part/part_pricing.html:16 #: part/templates/part/sale_prices.html:85 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 @@ -486,9 +486,10 @@ msgstr "" #: stock/forms.py:175 stock/forms.py:308 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:571 +#: templates/js/build.js:1111 templates/js/order.js:393 +#: templates/js/part.js:796 templates/js/stock.js:1164 +#: templates/js/stock.js:1383 msgid "Quantity" msgstr "Quantité" @@ -500,7 +501,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:240 stock/forms.py:118 msgid "Serial Numbers" msgstr "Numéros de série" @@ -529,12 +530,12 @@ msgid "Mark build as complete" msgstr "" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:347 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:585 templates/js/order.js:378 +#: templates/js/stock.js:643 templates/js/stock.js:1056 msgid "Location" msgstr "" @@ -543,13 +544,13 @@ msgid "Location of completed parts" msgstr "Emplacement des pièces terminées" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:469 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:867 #: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: templates/js/stock.js:630 templates/js/stock.js:1133 +#: templates/js/stock.js:1399 msgid "Status" msgstr "" @@ -583,16 +584,16 @@ msgstr "" #: build/models.py:66 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "" #: build/models.py:67 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:57 +#: part/templates/part/navbar.html:60 templates/InvenTree/index.html:183 #: templates/InvenTree/search.html:185 #: templates/InvenTree/settings/tabs.html:34 users/models.py:43 msgid "Build Orders" @@ -602,12 +603,12 @@ msgstr "" msgid "Build Order Reference" msgstr "" -#: build/models.py:128 order/models.py:101 order/models.py:618 +#: build/models.py:128 order/models.py:102 order/models.py:619 #: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: order/templates/order/sales_order_detail.html:229 part/models.py:2302 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:660 templates/js/build.js:1105 msgid "Reference" msgstr "Référence" @@ -626,27 +627,27 @@ msgstr "" #: build/models.py:153 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 +#: build/templates/build/detail.html:26 company/models.py:663 +#: order/models.py:661 order/models.py:717 +#: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:132 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:214 part/models.py:321 +#: part/models.py:1975 part/models.py:1987 part/models.py:2002 +#: part/models.py:2020 part/models.py:2095 part/models.py:2191 +#: part/models.py:2277 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:551 templates/js/build.js:838 +#: templates/js/build.js:1078 templates/js/company.js:140 +#: templates/js/company.js:339 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1371 msgid "Part" msgstr "Pièce" @@ -710,16 +711,16 @@ msgstr "" msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 +#: build/models.py:220 order/models.py:108 part/models.py:867 #: part/templates/part/detail.html:126 templates/js/order.js:293 msgid "Creation Date" msgstr "Date de création" -#: build/models.py:224 order/models.py:474 +#: build/models.py:224 order/models.py:475 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:228 order/models.py:221 templates/js/build.js:885 msgid "Completion Date" msgstr "" @@ -736,9 +737,9 @@ msgid "User who issued this build order" msgstr "" #: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/templates/build/detail.html:105 order/models.py:122 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:871 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "" @@ -757,26 +758,26 @@ msgstr "" msgid "External Link" msgstr "Lien Externe" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:258 part/models.py:729 stock/models.py:462 msgid "Link to external URL" msgstr "" #: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: company/models.py:132 company/models.py:539 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:126 +#: order/models.py:621 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:243 +#: order/templates/order/sales_order_detail.html:309 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:856 +#: part/templates/part/navbar.html:142 #: report/templates/report/inventree_build_order_base.html:173 #: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 #: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:699 msgid "Notes" msgstr "Notes" @@ -809,11 +810,11 @@ msgstr "L'élément de construction doit spécifier une sortie de construction, msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1188 order/models.py:815 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1192 order/models.py:818 msgid "Allocation quantity must be greater than zero" msgstr "" @@ -827,7 +828,7 @@ msgid "Selected stock item not found in BOM for part '{p}'" msgstr "L'article en stock sélectionné n'a pas été trouvé dans la BOM pour la pièce '{p}'" #: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: templates/InvenTree/search.html:183 templates/js/build.js:811 #: templates/navbar.html:29 msgid "Build" msgstr "" @@ -836,15 +837,13 @@ msgstr "" msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1333 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:928 +#: templates/js/order.js:366 templates/js/order.js:371 +#: templates/js/stock.js:1115 msgid "Stock Item" msgstr "" @@ -880,7 +879,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:743 msgid "Unallocate stock" msgstr "" @@ -917,15 +916,15 @@ msgstr "" #: order/templates/order/sales_order_detail.html:160 #: report/templates/report/inventree_test_report_base.html:75 #: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: templates/js/build.js:569 msgid "Serial Number" msgstr "" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:133 +#: part/templates/part/navbar.html:136 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "Pieces jointes" @@ -1037,11 +1036,10 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:715 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 #: stock/templates/stock/item_base.html:279 templates/js/order.js:245 @@ -1185,7 +1183,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:85 order/models.py:678 +#: order/templates/order/purchase_order_detail.html:239 +#: order/templates/order/receive_parts.html:25 stock/forms.py:169 +#: stock/forms.py:375 msgid "Destination" msgstr "" @@ -1194,15 +1195,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1406 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:875 msgid "Created" msgstr "" @@ -1210,7 +1211,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:853 msgid "Completed" msgstr "" @@ -1248,9 +1249,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:17 +#: templates/js/stock.js:1044 msgid "Details" msgstr "Détails" @@ -1285,8 +1286,8 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 +#: stock/templates/stock/item_base.html:497 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "Enregistrer" @@ -1411,8 +1412,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:670 +#: templates/js/build.js:935 templates/js/build.js:1118 msgid "Available" msgstr "Disponible" @@ -1598,8 +1599,8 @@ msgstr "" msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 +#: common/models.py:153 part/models.py:2193 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:259 templates/js/table_filters.js:25 #: templates/js/table_filters.js:315 msgid "Template" msgstr "" @@ -1608,7 +1609,7 @@ msgstr "" msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 +#: common/models.py:160 part/models.py:819 part/templates/part/detail.html:170 #: templates/js/table_filters.js:128 templates/js/table_filters.js:327 msgid "Assembly" msgstr "" @@ -1617,7 +1618,7 @@ msgstr "" msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 +#: common/models.py:167 part/models.py:825 part/templates/part/detail.html:180 #: templates/js/table_filters.js:331 msgid "Component" msgstr "" @@ -1626,7 +1627,7 @@ msgstr "" msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:174 part/models.py:836 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" @@ -1634,7 +1635,7 @@ msgstr "" msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 +#: common/models.py:181 part/models.py:841 part/templates/part/detail.html:210 #: templates/js/table_filters.js:339 msgid "Salable" msgstr "" @@ -1643,7 +1644,7 @@ msgstr "" msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 +#: common/models.py:188 part/models.py:831 part/templates/part/detail.html:190 #: templates/js/table_filters.js:33 templates/js/table_filters.js:343 msgid "Trackable" msgstr "" @@ -1652,7 +1653,7 @@ msgstr "" msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:195 part/models.py:851 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" @@ -1669,160 +1670,185 @@ msgstr "" msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" +#: common/models.py:209 +msgid "Show Price in Forms" msgstr "" #: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" +msgid "Display part price in some forms" msgstr "" #: common/models.py:216 -msgid "Page Size" +msgid "Internal Prices" msgstr "" #: common/models.py:217 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:223 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:224 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:230 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:231 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:237 +msgid "Page Size" +msgstr "" + +#: common/models.py:238 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:248 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:249 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:255 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:256 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:262 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:263 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:269 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:270 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:272 part/templates/part/detail.html:121 msgid "days" msgstr "jours" -#: common/models.py:256 +#: common/models.py:277 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:278 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:284 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:285 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:291 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:292 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:298 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:299 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:305 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:306 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:311 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:312 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:316 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:317 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:322 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:323 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:546 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:548 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:583 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:606 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:617 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:640 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:721 company/forms.py:192 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 +#: common/models.py:729 company/templates/company/supplier_part_pricing.html:82 +#: part/templates/part/internal_prices.html:103 #: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:730 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:822 msgid "Default" msgstr "" @@ -1843,7 +1869,9 @@ msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:582 +#: part/templates/part/bom_upload/upload_file.html:27 msgid "Upload File" msgstr "" @@ -1877,29 +1905,29 @@ msgstr "" msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:133 templates/js/part.js:787 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:135 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:143 company/models.py:321 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:149 company/models.py:328 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:151 company/models.py:327 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 #: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:408 msgid "MPN" msgstr "" @@ -1952,11 +1980,11 @@ msgstr "" msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:121 company/models.py:333 company/models.py:526 +#: order/models.py:106 part/models.py:728 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:188 templates/js/company.js:419 +#: templates/js/part.js:498 msgid "Link" msgstr "" @@ -1964,7 +1992,7 @@ msgstr "" msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:129 part/models.py:738 msgid "Image" msgstr "" @@ -1992,12 +2020,12 @@ msgstr "" msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:305 company/models.py:497 stock/models.py:407 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:309 company/models.py:501 order/views.py:1597 msgid "Select part" msgstr "" @@ -2008,7 +2036,7 @@ msgstr "" #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 #: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:390 msgid "Manufacturer" msgstr "" @@ -2020,87 +2048,112 @@ msgstr "" msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:390 company/models.py:520 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:397 +msgid "Parameter name" +msgstr "" + +#: company/models.py:403 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:241 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:404 +msgid "Parameter value" +msgstr "" + +#: company/models.py:410 part/models.py:813 part/models.py:2165 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:247 +msgid "Units" +msgstr "" + +#: company/models.py:411 +msgid "Parameter units" +msgstr "" + +#: company/models.py:507 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:193 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:48 templates/js/company.js:364 #: templates/js/order.js:170 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:508 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:513 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 #: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:514 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:521 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:527 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:533 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:538 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2305 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 +#: company/models.py:544 company/templates/company/supplier_part_base.html:109 #: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: templates/js/stock.js:695 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:544 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:546 part/models.py:1608 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:546 msgid "Order multiple" msgstr "" #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:562 msgid "Assigned Stock" msgstr "" @@ -2165,11 +2218,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 +#: company/templates/company/detail.html:67 order/models.py:464 #: order/templates/order/sales_order_base.html:94 stock/models.py:449 #: stock/models.py:450 stock/templates/stock/item_base.html:262 #: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: templates/js/stock.js:1097 msgid "Customer" msgstr "" @@ -2215,7 +2268,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:66 #: company/templates/company/detail_supplier_part.html:66 #: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: templates/js/stock.js:1312 msgid "New Part" msgstr "" @@ -2248,13 +2301,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 +#: order/templates/order/order_wizard/select_parts.html:44 #: order/templates/order/purchase_order_detail.html:50 msgid "Create new supplier part" msgstr "" @@ -2262,12 +2314,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 #: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/supplier.html:17 templates/js/stock.js:1318 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 +#: company/templates/company/manufacturer_part_suppliers.html:82 #: company/views.py:64 order/templates/order/purchase_orders.html:185 #: part/templates/part/supplier.html:50 msgid "New Supplier" @@ -2319,8 +2371,9 @@ msgid "There are %(count)s suppliers defined for this manufacturer part. If you msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:63 part/templates/part/navbar.html:86 +#: part/templates/part/navbar.html:89 templates/InvenTree/search.html:316 #: templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,13 +2385,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:38 stock/api.py:54 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2360,11 +2413,25 @@ msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:1002 users/models.py:191 msgid "Delete" msgstr "" -#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:34 +#: part/templates/part/category_navbar.html:37 +#: part/templates/part/navbar.html:24 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:48 +msgid "New Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:83 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" @@ -2379,13 +2446,13 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:35 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 +#: templates/InvenTree/search.html:198 templates/js/stock.js:996 #: templates/stats.html:93 templates/stats.html:102 users/models.py:42 msgid "Stock Items" msgstr "" @@ -2396,7 +2463,7 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 +#: part/templates/part/navbar.html:112 part/templates/part/navbar.html:115 #: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 @@ -2408,7 +2475,7 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 +#: part/templates/part/navbar.html:92 part/templates/part/navbar.html:95 #: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 @@ -2442,7 +2509,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:7 #: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:380 msgid "Supplier Part" msgstr "" @@ -2490,8 +2557,8 @@ msgstr "" msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 company/views.py:855 +#: part/templates/part/sale_prices.html:17 part/views.py:2751 msgid "Add Price Break" msgstr "" @@ -2510,8 +2577,8 @@ msgstr "" msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 +#: company/views.py:70 part/templates/part/navbar.html:80 +#: part/templates/part/navbar.html:83 templates/InvenTree/search.html:306 #: templates/navbar.html:36 msgid "Manufacturers" msgstr "" @@ -2533,20 +2600,20 @@ msgstr "" msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:169 part/views.py:948 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:198 part/views.py:980 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:205 part/views.py:987 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:214 part/views.py:996 msgid "Supplied URL is not a valid image file" msgstr "" @@ -2594,27 +2661,35 @@ msgstr "" msgid "Delete Manufacturer Part" msgstr "" -#: company/views.py:528 +#: company/views.py:514 +msgid "Add Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:548 +msgid "Edit Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:588 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:639 templates/js/stock.js:1319 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:783 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 +#: company/views.py:860 part/views.py:2755 msgid "Added new price break" msgstr "" -#: company/views.py:855 part/views.py:2781 +#: company/views.py:916 part/views.py:2799 msgid "Edit Price Break" msgstr "" -#: company/views.py:870 part/views.py:2795 +#: company/views.py:931 part/views.py:2813 msgid "Delete Price Break" msgstr "" @@ -2638,7 +2713,7 @@ msgstr "" msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:124 report/models.py:297 msgid "Enabled" msgstr "" @@ -2662,7 +2737,7 @@ msgstr "" msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:144 report/models.py:290 msgid "Filename Pattern" msgstr "" @@ -2674,8 +2749,8 @@ msgstr "" msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:245 label/models.py:298 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" @@ -2696,237 +2771,239 @@ msgstr "" msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:86 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 +#: order/forms.py:108 msgid "Purchase Order reference" msgstr "" -#: order/forms.py:110 +#: order/forms.py:115 msgid "Target date for order delivery. Order will be overdue after this date." msgstr "" -#: order/forms.py:138 +#: order/forms.py:143 msgid "Enter sales order number" msgstr "" -#: order/forms.py:145 order/models.py:475 +#: order/forms.py:150 order/models.py:476 msgid "Target date for order completion. Order will be overdue after this date." msgstr "" -#: order/forms.py:236 +#: order/forms.py:242 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:248 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 +#: order/models.py:102 msgid "Order reference" msgstr "" -#: order/models.py:103 +#: order/models.py:104 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:106 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:114 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:121 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:126 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:185 order/models.py:469 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:194 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 +#: order/models.py:197 order/templates/order/order_base.html:98 #: templates/js/order.js:179 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:197 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:204 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:209 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:210 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:215 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:216 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:222 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 +#: order/models.py:246 part/views.py:1686 stock/models.py:304 #: stock/models.py:1020 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:251 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:349 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:353 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:355 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:465 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:479 templates/js/order.js:303 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:486 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:530 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:617 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:619 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:621 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:647 order/models.py:715 templates/js/order.js:353 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:648 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 #: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: templates/js/stock.js:669 templates/js/stock.js:1078 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:662 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 +#: order/models.py:665 order/templates/order/order_base.html:131 #: order/templates/order/purchase_order_detail.html:219 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:665 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:672 stock/models.py:542 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:690 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:673 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:681 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:724 part/templates/part/navbar.html:109 +#: part/templates/part/order_prices.html:107 +#: part/templates/part/part_pricing.html:97 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:725 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:800 order/models.py:802 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:806 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:808 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:811 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:821 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:826 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:837 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:838 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:841 msgid "Enter stock allocation quantity" msgstr "" @@ -2955,7 +3032,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2977,8 +3054,8 @@ msgstr "" #: order/templates/order/order_base.html:180 #: order/templates/order/purchase_order_detail.html:100 #: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: stock/templates/stock/location.html:191 templates/js/stock.js:736 +#: templates/js/stock.js:1324 msgid "New Location" msgstr "" @@ -3081,28 +3158,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3135,15 +3216,20 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +#: order/templates/order/so_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,8 +3239,8 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/sales_order_detail.html:22 order/views.py:1321 +#: order/views.py:1404 msgid "Add Line Item" msgstr "" @@ -3162,25 +3248,31 @@ msgstr "" msgid "No line items found" msgstr "" +#: order/templates/order/purchase_order_detail.html:142 +#: order/templates/order/sales_order_detail.html:223 +msgid "Total" +msgstr "" + #: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/sales_order_detail.html:246 msgid "Unit Price" msgstr "" #: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/sales_order_detail.html:253 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:255 +#: order/templates/order/sales_order_detail.html:359 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:256 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:261 msgid "Receive line item" msgstr "" @@ -3201,7 +3293,7 @@ msgstr "" #: part/templates/part/category_navbar.html:29 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 #: users/models.py:40 msgid "Parts" @@ -3216,7 +3308,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3316,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3265,17 +3357,17 @@ msgid "Sales Order Items" msgstr "" #: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: templates/js/build.js:724 templates/js/build.js:1141 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:610 +#: templates/js/build.js:946 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:612 +#: templates/js/build.js:947 msgid "Delete stock allocation" msgstr "" @@ -3283,50 +3375,50 @@ msgstr "" msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:206 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:274 templates/js/build.js:675 +#: templates/js/build.js:942 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:276 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:313 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:343 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:346 templates/js/build.js:738 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:349 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:353 templates/js/build.js:731 +#: templates/js/build.js:1149 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:356 +#: order/templates/order/sales_order_detail.html:465 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:360 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:471 msgid "Update Unit Price" msgstr "" @@ -3367,10 +3459,6 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - #: order/views.py:104 msgid "Add Purchase Order Attachment" msgstr "" @@ -3471,90 +3559,94 @@ msgstr "" msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:1012 +msgid "Update prices" +msgstr "" + +#: order/views.py:1270 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 +#: order/views.py:1330 msgid "Supplier part must be specified" msgstr "" -#: order/views.py:1326 +#: order/views.py:1336 msgid "Supplier must match for Part and Order" msgstr "" -#: order/views.py:1457 order/views.py:1475 +#: order/views.py:1467 order/views.py:1485 msgid "Edit Line Item" msgstr "" -#: order/views.py:1491 order/views.py:1503 +#: order/views.py:1501 order/views.py:1513 msgid "Delete Line Item" msgstr "" -#: order/views.py:1496 order/views.py:1508 +#: order/views.py:1506 order/views.py:1518 msgid "Deleted line item" msgstr "" -#: order/views.py:1521 +#: order/views.py:1531 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1576 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1592 msgid "Select line item" msgstr "" -#: order/views.py:1613 -#, python-brace-format -msgid "No matching item for serial {serial}" -msgstr "" - #: order/views.py:1623 #, python-brace-format +msgid "No matching item for serial {serial}" +msgstr "" + +#: order/views.py:1633 +#, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1641 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1695 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1769 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1784 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1856 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1862 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1865 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1870 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 +#: part/bom.py:138 part/models.py:72 part/models.py:747 #: part/templates/part/category.html:66 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3632,7 +3724,7 @@ msgstr "" msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:122 part/models.py:2191 msgid "Parent Part" msgstr "" @@ -3708,7 +3800,7 @@ msgstr "" msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:344 part/models.py:2286 msgid "Sub part" msgstr "" @@ -3728,7 +3820,7 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:82 part/models.py:2237 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" @@ -3739,365 +3831,360 @@ msgstr "" msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:448 part/models.py:460 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:557 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:561 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:566 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:645 msgid "Duplicate IPN not allowed in part settings" msgstr "IPN dupliqué non autorisé dans les paramètres de la pièce" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "La pièce doit être unique par son nom, son IPN et sa révision" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:670 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:677 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:678 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:689 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:690 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:696 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:701 part/templates/part/category.html:73 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:702 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:709 part/models.py:2236 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:710 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:715 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "IPN" -#: part/models.py:731 +#: part/models.py:716 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:722 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:723 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:745 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:792 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:793 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:800 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:801 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:806 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:807 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:814 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:820 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:826 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:832 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:837 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:842 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:846 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 #: templates/js/table_filters.js:241 templates/js/table_filters.js:310 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:847 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:852 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:857 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:863 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:865 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:869 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1608 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2063 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2080 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2100 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2101 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2106 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2107 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 +#: part/models.py:2112 templates/js/part.js:726 #: templates/js/table_filters.js:227 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2113 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2118 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2119 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2124 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2125 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2158 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2163 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2165 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2193 part/models.py:2242 part/models.py:2243 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2247 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2248 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2278 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2287 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2293 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2295 templates/js/bom.js:216 templates/js/bom.js:285 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2295 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2298 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2299 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2302 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2305 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2311 templates/js/bom.js:302 templates/js/bom.js:309 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2312 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2317 templates/js/bom.js:294 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2318 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 +#: part/models.py:2394 part/views.py:1692 part/views.py:1744 #: stock/models.py:294 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2403 part/models.py:2405 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2408 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2527 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2563 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 @@ -4112,8 +4199,8 @@ msgstr "" msgid "Deleting this entry will remove the BOM row from the following part" msgstr "" -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:50 +#: part/templates/part/navbar.html:53 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4247,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:1987 msgid "Export Bill of Materials" msgstr "" @@ -4177,7 +4264,7 @@ msgid "All selected BOM items will be deleted" msgstr "" #: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: templates/js/stock.js:1313 msgid "Create New Part" msgstr "" @@ -4258,7 +4345,7 @@ msgstr "" msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:29 part/views.py:2397 msgid "Create new part category" msgstr "" @@ -4318,7 +4405,7 @@ msgid "View grid display" msgstr "" #: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: stock/templates/stock/location.html:192 templates/js/stock.js:737 msgid "Create new location" msgstr "" @@ -4373,14 +4460,8 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 -#: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" -msgstr "" - #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:21 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" @@ -4408,7 +4489,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:13 msgid "Part Details" msgstr "" @@ -4488,6 +4569,36 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/internal_prices.html:11 +#: part/templates/part/navbar.html:100 +msgid "Internal Price Information" +msgstr "" + +#: part/templates/part/internal_prices.html:19 part/views.py:2822 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/internal_prices.html:28 templates/403.html:5 +#: templates/403.html:11 +msgid "Permission Denied" +msgstr "" + +#: part/templates/part/internal_prices.html:31 templates/403.html:14 +msgid "You do not have permission to view this page." +msgstr "" + +#: part/templates/part/internal_prices.html:59 +msgid "No internal price break information found" +msgstr "" + +#: part/templates/part/internal_prices.html:110 +msgid "Edit internal price break" +msgstr "" + +#: part/templates/part/internal_prices.html:111 +msgid "Delete internal price break" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4501,127 +4612,141 @@ msgstr "" msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:28 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:31 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:42 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:45 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:66 part/templates/part/navbar.html:69 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 +#: part/templates/part/navbar.html:74 part/templates/part/order_prices.html:12 msgid "Order Price Information" msgstr "" -#: part/templates/part/navbar.html:75 +#: part/templates/part/navbar.html:77 msgid "Order Price" msgstr "" -#: part/templates/part/navbar.html:98 +#: part/templates/part/navbar.html:103 part/templates/part/order_prices.html:93 +#: part/templates/part/part_pricing.html:82 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/navbar.html:106 msgid "Sales Price Information" msgstr "" -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:120 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:123 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:127 part/templates/part/navbar.html:130 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:139 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 +#: part/templates/part/order_prices.html:24 +#: part/templates/part/part_base.html:282 +msgid "Calculate" +msgstr "" + +#: part/templates/part/order_prices.html:31 msgid "Pricing ranges" msgstr "" -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 +#: part/templates/part/order_prices.html:36 +#: part/templates/part/part_pricing.html:22 msgid "Supplier Pricing" msgstr "" -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 +#: part/templates/part/order_prices.html:37 +#: part/templates/part/order_prices.html:62 +#: part/templates/part/order_prices.html:94 +#: part/templates/part/order_prices.html:108 +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 msgid "Unit Cost" msgstr "" -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 +#: part/templates/part/order_prices.html:44 +#: part/templates/part/order_prices.html:69 +#: part/templates/part/order_prices.html:99 +#: part/templates/part/order_prices.html:113 +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 msgid "Total Cost" msgstr "" -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 +#: part/templates/part/order_prices.html:52 +#: part/templates/part/part_pricing.html:40 msgid "No supplier pricing available" msgstr "" -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 +#: part/templates/part/order_prices.html:61 +#: part/templates/part/order_prices.html:128 +#: part/templates/part/part_pricing.html:48 msgid "BOM Pricing" msgstr "" -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 +#: part/templates/part/order_prices.html:77 +#: part/templates/part/part_pricing.html:66 msgid "Note: BOM pricing is incomplete for this part" msgstr "" -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 +#: part/templates/part/order_prices.html:84 +#: part/templates/part/part_pricing.html:73 msgid "No BOM pricing available" msgstr "" -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 +#: part/templates/part/order_prices.html:122 +#: part/templates/part/part_pricing.html:113 msgid "No pricing information is available for this part." msgstr "" -#: part/templates/part/order_prices.html:113 +#: part/templates/part/order_prices.html:138 msgid "Stock Pricing" msgstr "" -#: part/templates/part/order_prices.html:121 +#: part/templates/part/order_prices.html:146 msgid "No stock pricing history is available for this part." msgstr "" -#: part/templates/part/order_prices.html:140 +#: part/templates/part/order_prices.html:165 #, python-format msgid "Single Price - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:152 +#: part/templates/part/order_prices.html:177 #, python-format msgid "Single Price Difference - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:163 +#: part/templates/part/order_prices.html:189 #, python-format msgid "Part Single Price - %(currency)s" msgstr "" @@ -4630,19 +4755,6 @@ msgstr "" msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4660,7 +4772,7 @@ msgid "Part List" msgstr "" #: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: templates/js/company.js:355 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4740,14 +4852,10 @@ msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 -msgid "Calculate" -msgstr "" - #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" @@ -4816,7 +4924,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,7 +4961,7 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" @@ -4922,227 +5030,239 @@ msgstr "" msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:925 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 +#: part/views.py:1027 msgid "Upload Part Image" msgstr "" -#: part/views.py:1022 part/views.py:1057 +#: part/views.py:1033 part/views.py:1068 msgid "Updated part image" msgstr "" -#: part/views.py:1031 +#: part/views.py:1042 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1071 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1082 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1117 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1147 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1168 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1189 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1200 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1334 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1695 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1720 part/views.py:1723 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1729 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1767 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1773 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1777 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2039 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2046 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2055 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2196 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2206 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2213 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2221 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2271 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2285 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 +#: part/views.py:2345 msgid "Edit Part Category" msgstr "" -#: part/views.py:2365 +#: part/views.py:2383 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2389 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2441 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2542 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2598 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2617 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2687 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 +#: part/views.py:2743 msgid "Confim BOM item deletion" msgstr "" -#: report/models.py:180 +#: part/views.py:2831 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2839 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5174,7 +5294,7 @@ msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:195 templates/js/stock.js:1012 msgid "Date" msgstr "" @@ -5197,7 +5317,7 @@ msgid "Moved {n} parts to {loc}" msgstr "" #: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" @@ -5483,12 +5603,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5738,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:593 msgid "No location set" msgstr "" @@ -5630,25 +5750,29 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" @@ -5945,7 +6069,7 @@ msgstr "" msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:1001 users/models.py:187 msgid "Add" msgstr "" @@ -6011,7 +6135,7 @@ msgstr "" msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1575 templates/js/build.js:326 msgid "Create new Stock Item" msgstr "" @@ -6043,14 +6167,6 @@ msgstr "" msgid "Add Stock Tracking Entry" msgstr "" -#: templates/403.html:5 templates/403.html:11 -msgid "Permission Denied" -msgstr "" - -#: templates/403.html:14 -msgid "You do not have permission to view this page." -msgstr "" - #: templates/404.html:5 templates/404.html:11 msgid "Page Not Found" msgstr "" @@ -6119,11 +6235,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6284,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:85 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:86 msgid "Delete Template" msgstr "" @@ -6221,11 +6337,11 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 +#: templates/InvenTree/settings/part.html:44 msgid "Part Parameter Templates" msgstr "" -#: templates/InvenTree/settings/part.html:61 +#: templates/InvenTree/settings/part.html:65 msgid "No part parameter templates found" msgstr "" @@ -6341,47 +6457,51 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 +#: templates/about.html:100 templates/js/modals.js:568 +#: templates/js/modals.js:861 templates/modals.html:29 templates/modals.html:54 #: templates/modals.html:97 msgid "Close" msgstr "" @@ -6442,7 +6562,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:921 msgid "Invalid server response" msgstr "" @@ -6506,7 +6626,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1091 msgid "Open subassembly" msgstr "" @@ -6542,7 +6662,7 @@ msgstr "" msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:470 templates/js/build.js:423 templates/js/build.js:1189 msgid "No BOM items found" msgstr "" @@ -6562,37 +6682,45 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:382 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:325 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:644 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:665 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:735 templates/js/build.js:1153 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:788 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:805 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:966 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:825 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:924 msgid "No parts allocated for" msgstr "" @@ -6612,17 +6740,29 @@ msgstr "" msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:148 templates/js/company.js:347 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:152 templates/js/company.js:351 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:226 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:262 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:263 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:328 msgid "No supplier parts found" msgstr "" @@ -6710,76 +6850,76 @@ msgstr "" msgid "Loading Data" msgstr "" -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:567 templates/js/modals.js:860 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:824 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:921 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 +#: templates/js/modals.js:931 msgid "No Response" msgstr "" -#: templates/js/modals.js:912 +#: templates/js/modals.js:932 msgid "No response from the InvenTree server" msgstr "" -#: templates/js/modals.js:916 +#: templates/js/modals.js:936 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:937 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 +#: templates/js/modals.js:941 msgid "Error 401: Not Authenticated" msgstr "" -#: templates/js/modals.js:922 +#: templates/js/modals.js:942 msgid "Authentication credentials not supplied" msgstr "" -#: templates/js/modals.js:926 +#: templates/js/modals.js:946 msgid "Error 403: Permission Denied" msgstr "" -#: templates/js/modals.js:927 +#: templates/js/modals.js:947 msgid "You do not have the required permissions to access this function" msgstr "" -#: templates/js/modals.js:931 +#: templates/js/modals.js:951 msgid "Error 404: Resource Not Found" msgstr "" -#: templates/js/modals.js:932 +#: templates/js/modals.js:952 msgid "The requested resource could not be located on the server" msgstr "" -#: templates/js/modals.js:936 +#: templates/js/modals.js:956 msgid "Error 408: Timeout" msgstr "" -#: templates/js/modals.js:937 +#: templates/js/modals.js:957 msgid "Connection timeout while requesting data from server" msgstr "" -#: templates/js/modals.js:940 +#: templates/js/modals.js:960 msgid "Error requesting form data" msgstr "" @@ -6795,6 +6935,10 @@ msgstr "" msgid "No sales orders found" msgstr "" +#: templates/js/order.js:343 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +6967,39 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:323 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:990 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:806 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7097,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:853 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:868 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:882 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:883 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1022 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1069 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1088 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1107 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1125 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1148 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1156 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1188 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1200 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1201 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1325 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1366 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1389 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1417 msgid "Uninstall Stock Item" msgstr "" @@ -7267,56 +7411,56 @@ msgstr "" msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" @@ -7560,35 +7704,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:174 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:182 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:187 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:191 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/it/LC_MESSAGES/django.po b/InvenTree/locale/it/LC_MESSAGES/django.po index 6caf5cb88d..87d69fb09a 100644 --- a/InvenTree/locale/it/LC_MESSAGES/django.po +++ b/InvenTree/locale/it/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:40\n" +"POT-Creation-Date: 2021-06-24 21:38+0000\n" +"PO-Revision-Date: 2021-06-24 21:40\n" "Last-Translator: \n" "Language-Team: Italian\n" "Language: it_IT\n" @@ -77,7 +77,7 @@ msgstr "" msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 +#: InvenTree/helpers.py:384 order/models.py:248 order/models.py:358 #: stock/views.py:1795 msgid "Invalid quantity provided" msgstr "" @@ -122,9 +122,9 @@ msgstr "" msgid "File comment" msgstr "" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:2022 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1179 msgid "User" msgstr "" @@ -132,34 +132,35 @@ msgstr "" msgid "upload date" msgstr "" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:107 InvenTree/models.py:108 company/models.py:396 +#: label/models.py:102 part/models.py:671 part/models.py:2163 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:235 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:972 msgid "Name" msgstr "" #: InvenTree/models.py:114 build/models.py:135 #: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: company/models.py:532 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 #: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: order/models.py:104 order/templates/order/purchase_order_detail.html:147 +#: part/models.py:695 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 +#: templates/js/build.js:833 templates/js/build.js:1101 #: templates/js/company.js:56 templates/js/order.js:183 #: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:984 +#: templates/js/stock.js:1029 msgid "Description" msgstr "" @@ -191,15 +192,15 @@ msgstr "" msgid "Turkish" msgstr "" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "" @@ -372,27 +373,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "" @@ -445,11 +446,11 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 order/forms.py:114 order/forms.py:149 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 +#: templates/js/build.js:880 templates/js/order.js:200 #: templates/js/order.js:298 msgid "Target Date" msgstr "" @@ -462,22 +463,21 @@ msgstr "" #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 +#: build/templates/build/detail.html:31 common/models.py:720 +#: company/forms.py:191 company/templates/company/supplier_part_pricing.html:77 +#: order/forms.py:193 order/forms.py:211 order/forms.py:246 order/forms.py:268 +#: order/forms.py:285 order/models.py:617 order/models.py:841 #: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/order_wizard/select_parts.html:34 #: order/templates/order/purchase_order_detail.html:179 #: order/templates/order/sales_order_detail.html:70 #: order/templates/order/sales_order_detail.html:77 #: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 +#: order/templates/order/sales_order_detail.html:234 part/forms.py:342 +#: part/forms.py:372 part/forms.py:388 part/forms.py:404 part/models.py:2293 +#: part/templates/part/internal_prices.html:98 +#: part/templates/part/order_prices.html:202 +#: part/templates/part/part_pricing.html:16 #: part/templates/part/sale_prices.html:85 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 @@ -486,9 +486,10 @@ msgstr "" #: stock/forms.py:175 stock/forms.py:308 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:571 +#: templates/js/build.js:1111 templates/js/order.js:393 +#: templates/js/part.js:796 templates/js/stock.js:1164 +#: templates/js/stock.js:1383 msgid "Quantity" msgstr "" @@ -500,7 +501,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:240 stock/forms.py:118 msgid "Serial Numbers" msgstr "" @@ -529,12 +530,12 @@ msgid "Mark build as complete" msgstr "" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:347 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:585 templates/js/order.js:378 +#: templates/js/stock.js:643 templates/js/stock.js:1056 msgid "Location" msgstr "" @@ -543,13 +544,13 @@ msgid "Location of completed parts" msgstr "" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:469 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:867 #: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: templates/js/stock.js:630 templates/js/stock.js:1133 +#: templates/js/stock.js:1399 msgid "Status" msgstr "" @@ -583,16 +584,16 @@ msgstr "" #: build/models.py:66 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "" #: build/models.py:67 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:57 +#: part/templates/part/navbar.html:60 templates/InvenTree/index.html:183 #: templates/InvenTree/search.html:185 #: templates/InvenTree/settings/tabs.html:34 users/models.py:43 msgid "Build Orders" @@ -602,12 +603,12 @@ msgstr "" msgid "Build Order Reference" msgstr "" -#: build/models.py:128 order/models.py:101 order/models.py:618 +#: build/models.py:128 order/models.py:102 order/models.py:619 #: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: order/templates/order/sales_order_detail.html:229 part/models.py:2302 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:660 templates/js/build.js:1105 msgid "Reference" msgstr "" @@ -626,27 +627,27 @@ msgstr "" #: build/models.py:153 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 +#: build/templates/build/detail.html:26 company/models.py:663 +#: order/models.py:661 order/models.py:717 +#: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:132 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:214 part/models.py:321 +#: part/models.py:1975 part/models.py:1987 part/models.py:2002 +#: part/models.py:2020 part/models.py:2095 part/models.py:2191 +#: part/models.py:2277 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:551 templates/js/build.js:838 +#: templates/js/build.js:1078 templates/js/company.js:140 +#: templates/js/company.js:339 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1371 msgid "Part" msgstr "" @@ -710,16 +711,16 @@ msgstr "" msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 +#: build/models.py:220 order/models.py:108 part/models.py:867 #: part/templates/part/detail.html:126 templates/js/order.js:293 msgid "Creation Date" msgstr "" -#: build/models.py:224 order/models.py:474 +#: build/models.py:224 order/models.py:475 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:228 order/models.py:221 templates/js/build.js:885 msgid "Completion Date" msgstr "" @@ -736,9 +737,9 @@ msgid "User who issued this build order" msgstr "" #: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/templates/build/detail.html:105 order/models.py:122 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:871 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "" @@ -757,26 +758,26 @@ msgstr "" msgid "External Link" msgstr "" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:258 part/models.py:729 stock/models.py:462 msgid "Link to external URL" msgstr "" #: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: company/models.py:132 company/models.py:539 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:126 +#: order/models.py:621 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:243 +#: order/templates/order/sales_order_detail.html:309 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:856 +#: part/templates/part/navbar.html:142 #: report/templates/report/inventree_build_order_base.html:173 #: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 #: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:699 msgid "Notes" msgstr "" @@ -809,11 +810,11 @@ msgstr "" msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1188 order/models.py:815 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1192 order/models.py:818 msgid "Allocation quantity must be greater than zero" msgstr "" @@ -827,7 +828,7 @@ msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" #: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: templates/InvenTree/search.html:183 templates/js/build.js:811 #: templates/navbar.html:29 msgid "Build" msgstr "" @@ -836,15 +837,13 @@ msgstr "" msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1333 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:928 +#: templates/js/order.js:366 templates/js/order.js:371 +#: templates/js/stock.js:1115 msgid "Stock Item" msgstr "" @@ -880,7 +879,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:743 msgid "Unallocate stock" msgstr "" @@ -917,15 +916,15 @@ msgstr "" #: order/templates/order/sales_order_detail.html:160 #: report/templates/report/inventree_test_report_base.html:75 #: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: templates/js/build.js:569 msgid "Serial Number" msgstr "" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:133 +#: part/templates/part/navbar.html:136 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "" @@ -1037,11 +1036,10 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:715 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 #: stock/templates/stock/item_base.html:279 templates/js/order.js:245 @@ -1185,7 +1183,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:85 order/models.py:678 +#: order/templates/order/purchase_order_detail.html:239 +#: order/templates/order/receive_parts.html:25 stock/forms.py:169 +#: stock/forms.py:375 msgid "Destination" msgstr "" @@ -1194,15 +1195,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1406 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:875 msgid "Created" msgstr "" @@ -1210,7 +1211,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:853 msgid "Completed" msgstr "" @@ -1248,9 +1249,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:17 +#: templates/js/stock.js:1044 msgid "Details" msgstr "" @@ -1285,8 +1286,8 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 +#: stock/templates/stock/item_base.html:497 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "" @@ -1411,8 +1412,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:670 +#: templates/js/build.js:935 templates/js/build.js:1118 msgid "Available" msgstr "" @@ -1598,8 +1599,8 @@ msgstr "" msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 +#: common/models.py:153 part/models.py:2193 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:259 templates/js/table_filters.js:25 #: templates/js/table_filters.js:315 msgid "Template" msgstr "" @@ -1608,7 +1609,7 @@ msgstr "" msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 +#: common/models.py:160 part/models.py:819 part/templates/part/detail.html:170 #: templates/js/table_filters.js:128 templates/js/table_filters.js:327 msgid "Assembly" msgstr "" @@ -1617,7 +1618,7 @@ msgstr "" msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 +#: common/models.py:167 part/models.py:825 part/templates/part/detail.html:180 #: templates/js/table_filters.js:331 msgid "Component" msgstr "" @@ -1626,7 +1627,7 @@ msgstr "" msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:174 part/models.py:836 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" @@ -1634,7 +1635,7 @@ msgstr "" msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 +#: common/models.py:181 part/models.py:841 part/templates/part/detail.html:210 #: templates/js/table_filters.js:339 msgid "Salable" msgstr "" @@ -1643,7 +1644,7 @@ msgstr "" msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 +#: common/models.py:188 part/models.py:831 part/templates/part/detail.html:190 #: templates/js/table_filters.js:33 templates/js/table_filters.js:343 msgid "Trackable" msgstr "" @@ -1652,7 +1653,7 @@ msgstr "" msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:195 part/models.py:851 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" @@ -1669,160 +1670,185 @@ msgstr "" msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" +#: common/models.py:209 +msgid "Show Price in Forms" msgstr "" #: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" +msgid "Display part price in some forms" msgstr "" #: common/models.py:216 -msgid "Page Size" +msgid "Internal Prices" msgstr "" #: common/models.py:217 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:223 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:224 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:230 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:231 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:237 +msgid "Page Size" +msgstr "" + +#: common/models.py:238 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:248 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:249 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:255 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:256 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:262 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:263 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:269 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:270 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:272 part/templates/part/detail.html:121 msgid "days" msgstr "" -#: common/models.py:256 +#: common/models.py:277 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:278 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:284 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:285 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:291 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:292 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:298 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:299 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:305 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:306 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:311 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:312 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:316 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:317 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:322 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:323 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:546 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:548 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:583 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:606 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:617 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:640 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:721 company/forms.py:192 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 +#: common/models.py:729 company/templates/company/supplier_part_pricing.html:82 +#: part/templates/part/internal_prices.html:103 #: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:730 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:822 msgid "Default" msgstr "" @@ -1843,7 +1869,9 @@ msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:582 +#: part/templates/part/bom_upload/upload_file.html:27 msgid "Upload File" msgstr "" @@ -1877,29 +1905,29 @@ msgstr "" msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:133 templates/js/part.js:787 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:135 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:143 company/models.py:321 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:149 company/models.py:328 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:151 company/models.py:327 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 #: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:408 msgid "MPN" msgstr "" @@ -1952,11 +1980,11 @@ msgstr "" msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:121 company/models.py:333 company/models.py:526 +#: order/models.py:106 part/models.py:728 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:188 templates/js/company.js:419 +#: templates/js/part.js:498 msgid "Link" msgstr "" @@ -1964,7 +1992,7 @@ msgstr "" msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:129 part/models.py:738 msgid "Image" msgstr "" @@ -1992,12 +2020,12 @@ msgstr "" msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:305 company/models.py:497 stock/models.py:407 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:309 company/models.py:501 order/views.py:1597 msgid "Select part" msgstr "" @@ -2008,7 +2036,7 @@ msgstr "" #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 #: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:390 msgid "Manufacturer" msgstr "" @@ -2020,87 +2048,112 @@ msgstr "" msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:390 company/models.py:520 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:397 +msgid "Parameter name" +msgstr "" + +#: company/models.py:403 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:241 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:404 +msgid "Parameter value" +msgstr "" + +#: company/models.py:410 part/models.py:813 part/models.py:2165 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:247 +msgid "Units" +msgstr "" + +#: company/models.py:411 +msgid "Parameter units" +msgstr "" + +#: company/models.py:507 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:193 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:48 templates/js/company.js:364 #: templates/js/order.js:170 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:508 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:513 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 #: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:514 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:521 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:527 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:533 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:538 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2305 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 +#: company/models.py:544 company/templates/company/supplier_part_base.html:109 #: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: templates/js/stock.js:695 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:544 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:546 part/models.py:1608 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:546 msgid "Order multiple" msgstr "" #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:562 msgid "Assigned Stock" msgstr "" @@ -2165,11 +2218,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 +#: company/templates/company/detail.html:67 order/models.py:464 #: order/templates/order/sales_order_base.html:94 stock/models.py:449 #: stock/models.py:450 stock/templates/stock/item_base.html:262 #: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: templates/js/stock.js:1097 msgid "Customer" msgstr "" @@ -2215,7 +2268,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:66 #: company/templates/company/detail_supplier_part.html:66 #: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: templates/js/stock.js:1312 msgid "New Part" msgstr "" @@ -2248,13 +2301,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 +#: order/templates/order/order_wizard/select_parts.html:44 #: order/templates/order/purchase_order_detail.html:50 msgid "Create new supplier part" msgstr "" @@ -2262,12 +2314,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 #: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/supplier.html:17 templates/js/stock.js:1318 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 +#: company/templates/company/manufacturer_part_suppliers.html:82 #: company/views.py:64 order/templates/order/purchase_orders.html:185 #: part/templates/part/supplier.html:50 msgid "New Supplier" @@ -2319,8 +2371,9 @@ msgid "There are %(count)s suppliers defined for this manufacturer part. If you msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:63 part/templates/part/navbar.html:86 +#: part/templates/part/navbar.html:89 templates/InvenTree/search.html:316 #: templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,13 +2385,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:38 stock/api.py:54 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2360,11 +2413,25 @@ msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:1002 users/models.py:191 msgid "Delete" msgstr "" -#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:34 +#: part/templates/part/category_navbar.html:37 +#: part/templates/part/navbar.html:24 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:48 +msgid "New Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:83 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" @@ -2379,13 +2446,13 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:35 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 +#: templates/InvenTree/search.html:198 templates/js/stock.js:996 #: templates/stats.html:93 templates/stats.html:102 users/models.py:42 msgid "Stock Items" msgstr "" @@ -2396,7 +2463,7 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 +#: part/templates/part/navbar.html:112 part/templates/part/navbar.html:115 #: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 @@ -2408,7 +2475,7 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 +#: part/templates/part/navbar.html:92 part/templates/part/navbar.html:95 #: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 @@ -2442,7 +2509,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:7 #: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:380 msgid "Supplier Part" msgstr "" @@ -2490,8 +2557,8 @@ msgstr "" msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 company/views.py:855 +#: part/templates/part/sale_prices.html:17 part/views.py:2751 msgid "Add Price Break" msgstr "" @@ -2510,8 +2577,8 @@ msgstr "" msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 +#: company/views.py:70 part/templates/part/navbar.html:80 +#: part/templates/part/navbar.html:83 templates/InvenTree/search.html:306 #: templates/navbar.html:36 msgid "Manufacturers" msgstr "" @@ -2533,20 +2600,20 @@ msgstr "" msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:169 part/views.py:948 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:198 part/views.py:980 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:205 part/views.py:987 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:214 part/views.py:996 msgid "Supplied URL is not a valid image file" msgstr "" @@ -2594,27 +2661,35 @@ msgstr "" msgid "Delete Manufacturer Part" msgstr "" -#: company/views.py:528 +#: company/views.py:514 +msgid "Add Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:548 +msgid "Edit Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:588 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:639 templates/js/stock.js:1319 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:783 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 +#: company/views.py:860 part/views.py:2755 msgid "Added new price break" msgstr "" -#: company/views.py:855 part/views.py:2781 +#: company/views.py:916 part/views.py:2799 msgid "Edit Price Break" msgstr "" -#: company/views.py:870 part/views.py:2795 +#: company/views.py:931 part/views.py:2813 msgid "Delete Price Break" msgstr "" @@ -2638,7 +2713,7 @@ msgstr "" msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:124 report/models.py:297 msgid "Enabled" msgstr "" @@ -2662,7 +2737,7 @@ msgstr "" msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:144 report/models.py:290 msgid "Filename Pattern" msgstr "" @@ -2674,8 +2749,8 @@ msgstr "" msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:245 label/models.py:298 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" @@ -2696,237 +2771,239 @@ msgstr "" msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:86 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 +#: order/forms.py:108 msgid "Purchase Order reference" msgstr "" -#: order/forms.py:110 +#: order/forms.py:115 msgid "Target date for order delivery. Order will be overdue after this date." msgstr "" -#: order/forms.py:138 +#: order/forms.py:143 msgid "Enter sales order number" msgstr "" -#: order/forms.py:145 order/models.py:475 +#: order/forms.py:150 order/models.py:476 msgid "Target date for order completion. Order will be overdue after this date." msgstr "" -#: order/forms.py:236 +#: order/forms.py:242 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:248 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 +#: order/models.py:102 msgid "Order reference" msgstr "" -#: order/models.py:103 +#: order/models.py:104 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:106 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:114 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:121 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:126 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:185 order/models.py:469 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:194 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 +#: order/models.py:197 order/templates/order/order_base.html:98 #: templates/js/order.js:179 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:197 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:204 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:209 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:210 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:215 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:216 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:222 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 +#: order/models.py:246 part/views.py:1686 stock/models.py:304 #: stock/models.py:1020 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:251 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:349 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:353 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:355 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:465 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:479 templates/js/order.js:303 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:486 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:530 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:617 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:619 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:621 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:647 order/models.py:715 templates/js/order.js:353 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:648 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 #: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: templates/js/stock.js:669 templates/js/stock.js:1078 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:662 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 +#: order/models.py:665 order/templates/order/order_base.html:131 #: order/templates/order/purchase_order_detail.html:219 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:665 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:672 stock/models.py:542 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:690 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:673 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:681 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:724 part/templates/part/navbar.html:109 +#: part/templates/part/order_prices.html:107 +#: part/templates/part/part_pricing.html:97 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:725 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:800 order/models.py:802 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:806 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:808 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:811 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:821 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:826 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:837 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:838 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:841 msgid "Enter stock allocation quantity" msgstr "" @@ -2955,7 +3032,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2977,8 +3054,8 @@ msgstr "" #: order/templates/order/order_base.html:180 #: order/templates/order/purchase_order_detail.html:100 #: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: stock/templates/stock/location.html:191 templates/js/stock.js:736 +#: templates/js/stock.js:1324 msgid "New Location" msgstr "" @@ -3081,28 +3158,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3135,15 +3216,20 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +#: order/templates/order/so_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,8 +3239,8 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/sales_order_detail.html:22 order/views.py:1321 +#: order/views.py:1404 msgid "Add Line Item" msgstr "" @@ -3162,25 +3248,31 @@ msgstr "" msgid "No line items found" msgstr "" +#: order/templates/order/purchase_order_detail.html:142 +#: order/templates/order/sales_order_detail.html:223 +msgid "Total" +msgstr "" + #: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/sales_order_detail.html:246 msgid "Unit Price" msgstr "" #: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/sales_order_detail.html:253 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:255 +#: order/templates/order/sales_order_detail.html:359 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:256 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:261 msgid "Receive line item" msgstr "" @@ -3201,7 +3293,7 @@ msgstr "" #: part/templates/part/category_navbar.html:29 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 #: users/models.py:40 msgid "Parts" @@ -3216,7 +3308,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3316,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3265,17 +3357,17 @@ msgid "Sales Order Items" msgstr "" #: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: templates/js/build.js:724 templates/js/build.js:1141 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:610 +#: templates/js/build.js:946 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:612 +#: templates/js/build.js:947 msgid "Delete stock allocation" msgstr "" @@ -3283,50 +3375,50 @@ msgstr "" msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:206 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:274 templates/js/build.js:675 +#: templates/js/build.js:942 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:276 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:313 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:343 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:346 templates/js/build.js:738 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:349 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:353 templates/js/build.js:731 +#: templates/js/build.js:1149 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:356 +#: order/templates/order/sales_order_detail.html:465 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:360 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:471 msgid "Update Unit Price" msgstr "" @@ -3367,10 +3459,6 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - #: order/views.py:104 msgid "Add Purchase Order Attachment" msgstr "" @@ -3471,90 +3559,94 @@ msgstr "" msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:1012 +msgid "Update prices" +msgstr "" + +#: order/views.py:1270 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 +#: order/views.py:1330 msgid "Supplier part must be specified" msgstr "" -#: order/views.py:1326 +#: order/views.py:1336 msgid "Supplier must match for Part and Order" msgstr "" -#: order/views.py:1457 order/views.py:1475 +#: order/views.py:1467 order/views.py:1485 msgid "Edit Line Item" msgstr "" -#: order/views.py:1491 order/views.py:1503 +#: order/views.py:1501 order/views.py:1513 msgid "Delete Line Item" msgstr "" -#: order/views.py:1496 order/views.py:1508 +#: order/views.py:1506 order/views.py:1518 msgid "Deleted line item" msgstr "" -#: order/views.py:1521 +#: order/views.py:1531 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1576 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1592 msgid "Select line item" msgstr "" -#: order/views.py:1613 -#, python-brace-format -msgid "No matching item for serial {serial}" -msgstr "" - #: order/views.py:1623 #, python-brace-format +msgid "No matching item for serial {serial}" +msgstr "" + +#: order/views.py:1633 +#, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1641 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1695 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1769 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1784 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1856 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1862 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1865 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1870 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 +#: part/bom.py:138 part/models.py:72 part/models.py:747 #: part/templates/part/category.html:66 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3632,7 +3724,7 @@ msgstr "" msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:122 part/models.py:2191 msgid "Parent Part" msgstr "" @@ -3708,7 +3800,7 @@ msgstr "" msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:344 part/models.py:2286 msgid "Sub part" msgstr "" @@ -3728,7 +3820,7 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:82 part/models.py:2237 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" @@ -3739,365 +3831,360 @@ msgstr "" msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:448 part/models.py:460 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:557 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:561 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:566 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:645 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:670 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:677 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:678 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:689 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:690 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:696 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:701 part/templates/part/category.html:73 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:702 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:709 part/models.py:2236 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:710 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:715 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "" -#: part/models.py:731 +#: part/models.py:716 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:722 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:723 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:745 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:792 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:793 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:800 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:801 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:806 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:807 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:814 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:820 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:826 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:832 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:837 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:842 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:846 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 #: templates/js/table_filters.js:241 templates/js/table_filters.js:310 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:847 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:852 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:857 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:863 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:865 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:869 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1608 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2063 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2080 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2100 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2101 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2106 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2107 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 +#: part/models.py:2112 templates/js/part.js:726 #: templates/js/table_filters.js:227 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2113 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2118 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2119 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2124 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2125 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2158 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2163 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2165 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2193 part/models.py:2242 part/models.py:2243 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2247 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2248 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2278 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2287 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2293 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2295 templates/js/bom.js:216 templates/js/bom.js:285 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2295 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2298 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2299 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2302 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2305 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2311 templates/js/bom.js:302 templates/js/bom.js:309 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2312 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2317 templates/js/bom.js:294 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2318 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 +#: part/models.py:2394 part/views.py:1692 part/views.py:1744 #: stock/models.py:294 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2403 part/models.py:2405 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2408 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2527 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2563 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 @@ -4112,8 +4199,8 @@ msgstr "" msgid "Deleting this entry will remove the BOM row from the following part" msgstr "" -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:50 +#: part/templates/part/navbar.html:53 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4247,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:1987 msgid "Export Bill of Materials" msgstr "" @@ -4177,7 +4264,7 @@ msgid "All selected BOM items will be deleted" msgstr "" #: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: templates/js/stock.js:1313 msgid "Create New Part" msgstr "" @@ -4258,7 +4345,7 @@ msgstr "" msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:29 part/views.py:2397 msgid "Create new part category" msgstr "" @@ -4318,7 +4405,7 @@ msgid "View grid display" msgstr "" #: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: stock/templates/stock/location.html:192 templates/js/stock.js:737 msgid "Create new location" msgstr "" @@ -4373,14 +4460,8 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 -#: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" -msgstr "" - #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:21 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" @@ -4408,7 +4489,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:13 msgid "Part Details" msgstr "" @@ -4488,6 +4569,36 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/internal_prices.html:11 +#: part/templates/part/navbar.html:100 +msgid "Internal Price Information" +msgstr "" + +#: part/templates/part/internal_prices.html:19 part/views.py:2822 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/internal_prices.html:28 templates/403.html:5 +#: templates/403.html:11 +msgid "Permission Denied" +msgstr "" + +#: part/templates/part/internal_prices.html:31 templates/403.html:14 +msgid "You do not have permission to view this page." +msgstr "" + +#: part/templates/part/internal_prices.html:59 +msgid "No internal price break information found" +msgstr "" + +#: part/templates/part/internal_prices.html:110 +msgid "Edit internal price break" +msgstr "" + +#: part/templates/part/internal_prices.html:111 +msgid "Delete internal price break" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4501,127 +4612,141 @@ msgstr "" msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:28 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:31 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:42 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:45 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:66 part/templates/part/navbar.html:69 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 +#: part/templates/part/navbar.html:74 part/templates/part/order_prices.html:12 msgid "Order Price Information" msgstr "" -#: part/templates/part/navbar.html:75 +#: part/templates/part/navbar.html:77 msgid "Order Price" msgstr "" -#: part/templates/part/navbar.html:98 +#: part/templates/part/navbar.html:103 part/templates/part/order_prices.html:93 +#: part/templates/part/part_pricing.html:82 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/navbar.html:106 msgid "Sales Price Information" msgstr "" -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:120 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:123 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:127 part/templates/part/navbar.html:130 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:139 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 +#: part/templates/part/order_prices.html:24 +#: part/templates/part/part_base.html:282 +msgid "Calculate" +msgstr "" + +#: part/templates/part/order_prices.html:31 msgid "Pricing ranges" msgstr "" -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 +#: part/templates/part/order_prices.html:36 +#: part/templates/part/part_pricing.html:22 msgid "Supplier Pricing" msgstr "" -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 +#: part/templates/part/order_prices.html:37 +#: part/templates/part/order_prices.html:62 +#: part/templates/part/order_prices.html:94 +#: part/templates/part/order_prices.html:108 +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 msgid "Unit Cost" msgstr "" -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 +#: part/templates/part/order_prices.html:44 +#: part/templates/part/order_prices.html:69 +#: part/templates/part/order_prices.html:99 +#: part/templates/part/order_prices.html:113 +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 msgid "Total Cost" msgstr "" -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 +#: part/templates/part/order_prices.html:52 +#: part/templates/part/part_pricing.html:40 msgid "No supplier pricing available" msgstr "" -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 +#: part/templates/part/order_prices.html:61 +#: part/templates/part/order_prices.html:128 +#: part/templates/part/part_pricing.html:48 msgid "BOM Pricing" msgstr "" -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 +#: part/templates/part/order_prices.html:77 +#: part/templates/part/part_pricing.html:66 msgid "Note: BOM pricing is incomplete for this part" msgstr "" -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 +#: part/templates/part/order_prices.html:84 +#: part/templates/part/part_pricing.html:73 msgid "No BOM pricing available" msgstr "" -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 +#: part/templates/part/order_prices.html:122 +#: part/templates/part/part_pricing.html:113 msgid "No pricing information is available for this part." msgstr "" -#: part/templates/part/order_prices.html:113 +#: part/templates/part/order_prices.html:138 msgid "Stock Pricing" msgstr "" -#: part/templates/part/order_prices.html:121 +#: part/templates/part/order_prices.html:146 msgid "No stock pricing history is available for this part." msgstr "" -#: part/templates/part/order_prices.html:140 +#: part/templates/part/order_prices.html:165 #, python-format msgid "Single Price - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:152 +#: part/templates/part/order_prices.html:177 #, python-format msgid "Single Price Difference - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:163 +#: part/templates/part/order_prices.html:189 #, python-format msgid "Part Single Price - %(currency)s" msgstr "" @@ -4630,19 +4755,6 @@ msgstr "" msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4660,7 +4772,7 @@ msgid "Part List" msgstr "" #: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: templates/js/company.js:355 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4740,14 +4852,10 @@ msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 -msgid "Calculate" -msgstr "" - #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" @@ -4816,7 +4924,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,7 +4961,7 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" @@ -4922,227 +5030,239 @@ msgstr "" msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:925 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 +#: part/views.py:1027 msgid "Upload Part Image" msgstr "" -#: part/views.py:1022 part/views.py:1057 +#: part/views.py:1033 part/views.py:1068 msgid "Updated part image" msgstr "" -#: part/views.py:1031 +#: part/views.py:1042 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1071 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1082 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1117 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1147 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1168 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1189 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1200 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1334 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1695 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1720 part/views.py:1723 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1729 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1767 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1773 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1777 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2039 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2046 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2055 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2196 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2206 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2213 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2221 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2271 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2285 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 +#: part/views.py:2345 msgid "Edit Part Category" msgstr "" -#: part/views.py:2365 +#: part/views.py:2383 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2389 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2441 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2542 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2598 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2617 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2687 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 +#: part/views.py:2743 msgid "Confim BOM item deletion" msgstr "" -#: report/models.py:180 +#: part/views.py:2831 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2839 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5174,7 +5294,7 @@ msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:195 templates/js/stock.js:1012 msgid "Date" msgstr "" @@ -5197,7 +5317,7 @@ msgid "Moved {n} parts to {loc}" msgstr "" #: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" @@ -5483,12 +5603,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5738,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:593 msgid "No location set" msgstr "" @@ -5630,25 +5750,29 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" @@ -5945,7 +6069,7 @@ msgstr "" msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:1001 users/models.py:187 msgid "Add" msgstr "" @@ -6011,7 +6135,7 @@ msgstr "" msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1575 templates/js/build.js:326 msgid "Create new Stock Item" msgstr "" @@ -6043,14 +6167,6 @@ msgstr "" msgid "Add Stock Tracking Entry" msgstr "" -#: templates/403.html:5 templates/403.html:11 -msgid "Permission Denied" -msgstr "" - -#: templates/403.html:14 -msgid "You do not have permission to view this page." -msgstr "" - #: templates/404.html:5 templates/404.html:11 msgid "Page Not Found" msgstr "" @@ -6119,11 +6235,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6284,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:85 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:86 msgid "Delete Template" msgstr "" @@ -6221,11 +6337,11 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 +#: templates/InvenTree/settings/part.html:44 msgid "Part Parameter Templates" msgstr "" -#: templates/InvenTree/settings/part.html:61 +#: templates/InvenTree/settings/part.html:65 msgid "No part parameter templates found" msgstr "" @@ -6341,47 +6457,51 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 +#: templates/about.html:100 templates/js/modals.js:568 +#: templates/js/modals.js:861 templates/modals.html:29 templates/modals.html:54 #: templates/modals.html:97 msgid "Close" msgstr "" @@ -6442,7 +6562,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:921 msgid "Invalid server response" msgstr "" @@ -6506,7 +6626,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1091 msgid "Open subassembly" msgstr "" @@ -6542,7 +6662,7 @@ msgstr "" msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:470 templates/js/build.js:423 templates/js/build.js:1189 msgid "No BOM items found" msgstr "" @@ -6562,37 +6682,45 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:382 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:325 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:644 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:665 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:735 templates/js/build.js:1153 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:788 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:805 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:966 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:825 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:924 msgid "No parts allocated for" msgstr "" @@ -6612,17 +6740,29 @@ msgstr "" msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:148 templates/js/company.js:347 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:152 templates/js/company.js:351 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:226 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:262 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:263 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:328 msgid "No supplier parts found" msgstr "" @@ -6710,76 +6850,76 @@ msgstr "" msgid "Loading Data" msgstr "" -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:567 templates/js/modals.js:860 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:824 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:921 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 +#: templates/js/modals.js:931 msgid "No Response" msgstr "" -#: templates/js/modals.js:912 +#: templates/js/modals.js:932 msgid "No response from the InvenTree server" msgstr "" -#: templates/js/modals.js:916 +#: templates/js/modals.js:936 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:937 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 +#: templates/js/modals.js:941 msgid "Error 401: Not Authenticated" msgstr "" -#: templates/js/modals.js:922 +#: templates/js/modals.js:942 msgid "Authentication credentials not supplied" msgstr "" -#: templates/js/modals.js:926 +#: templates/js/modals.js:946 msgid "Error 403: Permission Denied" msgstr "" -#: templates/js/modals.js:927 +#: templates/js/modals.js:947 msgid "You do not have the required permissions to access this function" msgstr "" -#: templates/js/modals.js:931 +#: templates/js/modals.js:951 msgid "Error 404: Resource Not Found" msgstr "" -#: templates/js/modals.js:932 +#: templates/js/modals.js:952 msgid "The requested resource could not be located on the server" msgstr "" -#: templates/js/modals.js:936 +#: templates/js/modals.js:956 msgid "Error 408: Timeout" msgstr "" -#: templates/js/modals.js:937 +#: templates/js/modals.js:957 msgid "Connection timeout while requesting data from server" msgstr "" -#: templates/js/modals.js:940 +#: templates/js/modals.js:960 msgid "Error requesting form data" msgstr "" @@ -6795,6 +6935,10 @@ msgstr "" msgid "No sales orders found" msgstr "" +#: templates/js/order.js:343 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +6967,39 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:323 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:990 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:806 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7097,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:853 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:868 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:882 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:883 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1022 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1069 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1088 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1107 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1125 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1148 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1156 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1188 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1200 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1201 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1325 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1366 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1389 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1417 msgid "Uninstall Stock Item" msgstr "" @@ -7267,56 +7411,56 @@ msgstr "" msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" @@ -7560,35 +7704,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:174 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:182 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:187 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:191 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/ja/LC_MESSAGES/django.po b/InvenTree/locale/ja/LC_MESSAGES/django.po index f5afd1b0fe..fa6df1a934 100644 --- a/InvenTree/locale/ja/LC_MESSAGES/django.po +++ b/InvenTree/locale/ja/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:41\n" +"POT-Creation-Date: 2021-06-24 21:38+0000\n" +"PO-Revision-Date: 2021-06-24 21:40\n" "Last-Translator: \n" "Language-Team: Japanese\n" "Language: ja_JP\n" @@ -77,7 +77,7 @@ msgstr "" msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 +#: InvenTree/helpers.py:384 order/models.py:248 order/models.py:358 #: stock/views.py:1795 msgid "Invalid quantity provided" msgstr "" @@ -122,9 +122,9 @@ msgstr "" msgid "File comment" msgstr "" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:2022 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1179 msgid "User" msgstr "" @@ -132,34 +132,35 @@ msgstr "" msgid "upload date" msgstr "" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:107 InvenTree/models.py:108 company/models.py:396 +#: label/models.py:102 part/models.py:671 part/models.py:2163 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:235 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:972 msgid "Name" msgstr "" #: InvenTree/models.py:114 build/models.py:135 #: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: company/models.py:532 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 #: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: order/models.py:104 order/templates/order/purchase_order_detail.html:147 +#: part/models.py:695 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 +#: templates/js/build.js:833 templates/js/build.js:1101 #: templates/js/company.js:56 templates/js/order.js:183 #: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:984 +#: templates/js/stock.js:1029 msgid "Description" msgstr "" @@ -191,15 +192,15 @@ msgstr "" msgid "Turkish" msgstr "" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "" @@ -372,27 +373,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "" @@ -445,11 +446,11 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 order/forms.py:114 order/forms.py:149 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 +#: templates/js/build.js:880 templates/js/order.js:200 #: templates/js/order.js:298 msgid "Target Date" msgstr "" @@ -462,22 +463,21 @@ msgstr "" #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 +#: build/templates/build/detail.html:31 common/models.py:720 +#: company/forms.py:191 company/templates/company/supplier_part_pricing.html:77 +#: order/forms.py:193 order/forms.py:211 order/forms.py:246 order/forms.py:268 +#: order/forms.py:285 order/models.py:617 order/models.py:841 #: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/order_wizard/select_parts.html:34 #: order/templates/order/purchase_order_detail.html:179 #: order/templates/order/sales_order_detail.html:70 #: order/templates/order/sales_order_detail.html:77 #: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 +#: order/templates/order/sales_order_detail.html:234 part/forms.py:342 +#: part/forms.py:372 part/forms.py:388 part/forms.py:404 part/models.py:2293 +#: part/templates/part/internal_prices.html:98 +#: part/templates/part/order_prices.html:202 +#: part/templates/part/part_pricing.html:16 #: part/templates/part/sale_prices.html:85 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 @@ -486,9 +486,10 @@ msgstr "" #: stock/forms.py:175 stock/forms.py:308 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:571 +#: templates/js/build.js:1111 templates/js/order.js:393 +#: templates/js/part.js:796 templates/js/stock.js:1164 +#: templates/js/stock.js:1383 msgid "Quantity" msgstr "" @@ -500,7 +501,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:240 stock/forms.py:118 msgid "Serial Numbers" msgstr "" @@ -529,12 +530,12 @@ msgid "Mark build as complete" msgstr "" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:347 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:585 templates/js/order.js:378 +#: templates/js/stock.js:643 templates/js/stock.js:1056 msgid "Location" msgstr "" @@ -543,13 +544,13 @@ msgid "Location of completed parts" msgstr "" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:469 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:867 #: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: templates/js/stock.js:630 templates/js/stock.js:1133 +#: templates/js/stock.js:1399 msgid "Status" msgstr "" @@ -583,16 +584,16 @@ msgstr "" #: build/models.py:66 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "" #: build/models.py:67 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:57 +#: part/templates/part/navbar.html:60 templates/InvenTree/index.html:183 #: templates/InvenTree/search.html:185 #: templates/InvenTree/settings/tabs.html:34 users/models.py:43 msgid "Build Orders" @@ -602,12 +603,12 @@ msgstr "" msgid "Build Order Reference" msgstr "" -#: build/models.py:128 order/models.py:101 order/models.py:618 +#: build/models.py:128 order/models.py:102 order/models.py:619 #: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: order/templates/order/sales_order_detail.html:229 part/models.py:2302 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:660 templates/js/build.js:1105 msgid "Reference" msgstr "" @@ -626,27 +627,27 @@ msgstr "" #: build/models.py:153 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 +#: build/templates/build/detail.html:26 company/models.py:663 +#: order/models.py:661 order/models.py:717 +#: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:132 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:214 part/models.py:321 +#: part/models.py:1975 part/models.py:1987 part/models.py:2002 +#: part/models.py:2020 part/models.py:2095 part/models.py:2191 +#: part/models.py:2277 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:551 templates/js/build.js:838 +#: templates/js/build.js:1078 templates/js/company.js:140 +#: templates/js/company.js:339 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1371 msgid "Part" msgstr "" @@ -710,16 +711,16 @@ msgstr "" msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 +#: build/models.py:220 order/models.py:108 part/models.py:867 #: part/templates/part/detail.html:126 templates/js/order.js:293 msgid "Creation Date" msgstr "" -#: build/models.py:224 order/models.py:474 +#: build/models.py:224 order/models.py:475 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:228 order/models.py:221 templates/js/build.js:885 msgid "Completion Date" msgstr "" @@ -736,9 +737,9 @@ msgid "User who issued this build order" msgstr "" #: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/templates/build/detail.html:105 order/models.py:122 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:871 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "" @@ -757,26 +758,26 @@ msgstr "" msgid "External Link" msgstr "" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:258 part/models.py:729 stock/models.py:462 msgid "Link to external URL" msgstr "" #: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: company/models.py:132 company/models.py:539 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:126 +#: order/models.py:621 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:243 +#: order/templates/order/sales_order_detail.html:309 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:856 +#: part/templates/part/navbar.html:142 #: report/templates/report/inventree_build_order_base.html:173 #: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 #: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:699 msgid "Notes" msgstr "" @@ -809,11 +810,11 @@ msgstr "" msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1188 order/models.py:815 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1192 order/models.py:818 msgid "Allocation quantity must be greater than zero" msgstr "" @@ -827,7 +828,7 @@ msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" #: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: templates/InvenTree/search.html:183 templates/js/build.js:811 #: templates/navbar.html:29 msgid "Build" msgstr "" @@ -836,15 +837,13 @@ msgstr "" msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1333 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:928 +#: templates/js/order.js:366 templates/js/order.js:371 +#: templates/js/stock.js:1115 msgid "Stock Item" msgstr "" @@ -880,7 +879,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:743 msgid "Unallocate stock" msgstr "" @@ -917,15 +916,15 @@ msgstr "" #: order/templates/order/sales_order_detail.html:160 #: report/templates/report/inventree_test_report_base.html:75 #: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: templates/js/build.js:569 msgid "Serial Number" msgstr "" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:133 +#: part/templates/part/navbar.html:136 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "" @@ -1037,11 +1036,10 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:715 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 #: stock/templates/stock/item_base.html:279 templates/js/order.js:245 @@ -1185,7 +1183,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:85 order/models.py:678 +#: order/templates/order/purchase_order_detail.html:239 +#: order/templates/order/receive_parts.html:25 stock/forms.py:169 +#: stock/forms.py:375 msgid "Destination" msgstr "" @@ -1194,15 +1195,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1406 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:875 msgid "Created" msgstr "" @@ -1210,7 +1211,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:853 msgid "Completed" msgstr "" @@ -1248,9 +1249,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:17 +#: templates/js/stock.js:1044 msgid "Details" msgstr "" @@ -1285,8 +1286,8 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 +#: stock/templates/stock/item_base.html:497 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "" @@ -1411,8 +1412,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:670 +#: templates/js/build.js:935 templates/js/build.js:1118 msgid "Available" msgstr "" @@ -1598,8 +1599,8 @@ msgstr "" msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 +#: common/models.py:153 part/models.py:2193 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:259 templates/js/table_filters.js:25 #: templates/js/table_filters.js:315 msgid "Template" msgstr "" @@ -1608,7 +1609,7 @@ msgstr "" msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 +#: common/models.py:160 part/models.py:819 part/templates/part/detail.html:170 #: templates/js/table_filters.js:128 templates/js/table_filters.js:327 msgid "Assembly" msgstr "" @@ -1617,7 +1618,7 @@ msgstr "" msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 +#: common/models.py:167 part/models.py:825 part/templates/part/detail.html:180 #: templates/js/table_filters.js:331 msgid "Component" msgstr "" @@ -1626,7 +1627,7 @@ msgstr "" msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:174 part/models.py:836 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" @@ -1634,7 +1635,7 @@ msgstr "" msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 +#: common/models.py:181 part/models.py:841 part/templates/part/detail.html:210 #: templates/js/table_filters.js:339 msgid "Salable" msgstr "" @@ -1643,7 +1644,7 @@ msgstr "" msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 +#: common/models.py:188 part/models.py:831 part/templates/part/detail.html:190 #: templates/js/table_filters.js:33 templates/js/table_filters.js:343 msgid "Trackable" msgstr "" @@ -1652,7 +1653,7 @@ msgstr "" msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:195 part/models.py:851 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" @@ -1669,160 +1670,185 @@ msgstr "" msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" +#: common/models.py:209 +msgid "Show Price in Forms" msgstr "" #: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" +msgid "Display part price in some forms" msgstr "" #: common/models.py:216 -msgid "Page Size" +msgid "Internal Prices" msgstr "" #: common/models.py:217 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:223 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:224 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:230 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:231 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:237 +msgid "Page Size" +msgstr "" + +#: common/models.py:238 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:248 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:249 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:255 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:256 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:262 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:263 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:269 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:270 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:272 part/templates/part/detail.html:121 msgid "days" msgstr "" -#: common/models.py:256 +#: common/models.py:277 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:278 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:284 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:285 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:291 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:292 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:298 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:299 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:305 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:306 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:311 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:312 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:316 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:317 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:322 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:323 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:546 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:548 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:583 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:606 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:617 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:640 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:721 company/forms.py:192 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 +#: common/models.py:729 company/templates/company/supplier_part_pricing.html:82 +#: part/templates/part/internal_prices.html:103 #: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:730 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:822 msgid "Default" msgstr "" @@ -1843,7 +1869,9 @@ msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:582 +#: part/templates/part/bom_upload/upload_file.html:27 msgid "Upload File" msgstr "" @@ -1877,29 +1905,29 @@ msgstr "" msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:133 templates/js/part.js:787 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:135 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:143 company/models.py:321 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:149 company/models.py:328 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:151 company/models.py:327 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 #: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:408 msgid "MPN" msgstr "" @@ -1952,11 +1980,11 @@ msgstr "" msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:121 company/models.py:333 company/models.py:526 +#: order/models.py:106 part/models.py:728 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:188 templates/js/company.js:419 +#: templates/js/part.js:498 msgid "Link" msgstr "" @@ -1964,7 +1992,7 @@ msgstr "" msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:129 part/models.py:738 msgid "Image" msgstr "" @@ -1992,12 +2020,12 @@ msgstr "" msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:305 company/models.py:497 stock/models.py:407 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:309 company/models.py:501 order/views.py:1597 msgid "Select part" msgstr "" @@ -2008,7 +2036,7 @@ msgstr "" #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 #: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:390 msgid "Manufacturer" msgstr "" @@ -2020,87 +2048,112 @@ msgstr "" msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:390 company/models.py:520 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:397 +msgid "Parameter name" +msgstr "" + +#: company/models.py:403 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:241 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:404 +msgid "Parameter value" +msgstr "" + +#: company/models.py:410 part/models.py:813 part/models.py:2165 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:247 +msgid "Units" +msgstr "" + +#: company/models.py:411 +msgid "Parameter units" +msgstr "" + +#: company/models.py:507 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:193 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:48 templates/js/company.js:364 #: templates/js/order.js:170 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:508 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:513 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 #: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:514 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:521 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:527 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:533 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:538 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2305 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 +#: company/models.py:544 company/templates/company/supplier_part_base.html:109 #: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: templates/js/stock.js:695 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:544 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:546 part/models.py:1608 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:546 msgid "Order multiple" msgstr "" #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:562 msgid "Assigned Stock" msgstr "" @@ -2165,11 +2218,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 +#: company/templates/company/detail.html:67 order/models.py:464 #: order/templates/order/sales_order_base.html:94 stock/models.py:449 #: stock/models.py:450 stock/templates/stock/item_base.html:262 #: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: templates/js/stock.js:1097 msgid "Customer" msgstr "" @@ -2215,7 +2268,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:66 #: company/templates/company/detail_supplier_part.html:66 #: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: templates/js/stock.js:1312 msgid "New Part" msgstr "" @@ -2248,13 +2301,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 +#: order/templates/order/order_wizard/select_parts.html:44 #: order/templates/order/purchase_order_detail.html:50 msgid "Create new supplier part" msgstr "" @@ -2262,12 +2314,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 #: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/supplier.html:17 templates/js/stock.js:1318 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 +#: company/templates/company/manufacturer_part_suppliers.html:82 #: company/views.py:64 order/templates/order/purchase_orders.html:185 #: part/templates/part/supplier.html:50 msgid "New Supplier" @@ -2319,8 +2371,9 @@ msgid "There are %(count)s suppliers defined for this manufacturer part. If you msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:63 part/templates/part/navbar.html:86 +#: part/templates/part/navbar.html:89 templates/InvenTree/search.html:316 #: templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,13 +2385,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:38 stock/api.py:54 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2360,11 +2413,25 @@ msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:1002 users/models.py:191 msgid "Delete" msgstr "" -#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:34 +#: part/templates/part/category_navbar.html:37 +#: part/templates/part/navbar.html:24 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:48 +msgid "New Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:83 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" @@ -2379,13 +2446,13 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:35 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 +#: templates/InvenTree/search.html:198 templates/js/stock.js:996 #: templates/stats.html:93 templates/stats.html:102 users/models.py:42 msgid "Stock Items" msgstr "" @@ -2396,7 +2463,7 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 +#: part/templates/part/navbar.html:112 part/templates/part/navbar.html:115 #: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 @@ -2408,7 +2475,7 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 +#: part/templates/part/navbar.html:92 part/templates/part/navbar.html:95 #: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 @@ -2442,7 +2509,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:7 #: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:380 msgid "Supplier Part" msgstr "" @@ -2490,8 +2557,8 @@ msgstr "" msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 company/views.py:855 +#: part/templates/part/sale_prices.html:17 part/views.py:2751 msgid "Add Price Break" msgstr "" @@ -2510,8 +2577,8 @@ msgstr "" msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 +#: company/views.py:70 part/templates/part/navbar.html:80 +#: part/templates/part/navbar.html:83 templates/InvenTree/search.html:306 #: templates/navbar.html:36 msgid "Manufacturers" msgstr "" @@ -2533,20 +2600,20 @@ msgstr "" msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:169 part/views.py:948 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:198 part/views.py:980 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:205 part/views.py:987 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:214 part/views.py:996 msgid "Supplied URL is not a valid image file" msgstr "" @@ -2594,27 +2661,35 @@ msgstr "" msgid "Delete Manufacturer Part" msgstr "" -#: company/views.py:528 +#: company/views.py:514 +msgid "Add Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:548 +msgid "Edit Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:588 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:639 templates/js/stock.js:1319 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:783 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 +#: company/views.py:860 part/views.py:2755 msgid "Added new price break" msgstr "" -#: company/views.py:855 part/views.py:2781 +#: company/views.py:916 part/views.py:2799 msgid "Edit Price Break" msgstr "" -#: company/views.py:870 part/views.py:2795 +#: company/views.py:931 part/views.py:2813 msgid "Delete Price Break" msgstr "" @@ -2638,7 +2713,7 @@ msgstr "" msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:124 report/models.py:297 msgid "Enabled" msgstr "" @@ -2662,7 +2737,7 @@ msgstr "" msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:144 report/models.py:290 msgid "Filename Pattern" msgstr "" @@ -2674,8 +2749,8 @@ msgstr "" msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:245 label/models.py:298 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" @@ -2696,237 +2771,239 @@ msgstr "" msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:86 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 +#: order/forms.py:108 msgid "Purchase Order reference" msgstr "" -#: order/forms.py:110 +#: order/forms.py:115 msgid "Target date for order delivery. Order will be overdue after this date." msgstr "" -#: order/forms.py:138 +#: order/forms.py:143 msgid "Enter sales order number" msgstr "" -#: order/forms.py:145 order/models.py:475 +#: order/forms.py:150 order/models.py:476 msgid "Target date for order completion. Order will be overdue after this date." msgstr "" -#: order/forms.py:236 +#: order/forms.py:242 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:248 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 +#: order/models.py:102 msgid "Order reference" msgstr "" -#: order/models.py:103 +#: order/models.py:104 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:106 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:114 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:121 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:126 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:185 order/models.py:469 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:194 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 +#: order/models.py:197 order/templates/order/order_base.html:98 #: templates/js/order.js:179 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:197 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:204 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:209 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:210 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:215 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:216 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:222 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 +#: order/models.py:246 part/views.py:1686 stock/models.py:304 #: stock/models.py:1020 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:251 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:349 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:353 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:355 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:465 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:479 templates/js/order.js:303 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:486 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:530 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:617 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:619 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:621 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:647 order/models.py:715 templates/js/order.js:353 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:648 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 #: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: templates/js/stock.js:669 templates/js/stock.js:1078 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:662 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 +#: order/models.py:665 order/templates/order/order_base.html:131 #: order/templates/order/purchase_order_detail.html:219 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:665 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:672 stock/models.py:542 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:690 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:673 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:681 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:724 part/templates/part/navbar.html:109 +#: part/templates/part/order_prices.html:107 +#: part/templates/part/part_pricing.html:97 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:725 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:800 order/models.py:802 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:806 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:808 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:811 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:821 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:826 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:837 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:838 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:841 msgid "Enter stock allocation quantity" msgstr "" @@ -2955,7 +3032,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2977,8 +3054,8 @@ msgstr "" #: order/templates/order/order_base.html:180 #: order/templates/order/purchase_order_detail.html:100 #: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: stock/templates/stock/location.html:191 templates/js/stock.js:736 +#: templates/js/stock.js:1324 msgid "New Location" msgstr "" @@ -3081,28 +3158,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3135,15 +3216,20 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +#: order/templates/order/so_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,8 +3239,8 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/sales_order_detail.html:22 order/views.py:1321 +#: order/views.py:1404 msgid "Add Line Item" msgstr "" @@ -3162,25 +3248,31 @@ msgstr "" msgid "No line items found" msgstr "" +#: order/templates/order/purchase_order_detail.html:142 +#: order/templates/order/sales_order_detail.html:223 +msgid "Total" +msgstr "" + #: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/sales_order_detail.html:246 msgid "Unit Price" msgstr "" #: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/sales_order_detail.html:253 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:255 +#: order/templates/order/sales_order_detail.html:359 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:256 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:261 msgid "Receive line item" msgstr "" @@ -3201,7 +3293,7 @@ msgstr "" #: part/templates/part/category_navbar.html:29 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 #: users/models.py:40 msgid "Parts" @@ -3216,7 +3308,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3316,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3265,17 +3357,17 @@ msgid "Sales Order Items" msgstr "" #: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: templates/js/build.js:724 templates/js/build.js:1141 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:610 +#: templates/js/build.js:946 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:612 +#: templates/js/build.js:947 msgid "Delete stock allocation" msgstr "" @@ -3283,50 +3375,50 @@ msgstr "" msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:206 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:274 templates/js/build.js:675 +#: templates/js/build.js:942 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:276 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:313 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:343 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:346 templates/js/build.js:738 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:349 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:353 templates/js/build.js:731 +#: templates/js/build.js:1149 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:356 +#: order/templates/order/sales_order_detail.html:465 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:360 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:471 msgid "Update Unit Price" msgstr "" @@ -3367,10 +3459,6 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - #: order/views.py:104 msgid "Add Purchase Order Attachment" msgstr "" @@ -3471,90 +3559,94 @@ msgstr "" msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:1012 +msgid "Update prices" +msgstr "" + +#: order/views.py:1270 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 +#: order/views.py:1330 msgid "Supplier part must be specified" msgstr "" -#: order/views.py:1326 +#: order/views.py:1336 msgid "Supplier must match for Part and Order" msgstr "" -#: order/views.py:1457 order/views.py:1475 +#: order/views.py:1467 order/views.py:1485 msgid "Edit Line Item" msgstr "" -#: order/views.py:1491 order/views.py:1503 +#: order/views.py:1501 order/views.py:1513 msgid "Delete Line Item" msgstr "" -#: order/views.py:1496 order/views.py:1508 +#: order/views.py:1506 order/views.py:1518 msgid "Deleted line item" msgstr "" -#: order/views.py:1521 +#: order/views.py:1531 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1576 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1592 msgid "Select line item" msgstr "" -#: order/views.py:1613 -#, python-brace-format -msgid "No matching item for serial {serial}" -msgstr "" - #: order/views.py:1623 #, python-brace-format +msgid "No matching item for serial {serial}" +msgstr "" + +#: order/views.py:1633 +#, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1641 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1695 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1769 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1784 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1856 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1862 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1865 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1870 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 +#: part/bom.py:138 part/models.py:72 part/models.py:747 #: part/templates/part/category.html:66 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3632,7 +3724,7 @@ msgstr "" msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:122 part/models.py:2191 msgid "Parent Part" msgstr "" @@ -3708,7 +3800,7 @@ msgstr "" msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:344 part/models.py:2286 msgid "Sub part" msgstr "" @@ -3728,7 +3820,7 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:82 part/models.py:2237 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" @@ -3739,365 +3831,360 @@ msgstr "" msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:448 part/models.py:460 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:557 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:561 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:566 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:645 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:670 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:677 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:678 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:689 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:690 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:696 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:701 part/templates/part/category.html:73 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:702 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:709 part/models.py:2236 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:710 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:715 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "" -#: part/models.py:731 +#: part/models.py:716 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:722 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:723 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:745 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:792 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:793 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:800 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:801 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:806 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:807 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:814 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:820 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:826 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:832 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:837 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:842 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:846 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 #: templates/js/table_filters.js:241 templates/js/table_filters.js:310 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:847 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:852 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:857 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:863 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:865 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:869 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1608 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2063 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2080 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2100 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2101 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2106 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2107 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 +#: part/models.py:2112 templates/js/part.js:726 #: templates/js/table_filters.js:227 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2113 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2118 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2119 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2124 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2125 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2158 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2163 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2165 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2193 part/models.py:2242 part/models.py:2243 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2247 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2248 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2278 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2287 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2293 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2295 templates/js/bom.js:216 templates/js/bom.js:285 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2295 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2298 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2299 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2302 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2305 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2311 templates/js/bom.js:302 templates/js/bom.js:309 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2312 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2317 templates/js/bom.js:294 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2318 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 +#: part/models.py:2394 part/views.py:1692 part/views.py:1744 #: stock/models.py:294 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2403 part/models.py:2405 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2408 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2527 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2563 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 @@ -4112,8 +4199,8 @@ msgstr "" msgid "Deleting this entry will remove the BOM row from the following part" msgstr "" -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:50 +#: part/templates/part/navbar.html:53 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4247,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:1987 msgid "Export Bill of Materials" msgstr "" @@ -4177,7 +4264,7 @@ msgid "All selected BOM items will be deleted" msgstr "" #: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: templates/js/stock.js:1313 msgid "Create New Part" msgstr "" @@ -4258,7 +4345,7 @@ msgstr "" msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:29 part/views.py:2397 msgid "Create new part category" msgstr "" @@ -4318,7 +4405,7 @@ msgid "View grid display" msgstr "" #: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: stock/templates/stock/location.html:192 templates/js/stock.js:737 msgid "Create new location" msgstr "" @@ -4373,14 +4460,8 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 -#: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" -msgstr "" - #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:21 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" @@ -4408,7 +4489,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:13 msgid "Part Details" msgstr "" @@ -4488,6 +4569,36 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/internal_prices.html:11 +#: part/templates/part/navbar.html:100 +msgid "Internal Price Information" +msgstr "" + +#: part/templates/part/internal_prices.html:19 part/views.py:2822 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/internal_prices.html:28 templates/403.html:5 +#: templates/403.html:11 +msgid "Permission Denied" +msgstr "" + +#: part/templates/part/internal_prices.html:31 templates/403.html:14 +msgid "You do not have permission to view this page." +msgstr "" + +#: part/templates/part/internal_prices.html:59 +msgid "No internal price break information found" +msgstr "" + +#: part/templates/part/internal_prices.html:110 +msgid "Edit internal price break" +msgstr "" + +#: part/templates/part/internal_prices.html:111 +msgid "Delete internal price break" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4501,127 +4612,141 @@ msgstr "" msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:28 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:31 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:42 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:45 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:66 part/templates/part/navbar.html:69 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 +#: part/templates/part/navbar.html:74 part/templates/part/order_prices.html:12 msgid "Order Price Information" msgstr "" -#: part/templates/part/navbar.html:75 +#: part/templates/part/navbar.html:77 msgid "Order Price" msgstr "" -#: part/templates/part/navbar.html:98 +#: part/templates/part/navbar.html:103 part/templates/part/order_prices.html:93 +#: part/templates/part/part_pricing.html:82 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/navbar.html:106 msgid "Sales Price Information" msgstr "" -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:120 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:123 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:127 part/templates/part/navbar.html:130 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:139 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 +#: part/templates/part/order_prices.html:24 +#: part/templates/part/part_base.html:282 +msgid "Calculate" +msgstr "" + +#: part/templates/part/order_prices.html:31 msgid "Pricing ranges" msgstr "" -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 +#: part/templates/part/order_prices.html:36 +#: part/templates/part/part_pricing.html:22 msgid "Supplier Pricing" msgstr "" -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 +#: part/templates/part/order_prices.html:37 +#: part/templates/part/order_prices.html:62 +#: part/templates/part/order_prices.html:94 +#: part/templates/part/order_prices.html:108 +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 msgid "Unit Cost" msgstr "" -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 +#: part/templates/part/order_prices.html:44 +#: part/templates/part/order_prices.html:69 +#: part/templates/part/order_prices.html:99 +#: part/templates/part/order_prices.html:113 +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 msgid "Total Cost" msgstr "" -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 +#: part/templates/part/order_prices.html:52 +#: part/templates/part/part_pricing.html:40 msgid "No supplier pricing available" msgstr "" -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 +#: part/templates/part/order_prices.html:61 +#: part/templates/part/order_prices.html:128 +#: part/templates/part/part_pricing.html:48 msgid "BOM Pricing" msgstr "" -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 +#: part/templates/part/order_prices.html:77 +#: part/templates/part/part_pricing.html:66 msgid "Note: BOM pricing is incomplete for this part" msgstr "" -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 +#: part/templates/part/order_prices.html:84 +#: part/templates/part/part_pricing.html:73 msgid "No BOM pricing available" msgstr "" -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 +#: part/templates/part/order_prices.html:122 +#: part/templates/part/part_pricing.html:113 msgid "No pricing information is available for this part." msgstr "" -#: part/templates/part/order_prices.html:113 +#: part/templates/part/order_prices.html:138 msgid "Stock Pricing" msgstr "" -#: part/templates/part/order_prices.html:121 +#: part/templates/part/order_prices.html:146 msgid "No stock pricing history is available for this part." msgstr "" -#: part/templates/part/order_prices.html:140 +#: part/templates/part/order_prices.html:165 #, python-format msgid "Single Price - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:152 +#: part/templates/part/order_prices.html:177 #, python-format msgid "Single Price Difference - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:163 +#: part/templates/part/order_prices.html:189 #, python-format msgid "Part Single Price - %(currency)s" msgstr "" @@ -4630,19 +4755,6 @@ msgstr "" msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4660,7 +4772,7 @@ msgid "Part List" msgstr "" #: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: templates/js/company.js:355 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4740,14 +4852,10 @@ msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 -msgid "Calculate" -msgstr "" - #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" @@ -4816,7 +4924,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,7 +4961,7 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" @@ -4922,227 +5030,239 @@ msgstr "" msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:925 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 +#: part/views.py:1027 msgid "Upload Part Image" msgstr "" -#: part/views.py:1022 part/views.py:1057 +#: part/views.py:1033 part/views.py:1068 msgid "Updated part image" msgstr "" -#: part/views.py:1031 +#: part/views.py:1042 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1071 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1082 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1117 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1147 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1168 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1189 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1200 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1334 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1695 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1720 part/views.py:1723 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1729 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1767 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1773 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1777 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2039 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2046 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2055 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2196 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2206 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2213 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2221 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2271 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2285 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 +#: part/views.py:2345 msgid "Edit Part Category" msgstr "" -#: part/views.py:2365 +#: part/views.py:2383 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2389 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2441 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2542 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2598 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2617 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2687 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 +#: part/views.py:2743 msgid "Confim BOM item deletion" msgstr "" -#: report/models.py:180 +#: part/views.py:2831 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2839 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5174,7 +5294,7 @@ msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:195 templates/js/stock.js:1012 msgid "Date" msgstr "" @@ -5197,7 +5317,7 @@ msgid "Moved {n} parts to {loc}" msgstr "" #: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" @@ -5483,12 +5603,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5738,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:593 msgid "No location set" msgstr "" @@ -5630,25 +5750,29 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" @@ -5945,7 +6069,7 @@ msgstr "" msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:1001 users/models.py:187 msgid "Add" msgstr "" @@ -6011,7 +6135,7 @@ msgstr "" msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1575 templates/js/build.js:326 msgid "Create new Stock Item" msgstr "" @@ -6043,14 +6167,6 @@ msgstr "" msgid "Add Stock Tracking Entry" msgstr "" -#: templates/403.html:5 templates/403.html:11 -msgid "Permission Denied" -msgstr "" - -#: templates/403.html:14 -msgid "You do not have permission to view this page." -msgstr "" - #: templates/404.html:5 templates/404.html:11 msgid "Page Not Found" msgstr "" @@ -6119,11 +6235,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6284,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:85 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:86 msgid "Delete Template" msgstr "" @@ -6221,11 +6337,11 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 +#: templates/InvenTree/settings/part.html:44 msgid "Part Parameter Templates" msgstr "" -#: templates/InvenTree/settings/part.html:61 +#: templates/InvenTree/settings/part.html:65 msgid "No part parameter templates found" msgstr "" @@ -6341,47 +6457,51 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 +#: templates/about.html:100 templates/js/modals.js:568 +#: templates/js/modals.js:861 templates/modals.html:29 templates/modals.html:54 #: templates/modals.html:97 msgid "Close" msgstr "" @@ -6442,7 +6562,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:921 msgid "Invalid server response" msgstr "" @@ -6506,7 +6626,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1091 msgid "Open subassembly" msgstr "" @@ -6542,7 +6662,7 @@ msgstr "" msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:470 templates/js/build.js:423 templates/js/build.js:1189 msgid "No BOM items found" msgstr "" @@ -6562,37 +6682,45 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:382 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:325 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:644 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:665 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:735 templates/js/build.js:1153 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:788 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:805 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:966 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:825 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:924 msgid "No parts allocated for" msgstr "" @@ -6612,17 +6740,29 @@ msgstr "" msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:148 templates/js/company.js:347 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:152 templates/js/company.js:351 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:226 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:262 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:263 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:328 msgid "No supplier parts found" msgstr "" @@ -6710,76 +6850,76 @@ msgstr "" msgid "Loading Data" msgstr "" -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:567 templates/js/modals.js:860 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:824 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:921 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 +#: templates/js/modals.js:931 msgid "No Response" msgstr "" -#: templates/js/modals.js:912 +#: templates/js/modals.js:932 msgid "No response from the InvenTree server" msgstr "" -#: templates/js/modals.js:916 +#: templates/js/modals.js:936 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:937 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 +#: templates/js/modals.js:941 msgid "Error 401: Not Authenticated" msgstr "" -#: templates/js/modals.js:922 +#: templates/js/modals.js:942 msgid "Authentication credentials not supplied" msgstr "" -#: templates/js/modals.js:926 +#: templates/js/modals.js:946 msgid "Error 403: Permission Denied" msgstr "" -#: templates/js/modals.js:927 +#: templates/js/modals.js:947 msgid "You do not have the required permissions to access this function" msgstr "" -#: templates/js/modals.js:931 +#: templates/js/modals.js:951 msgid "Error 404: Resource Not Found" msgstr "" -#: templates/js/modals.js:932 +#: templates/js/modals.js:952 msgid "The requested resource could not be located on the server" msgstr "" -#: templates/js/modals.js:936 +#: templates/js/modals.js:956 msgid "Error 408: Timeout" msgstr "" -#: templates/js/modals.js:937 +#: templates/js/modals.js:957 msgid "Connection timeout while requesting data from server" msgstr "" -#: templates/js/modals.js:940 +#: templates/js/modals.js:960 msgid "Error requesting form data" msgstr "" @@ -6795,6 +6935,10 @@ msgstr "" msgid "No sales orders found" msgstr "" +#: templates/js/order.js:343 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +6967,39 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:323 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:990 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:806 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7097,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:853 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:868 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:882 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:883 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1022 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1069 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1088 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1107 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1125 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1148 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1156 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1188 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1200 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1201 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1325 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1366 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1389 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1417 msgid "Uninstall Stock Item" msgstr "" @@ -7267,56 +7411,56 @@ msgstr "" msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" @@ -7560,35 +7704,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:174 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:182 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:187 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:191 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/pl/LC_MESSAGES/django.po b/InvenTree/locale/pl/LC_MESSAGES/django.po index 9b4e347ff7..4bc233a127 100644 --- a/InvenTree/locale/pl/LC_MESSAGES/django.po +++ b/InvenTree/locale/pl/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:40\n" +"POT-Creation-Date: 2021-06-24 21:38+0000\n" +"PO-Revision-Date: 2021-06-24 21:40\n" "Last-Translator: \n" "Language-Team: Polish\n" "Language: pl_PL\n" @@ -77,7 +77,7 @@ msgstr "Wybierz kategorię" msgid "Duplicate serial: {n}" msgstr "Powtórzony numer seryjny: {n}" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 +#: InvenTree/helpers.py:384 order/models.py:248 order/models.py:358 #: stock/views.py:1795 msgid "Invalid quantity provided" msgstr "Podano nieprawidłową ilość" @@ -122,9 +122,9 @@ msgstr "Komentarz" msgid "File comment" msgstr "Komentarz pliku" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:2022 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1179 msgid "User" msgstr "Użytkownik" @@ -132,34 +132,35 @@ msgstr "Użytkownik" msgid "upload date" msgstr "data przesłania" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:107 InvenTree/models.py:108 company/models.py:396 +#: label/models.py:102 part/models.py:671 part/models.py:2163 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:235 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:972 msgid "Name" msgstr "Nazwa" #: InvenTree/models.py:114 build/models.py:135 #: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: company/models.py:532 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 #: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: order/models.py:104 order/templates/order/purchase_order_detail.html:147 +#: part/models.py:695 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 +#: templates/js/build.js:833 templates/js/build.js:1101 #: templates/js/company.js:56 templates/js/order.js:183 #: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:984 +#: templates/js/stock.js:1029 msgid "Description" msgstr "Opis" @@ -191,15 +192,15 @@ msgstr "Polski" msgid "Turkish" msgstr "Turecki" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "Nie skonfigurowano backendu e-mail" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "" @@ -372,27 +373,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "Usuń element" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "Zaznacz pole aby potwierdzić usunięcie elementu" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "Edytuj informacje użytkownika" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "Ustaw hasło" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "Hasła muszą być zgodne" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "Informacja systemowa" @@ -445,11 +446,11 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 order/forms.py:114 order/forms.py:149 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 +#: templates/js/build.js:880 templates/js/order.js:200 #: templates/js/order.js:298 msgid "Target Date" msgstr "Data docelowa" @@ -462,22 +463,21 @@ msgstr "" #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 +#: build/templates/build/detail.html:31 common/models.py:720 +#: company/forms.py:191 company/templates/company/supplier_part_pricing.html:77 +#: order/forms.py:193 order/forms.py:211 order/forms.py:246 order/forms.py:268 +#: order/forms.py:285 order/models.py:617 order/models.py:841 #: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/order_wizard/select_parts.html:34 #: order/templates/order/purchase_order_detail.html:179 #: order/templates/order/sales_order_detail.html:70 #: order/templates/order/sales_order_detail.html:77 #: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 +#: order/templates/order/sales_order_detail.html:234 part/forms.py:342 +#: part/forms.py:372 part/forms.py:388 part/forms.py:404 part/models.py:2293 +#: part/templates/part/internal_prices.html:98 +#: part/templates/part/order_prices.html:202 +#: part/templates/part/part_pricing.html:16 #: part/templates/part/sale_prices.html:85 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 @@ -486,9 +486,10 @@ msgstr "" #: stock/forms.py:175 stock/forms.py:308 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:571 +#: templates/js/build.js:1111 templates/js/order.js:393 +#: templates/js/part.js:796 templates/js/stock.js:1164 +#: templates/js/stock.js:1383 msgid "Quantity" msgstr "Ilość" @@ -500,7 +501,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:240 stock/forms.py:118 msgid "Serial Numbers" msgstr "Numer seryjny" @@ -529,12 +530,12 @@ msgid "Mark build as complete" msgstr "Oznacz budowę jako ukończoną" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:347 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:585 templates/js/order.js:378 +#: templates/js/stock.js:643 templates/js/stock.js:1056 msgid "Location" msgstr "Lokalizacja" @@ -543,13 +544,13 @@ msgid "Location of completed parts" msgstr "Lokalizacja ukończonych części" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:469 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:867 #: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: templates/js/stock.js:630 templates/js/stock.js:1133 +#: templates/js/stock.js:1399 msgid "Status" msgstr "Status" @@ -583,16 +584,16 @@ msgstr "" #: build/models.py:66 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "Zlecenie Budowy" #: build/models.py:67 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:57 +#: part/templates/part/navbar.html:60 templates/InvenTree/index.html:183 #: templates/InvenTree/search.html:185 #: templates/InvenTree/settings/tabs.html:34 users/models.py:43 msgid "Build Orders" @@ -602,12 +603,12 @@ msgstr "Zlecenia budowy" msgid "Build Order Reference" msgstr "Odwołanie do zamówienia wykonania" -#: build/models.py:128 order/models.py:101 order/models.py:618 +#: build/models.py:128 order/models.py:102 order/models.py:619 #: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: order/templates/order/sales_order_detail.html:229 part/models.py:2302 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:660 templates/js/build.js:1105 msgid "Reference" msgstr "Referencja" @@ -626,27 +627,27 @@ msgstr "Zamówienie budowy, do którego budowa jest przypisana" #: build/models.py:153 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 +#: build/templates/build/detail.html:26 company/models.py:663 +#: order/models.py:661 order/models.py:717 +#: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:132 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:214 part/models.py:321 +#: part/models.py:1975 part/models.py:1987 part/models.py:2002 +#: part/models.py:2020 part/models.py:2095 part/models.py:2191 +#: part/models.py:2277 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:551 templates/js/build.js:838 +#: templates/js/build.js:1078 templates/js/company.js:140 +#: templates/js/company.js:339 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1371 msgid "Part" msgstr "Część" @@ -710,16 +711,16 @@ msgstr "Kod partii" msgid "Batch code for this build output" msgstr "Kod partii dla wyjścia budowy" -#: build/models.py:220 order/models.py:107 part/models.py:882 +#: build/models.py:220 order/models.py:108 part/models.py:867 #: part/templates/part/detail.html:126 templates/js/order.js:293 msgid "Creation Date" msgstr "Data utworzenia" -#: build/models.py:224 order/models.py:474 +#: build/models.py:224 order/models.py:475 msgid "Target completion date" msgstr "Docelowy termin zakończenia" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:228 order/models.py:221 templates/js/build.js:885 msgid "Completion Date" msgstr "Data zakończenia" @@ -736,9 +737,9 @@ msgid "User who issued this build order" msgstr "Użytkownik, który wydał to zamówienie" #: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/templates/build/detail.html:105 order/models.py:122 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:871 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "Odpowiedzialny" @@ -757,26 +758,26 @@ msgstr "Użytkownik odpowiedzialny za to zamówienie budowy" msgid "External Link" msgstr "Link Zewnętrzny" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:258 part/models.py:729 stock/models.py:462 msgid "Link to external URL" msgstr "Link do zewnętrznego adresu URL" #: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: company/models.py:132 company/models.py:539 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:126 +#: order/models.py:621 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:243 +#: order/templates/order/sales_order_detail.html:309 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:856 +#: part/templates/part/navbar.html:142 #: report/templates/report/inventree_build_order_base.html:173 #: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 #: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:699 msgid "Notes" msgstr "Uwagi" @@ -809,11 +810,11 @@ msgstr "" msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1188 order/models.py:815 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1192 order/models.py:818 msgid "Allocation quantity must be greater than zero" msgstr "" @@ -827,7 +828,7 @@ msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" #: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: templates/InvenTree/search.html:183 templates/js/build.js:811 #: templates/navbar.html:29 msgid "Build" msgstr "Budowa" @@ -836,15 +837,13 @@ msgstr "Budowa" msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1333 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:928 +#: templates/js/order.js:366 templates/js/order.js:371 +#: templates/js/stock.js:1115 msgid "Stock Item" msgstr "Element magazynowy" @@ -880,7 +879,7 @@ msgstr "Przydziel zapasy do budowy" msgid "Auto Allocate" msgstr "Automatyczne przypisywanie" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:743 msgid "Unallocate stock" msgstr "Cofnij przydział zapasów" @@ -917,15 +916,15 @@ msgstr "" #: order/templates/order/sales_order_detail.html:160 #: report/templates/report/inventree_test_report_base.html:75 #: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: templates/js/build.js:569 msgid "Serial Number" msgstr "Numer Seryjny" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:133 +#: part/templates/part/navbar.html:136 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "Załączniki" @@ -1037,11 +1036,10 @@ msgid "Progress" msgstr "Postęp" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:715 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 #: stock/templates/stock/item_base.html:279 templates/js/order.js:245 @@ -1185,7 +1183,10 @@ msgstr "Źródło magazynu" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:85 order/models.py:678 +#: order/templates/order/purchase_order_detail.html:239 +#: order/templates/order/receive_parts.html:25 stock/forms.py:169 +#: stock/forms.py:375 msgid "Destination" msgstr "Przeznaczenie" @@ -1194,15 +1195,15 @@ msgid "Destination location not specified" msgstr "Nie określono lokalizacji docelowej" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1406 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "Partia" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:875 msgid "Created" msgstr "Utworzony" @@ -1210,7 +1211,7 @@ msgstr "Utworzony" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:853 msgid "Completed" msgstr "Zakończone" @@ -1248,9 +1249,9 @@ msgstr "Szczegóły zlecenia budowy" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:17 +#: templates/js/stock.js:1044 msgid "Details" msgstr "Szczegóły" @@ -1285,8 +1286,8 @@ msgstr "Edytuj uwagi" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 +#: stock/templates/stock/item_base.html:497 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "Zapisz" @@ -1411,8 +1412,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:670 +#: templates/js/build.js:935 templates/js/build.js:1118 msgid "Available" msgstr "Dostępne" @@ -1598,8 +1599,8 @@ msgstr "" msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 +#: common/models.py:153 part/models.py:2193 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:259 templates/js/table_filters.js:25 #: templates/js/table_filters.js:315 msgid "Template" msgstr "Szablon" @@ -1608,7 +1609,7 @@ msgstr "Szablon" msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 +#: common/models.py:160 part/models.py:819 part/templates/part/detail.html:170 #: templates/js/table_filters.js:128 templates/js/table_filters.js:327 msgid "Assembly" msgstr "Złożenie" @@ -1617,7 +1618,7 @@ msgstr "Złożenie" msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 +#: common/models.py:167 part/models.py:825 part/templates/part/detail.html:180 #: templates/js/table_filters.js:331 msgid "Component" msgstr "Komponent" @@ -1626,7 +1627,7 @@ msgstr "Komponent" msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:174 part/models.py:836 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "Możliwość zakupu" @@ -1634,7 +1635,7 @@ msgstr "Możliwość zakupu" msgid "Parts are purchaseable by default" msgstr "Części są domyślnie z możliwością zakupu" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 +#: common/models.py:181 part/models.py:841 part/templates/part/detail.html:210 #: templates/js/table_filters.js:339 msgid "Salable" msgstr "Możliwość sprzedaży" @@ -1643,7 +1644,7 @@ msgstr "Możliwość sprzedaży" msgid "Parts are salable by default" msgstr "Części są domyślnie z możliwością sprzedaży" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 +#: common/models.py:188 part/models.py:831 part/templates/part/detail.html:190 #: templates/js/table_filters.js:33 templates/js/table_filters.js:343 msgid "Trackable" msgstr "Możliwość śledzenia" @@ -1652,7 +1653,7 @@ msgstr "Możliwość śledzenia" msgid "Parts are trackable by default" msgstr "Części są domyślnie z możliwością śledzenia" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:195 part/models.py:851 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "Wirtualny" @@ -1669,160 +1670,185 @@ msgstr "" msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" -msgstr "Tryb Debugowania" +#: common/models.py:209 +msgid "Show Price in Forms" +msgstr "" #: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" +msgid "Display part price in some forms" msgstr "" #: common/models.py:216 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:217 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:223 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:224 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:230 templates/stats.html:25 +msgid "Debug Mode" +msgstr "Tryb Debugowania" + +#: common/models.py:231 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:237 msgid "Page Size" msgstr "Rozmiar strony" -#: common/models.py:217 +#: common/models.py:238 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:248 msgid "Test Reports" msgstr "Raporty testów" -#: common/models.py:228 +#: common/models.py:249 msgid "Enable generation of test reports" msgstr "Włącz generowanie raportów testów" -#: common/models.py:234 +#: common/models.py:255 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:256 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:262 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:263 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:269 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:270 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:272 part/templates/part/detail.html:121 msgid "days" msgstr "dni" -#: common/models.py:256 +#: common/models.py:277 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:278 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:284 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:285 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:291 msgid "Group by Part" msgstr "Grupuj według komponentu" -#: common/models.py:271 +#: common/models.py:292 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:298 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:299 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:305 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:306 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:311 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:312 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:316 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:317 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:322 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:323 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:546 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:548 msgid "Settings value" msgstr "Ustawienia wartości" -#: common/models.py:562 +#: common/models.py:583 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:606 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:617 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:640 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:721 company/forms.py:192 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 +#: common/models.py:729 company/templates/company/supplier_part_pricing.html:82 +#: part/templates/part/internal_prices.html:103 #: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 msgid "Price" msgstr "Cena" -#: common/models.py:709 +#: common/models.py:730 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:822 msgid "Default" msgstr "Domyślny" @@ -1843,9 +1869,11 @@ msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:582 +#: part/templates/part/bom_upload/upload_file.html:27 msgid "Upload File" -msgstr "Wyślik plik" +msgstr "Wyślij plik" #: common/views.py:185 order/templates/order/order_wizard/match_fields.html:52 #: order/views.py:583 part/templates/part/bom_upload/select_fields.html:58 @@ -1877,29 +1905,29 @@ msgstr "URL" msgid "Image URL" msgstr "URL zdjęcia" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:133 templates/js/part.js:787 msgid "Single Price" msgstr "Cena jednostkowa" -#: company/forms.py:120 +#: company/forms.py:135 msgid "Single quantity price" msgstr "Cena jednostkowa" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:143 company/models.py:321 msgid "Select manufacturer" msgstr "Wybierz producenta" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:149 company/models.py:328 msgid "Manufacturer Part Number" msgstr "Numer producenta" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:151 company/models.py:327 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 #: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:408 msgid "MPN" msgstr "MPN" @@ -1952,11 +1980,11 @@ msgstr "Kontakt" msgid "Point of contact" msgstr "Punkt kontaktowy" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:121 company/models.py:333 company/models.py:526 +#: order/models.py:106 part/models.py:728 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:188 templates/js/company.js:419 +#: templates/js/part.js:498 msgid "Link" msgstr "Łącze" @@ -1964,7 +1992,7 @@ msgstr "Łącze" msgid "Link to external company information" msgstr "Link do informacji o zewnętrznym przedsiębiorstwie" -#: company/models.py:129 part/models.py:753 +#: company/models.py:129 part/models.py:738 msgid "Image" msgstr "Obraz" @@ -1992,12 +2020,12 @@ msgstr "jest producentem" msgid "Does this company manufacture parts?" msgstr "Czy to przedsiębiorstwo produkuje części?" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:305 company/models.py:497 stock/models.py:407 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "Część bazowa" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:309 company/models.py:501 order/views.py:1597 msgid "Select part" msgstr "Wybierz część" @@ -2008,7 +2036,7 @@ msgstr "Wybierz część" #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 #: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:390 msgid "Manufacturer" msgstr "Producent" @@ -2020,87 +2048,112 @@ msgstr "" msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:390 company/models.py:520 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "Część producenta" + +#: company/models.py:397 +msgid "Parameter name" +msgstr "" + +#: company/models.py:403 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:241 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:404 +msgid "Parameter value" +msgstr "" + +#: company/models.py:410 part/models.py:813 part/models.py:2165 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:247 +msgid "Units" +msgstr "Jednostki" + +#: company/models.py:411 +msgid "Parameter units" +msgstr "" + +#: company/models.py:507 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:193 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:48 templates/js/company.js:364 #: templates/js/order.js:170 msgid "Supplier" msgstr "Dostawca" -#: company/models.py:467 +#: company/models.py:508 msgid "Select supplier" msgstr "Wybierz dostawcę" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:513 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 #: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "SKU" -#: company/models.py:473 +#: company/models.py:514 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "Część producenta" - -#: company/models.py:480 +#: company/models.py:521 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:527 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:533 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:538 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2305 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "Uwaga" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "base cost" msgstr "koszt podstawowy" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 +#: company/models.py:544 company/templates/company/supplier_part_base.html:109 #: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: templates/js/stock.js:695 msgid "Packaging" msgstr "Opakowanie" -#: company/models.py:503 +#: company/models.py:544 msgid "Part packaging" msgstr "Opakowanie części" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:546 part/models.py:1608 msgid "multiple" msgstr "wielokrotność" -#: company/models.py:505 +#: company/models.py:546 msgid "Order multiple" msgstr "" #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:562 msgid "Assigned Stock" msgstr "" @@ -2165,11 +2218,11 @@ msgstr "Nie określono strony internetowej" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 +#: company/templates/company/detail.html:67 order/models.py:464 #: order/templates/order/sales_order_base.html:94 stock/models.py:449 #: stock/models.py:450 stock/templates/stock/item_base.html:262 #: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: templates/js/stock.js:1097 msgid "Customer" msgstr "Klient" @@ -2215,7 +2268,7 @@ msgstr "Usuń części" #: company/templates/company/detail_manufacturer_part.html:66 #: company/templates/company/detail_supplier_part.html:66 #: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: templates/js/stock.js:1312 msgid "New Part" msgstr "Nowy komponent" @@ -2248,13 +2301,12 @@ msgstr "Eksportuj" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "Komponenty dostawcy" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 +#: order/templates/order/order_wizard/select_parts.html:44 #: order/templates/order/purchase_order_detail.html:50 msgid "Create new supplier part" msgstr "Utwórz nowego dostawcę części" @@ -2262,12 +2314,12 @@ msgstr "Utwórz nowego dostawcę części" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 #: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/supplier.html:17 templates/js/stock.js:1318 msgid "New Supplier Part" msgstr "Now dostawca części" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 +#: company/templates/company/manufacturer_part_suppliers.html:82 #: company/views.py:64 order/templates/order/purchase_orders.html:185 #: part/templates/part/supplier.html:50 msgid "New Supplier" @@ -2319,8 +2371,9 @@ msgid "There are %(count)s suppliers defined for this manufacturer part. If you msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:63 part/templates/part/navbar.html:86 +#: part/templates/part/navbar.html:89 templates/InvenTree/search.html:316 #: templates/navbar.html:35 msgid "Suppliers" msgstr "Dostawcy" @@ -2332,13 +2385,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:38 stock/api.py:54 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "Stan" @@ -2360,11 +2413,25 @@ msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:1002 users/models.py:191 msgid "Delete" msgstr "Usuń" -#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:34 +#: part/templates/part/category_navbar.html:37 +#: part/templates/part/navbar.html:24 +msgid "Parameters" +msgstr "Parametry" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:48 +msgid "New Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:83 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "Utwórz nowego dostawcę" @@ -2379,13 +2446,13 @@ msgstr "" msgid "Supplied Parts" msgstr "Dostarczone części" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:35 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 +#: templates/InvenTree/search.html:198 templates/js/stock.js:996 #: templates/stats.html:93 templates/stats.html:102 users/models.py:42 msgid "Stock Items" msgstr "" @@ -2396,7 +2463,7 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 +#: part/templates/part/navbar.html:112 part/templates/part/navbar.html:115 #: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 @@ -2408,7 +2475,7 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 +#: part/templates/part/navbar.html:92 part/templates/part/navbar.html:95 #: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 @@ -2442,7 +2509,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:7 #: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:380 msgid "Supplier Part" msgstr "" @@ -2490,8 +2557,8 @@ msgstr "" msgid "Pricing Information" msgstr "Informacja cenowa" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 company/views.py:855 +#: part/templates/part/sale_prices.html:17 part/views.py:2751 msgid "Add Price Break" msgstr "" @@ -2510,8 +2577,8 @@ msgstr "Edytuj przedział cenowy" msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 +#: company/views.py:70 part/templates/part/navbar.html:80 +#: part/templates/part/navbar.html:83 templates/InvenTree/search.html:306 #: templates/navbar.html:36 msgid "Manufacturers" msgstr "Producenci" @@ -2533,20 +2600,20 @@ msgstr "Firmy" msgid "New Company" msgstr "Nowa firma" -#: company/views.py:169 part/views.py:937 +#: company/views.py:169 part/views.py:948 msgid "Download Image" msgstr "Pobierz obraz" -#: company/views.py:198 part/views.py:969 +#: company/views.py:198 part/views.py:980 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:205 part/views.py:987 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:214 part/views.py:996 msgid "Supplied URL is not a valid image file" msgstr "" @@ -2594,27 +2661,35 @@ msgstr "" msgid "Delete Manufacturer Part" msgstr "" -#: company/views.py:528 +#: company/views.py:514 +msgid "Add Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:548 +msgid "Edit Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:588 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:639 templates/js/stock.js:1319 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:783 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 +#: company/views.py:860 part/views.py:2755 msgid "Added new price break" msgstr "" -#: company/views.py:855 part/views.py:2781 +#: company/views.py:916 part/views.py:2799 msgid "Edit Price Break" msgstr "Edytuj przedział cenowy" -#: company/views.py:870 part/views.py:2795 +#: company/views.py:931 part/views.py:2813 msgid "Delete Price Break" msgstr "" @@ -2638,7 +2713,7 @@ msgstr "Etykieta" msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:124 report/models.py:297 msgid "Enabled" msgstr "Aktywne" @@ -2662,7 +2737,7 @@ msgstr "Wysokość [mm]" msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:144 report/models.py:290 msgid "Filename Pattern" msgstr "" @@ -2674,8 +2749,8 @@ msgstr "" msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:245 label/models.py:298 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "Filtry" @@ -2696,237 +2771,239 @@ msgstr "Anuluj zamówienie" msgid "Ship order" msgstr "Wyślij zamówienie" -#: order/forms.py:82 +#: order/forms.py:86 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 +#: order/forms.py:108 msgid "Purchase Order reference" msgstr "" -#: order/forms.py:110 +#: order/forms.py:115 msgid "Target date for order delivery. Order will be overdue after this date." msgstr "" -#: order/forms.py:138 +#: order/forms.py:143 msgid "Enter sales order number" msgstr "" -#: order/forms.py:145 order/models.py:475 +#: order/forms.py:150 order/models.py:476 msgid "Target date for order completion. Order will be overdue after this date." msgstr "" -#: order/forms.py:236 +#: order/forms.py:242 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:248 msgid "Enter quantity of stock items" msgstr "Wprowadź ilość produktów magazynowych" -#: order/models.py:101 +#: order/models.py:102 msgid "Order reference" msgstr "Odniesienie zamówienia" -#: order/models.py:103 +#: order/models.py:104 msgid "Order description" msgstr "Opis Zamówienia" -#: order/models.py:105 +#: order/models.py:106 msgid "Link to external page" msgstr "Link do zewnętrznej witryny" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:114 part/templates/part/detail.html:132 msgid "Created By" msgstr "Utworzony przez" -#: order/models.py:120 +#: order/models.py:121 msgid "User or group responsible for this order" msgstr "Użytkownik lub grupa odpowiedzialna za to zamówienie" -#: order/models.py:125 +#: order/models.py:126 msgid "Order notes" msgstr "Notatki do zamówienia" -#: order/models.py:184 order/models.py:468 +#: order/models.py:185 order/models.py:469 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:194 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 +#: order/models.py:197 order/templates/order/order_base.html:98 #: templates/js/order.js:179 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:197 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:204 msgid "received by" msgstr "odebrane przez" -#: order/models.py:208 +#: order/models.py:209 msgid "Issue Date" msgstr "Data wydania" -#: order/models.py:209 +#: order/models.py:210 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:215 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:216 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:222 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 +#: order/models.py:246 part/views.py:1686 stock/models.py:304 #: stock/models.py:1020 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:251 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:349 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:353 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:355 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:465 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:479 templates/js/order.js:303 msgid "Shipment Date" msgstr "Data wysyłki" -#: order/models.py:485 +#: order/models.py:486 msgid "shipped by" msgstr "wysłane przez" -#: order/models.py:529 +#: order/models.py:530 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:617 msgid "Item quantity" msgstr "Ilość elementów" -#: order/models.py:618 +#: order/models.py:619 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:621 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:647 order/models.py:715 templates/js/order.js:353 msgid "Order" msgstr "Zamówienie" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:648 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 #: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: templates/js/stock.js:669 templates/js/stock.js:1078 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:662 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 +#: order/models.py:665 order/templates/order/order_base.html:131 #: order/templates/order/purchase_order_detail.html:219 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "Odebrane" -#: order/models.py:664 +#: order/models.py:665 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:672 stock/models.py:542 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:690 msgid "Purchase Price" msgstr "Cena zakupu" -#: order/models.py:672 +#: order/models.py:673 msgid "Unit purchase price" msgstr "Cena zakupu jednostkowego" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:681 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:724 part/templates/part/navbar.html:109 +#: part/templates/part/order_prices.html:107 +#: part/templates/part/part_pricing.html:97 msgid "Sale Price" msgstr "Cena sprzedaży" -#: order/models.py:701 +#: order/models.py:725 msgid "Unit sale price" msgstr "Jednostkowa cena sprzedaży" -#: order/models.py:776 order/models.py:778 +#: order/models.py:800 order/models.py:802 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:806 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:808 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:811 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:821 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:826 msgid "Line" msgstr "Linia" -#: order/models.py:813 +#: order/models.py:837 msgid "Item" msgstr "Komponent" -#: order/models.py:814 +#: order/models.py:838 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:841 msgid "Enter stock allocation quantity" msgstr "" @@ -2955,7 +3032,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2977,8 +3054,8 @@ msgstr "Wydany" #: order/templates/order/order_base.html:180 #: order/templates/order/purchase_order_detail.html:100 #: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: stock/templates/stock/location.html:191 templates/js/stock.js:736 +#: templates/js/stock.js:1324 msgid "New Location" msgstr "Nowa lokalizacja" @@ -3081,28 +3158,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "Wybierz dostawcę" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "Usuń część" @@ -3135,15 +3216,20 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +#: order/templates/order/so_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "Otrzymane elementy" @@ -3153,8 +3239,8 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/sales_order_detail.html:22 order/views.py:1321 +#: order/views.py:1404 msgid "Add Line Item" msgstr "" @@ -3162,25 +3248,31 @@ msgstr "" msgid "No line items found" msgstr "" +#: order/templates/order/purchase_order_detail.html:142 +#: order/templates/order/sales_order_detail.html:223 +msgid "Total" +msgstr "" + #: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/sales_order_detail.html:246 msgid "Unit Price" msgstr "Cena jednostkowa" #: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/sales_order_detail.html:253 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:255 +#: order/templates/order/sales_order_detail.html:359 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:256 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:261 msgid "Receive line item" msgstr "" @@ -3201,7 +3293,7 @@ msgstr "" #: part/templates/part/category_navbar.html:29 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 #: users/models.py:40 msgid "Parts" @@ -3216,7 +3308,7 @@ msgid "Order Code" msgstr "Kod zamówienia" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3316,11 @@ msgstr "" msgid "Receive" msgstr "Odbierz" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "Usuń linie" @@ -3265,17 +3357,17 @@ msgid "Sales Order Items" msgstr "" #: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: templates/js/build.js:724 templates/js/build.js:1141 msgid "Actions" msgstr "Akcje" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:610 +#: templates/js/build.js:946 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:612 +#: templates/js/build.js:947 msgid "Delete stock allocation" msgstr "" @@ -3283,50 +3375,50 @@ msgstr "" msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:206 msgid "ID" msgstr "Numer ID" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:274 templates/js/build.js:675 +#: templates/js/build.js:942 msgid "Allocated" msgstr "Przydzielono" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:276 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:313 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:343 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:346 templates/js/build.js:738 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:349 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:353 templates/js/build.js:731 +#: templates/js/build.js:1149 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:356 +#: order/templates/order/sales_order_detail.html:465 msgid "Calculate price" msgstr "Oblicz cenę" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:360 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:471 msgid "Update Unit Price" msgstr "" @@ -3367,10 +3459,6 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - #: order/views.py:104 msgid "Add Purchase Order Attachment" msgstr "" @@ -3471,90 +3559,94 @@ msgstr "" msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:1012 +msgid "Update prices" +msgstr "" + +#: order/views.py:1270 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 +#: order/views.py:1330 msgid "Supplier part must be specified" msgstr "" -#: order/views.py:1326 +#: order/views.py:1336 msgid "Supplier must match for Part and Order" msgstr "" -#: order/views.py:1457 order/views.py:1475 +#: order/views.py:1467 order/views.py:1485 msgid "Edit Line Item" msgstr "" -#: order/views.py:1491 order/views.py:1503 +#: order/views.py:1501 order/views.py:1513 msgid "Delete Line Item" msgstr "" -#: order/views.py:1496 order/views.py:1508 +#: order/views.py:1506 order/views.py:1518 msgid "Deleted line item" msgstr "" -#: order/views.py:1521 +#: order/views.py:1531 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1576 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1592 msgid "Select line item" msgstr "" -#: order/views.py:1613 -#, python-brace-format -msgid "No matching item for serial {serial}" -msgstr "" - #: order/views.py:1623 #, python-brace-format +msgid "No matching item for serial {serial}" +msgstr "" + +#: order/views.py:1633 +#, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1641 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1695 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1769 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1784 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1856 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1862 msgid "Price not found" msgstr "Nie znaleziono ceny" -#: order/views.py:1855 +#: order/views.py:1865 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1870 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 +#: part/bom.py:138 part/models.py:72 part/models.py:747 #: part/templates/part/category.html:66 part/templates/part/detail.html:90 msgid "Default Location" msgstr "Domyślna lokalizacja" @@ -3632,7 +3724,7 @@ msgstr "" msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:122 part/models.py:2191 msgid "Parent Part" msgstr "Część nadrzędna" @@ -3708,7 +3800,7 @@ msgstr "" msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:344 part/models.py:2286 msgid "Sub part" msgstr "Podczęść" @@ -3728,7 +3820,7 @@ msgstr "Domyślne słowa kluczowe" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:82 part/models.py:2237 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" @@ -3739,365 +3831,360 @@ msgstr "" msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:448 part/models.py:460 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:557 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:561 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:566 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:645 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:670 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:677 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:678 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:689 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:690 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "Wariant" -#: part/models.py:711 +#: part/models.py:696 msgid "Part description" msgstr "Opis części" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:701 part/templates/part/category.html:73 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "Słowa kluczowe" -#: part/models.py:717 +#: part/models.py:702 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:709 part/models.py:2236 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "Kategoria" -#: part/models.py:725 +#: part/models.py:710 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:715 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "IPN" -#: part/models.py:731 +#: part/models.py:716 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:722 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:723 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "Wersja" -#: part/models.py:760 +#: part/models.py:745 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:792 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:793 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:800 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:801 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:806 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "Minimalny stan magazynowy" -#: part/models.py:822 +#: part/models.py:807 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "Jednostki" - -#: part/models.py:829 +#: part/models.py:814 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:820 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:826 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:832 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:837 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:842 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:846 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 #: templates/js/table_filters.js:241 templates/js/table_filters.js:310 msgid "Active" msgstr "Aktywny" -#: part/models.py:862 +#: part/models.py:847 msgid "Is this part active?" msgstr "Czy ta część jest aktywna?" -#: part/models.py:867 +#: part/models.py:852 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:857 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:863 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:865 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:869 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1608 msgid "Sell multiple" msgstr "Sprzedaj wiele" -#: part/models.py:2040 +#: part/models.py:2063 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2080 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2100 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "Nazwa testu" -#: part/models.py:2078 +#: part/models.py:2101 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2106 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2107 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 +#: part/models.py:2112 templates/js/part.js:726 #: templates/js/table_filters.js:227 msgid "Required" msgstr "Wymagane" -#: part/models.py:2090 +#: part/models.py:2113 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2118 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2119 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2124 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2125 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2158 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2163 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2165 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2193 part/models.py:2242 part/models.py:2243 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Data" msgstr "Dane" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2247 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "Wartość domyślna" -#: part/models.py:2225 +#: part/models.py:2248 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2278 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2287 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2293 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2295 templates/js/bom.js:216 templates/js/bom.js:285 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2295 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2298 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2299 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2302 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2305 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "Checksum" msgstr "Suma kontrolna" -#: part/models.py:2284 +#: part/models.py:2307 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2311 templates/js/bom.js:302 templates/js/bom.js:309 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2312 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2317 templates/js/bom.js:294 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2318 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 +#: part/models.py:2394 part/views.py:1692 part/views.py:1744 #: stock/models.py:294 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2403 part/models.py:2405 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2408 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2527 msgid "Part 1" msgstr "Część 1" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Part 2" msgstr "Część 2" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Select Related Part" msgstr "Wybierz powiązaną część" -#: part/models.py:2538 +#: part/models.py:2563 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 @@ -4112,8 +4199,8 @@ msgstr "" msgid "Deleting this entry will remove the BOM row from the following part" msgstr "" -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:50 +#: part/templates/part/navbar.html:53 msgid "Bill of Materials" msgstr "Zestawienie materiałowe" @@ -4160,7 +4247,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:1987 msgid "Export Bill of Materials" msgstr "" @@ -4177,7 +4264,7 @@ msgid "All selected BOM items will be deleted" msgstr "" #: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: templates/js/stock.js:1313 msgid "Create New Part" msgstr "" @@ -4258,7 +4345,7 @@ msgstr "" msgid "All parts" msgstr "Wszystkie części" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:29 part/views.py:2397 msgid "Create new part category" msgstr "Stwórz nową kategorię komponentów" @@ -4318,7 +4405,7 @@ msgid "View grid display" msgstr "" #: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: stock/templates/stock/location.html:192 templates/js/stock.js:737 msgid "Create new location" msgstr "" @@ -4373,14 +4460,8 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 -#: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" -msgstr "Parametry" - #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:21 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "Parametry części" @@ -4408,7 +4489,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:13 msgid "Part Details" msgstr "Szczegóły części" @@ -4488,6 +4569,36 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/internal_prices.html:11 +#: part/templates/part/navbar.html:100 +msgid "Internal Price Information" +msgstr "" + +#: part/templates/part/internal_prices.html:19 part/views.py:2822 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/internal_prices.html:28 templates/403.html:5 +#: templates/403.html:11 +msgid "Permission Denied" +msgstr "" + +#: part/templates/part/internal_prices.html:31 templates/403.html:14 +msgid "You do not have permission to view this page." +msgstr "" + +#: part/templates/part/internal_prices.html:59 +msgid "No internal price break information found" +msgstr "" + +#: part/templates/part/internal_prices.html:110 +msgid "Edit internal price break" +msgstr "" + +#: part/templates/part/internal_prices.html:111 +msgid "Delete internal price break" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4501,127 +4612,141 @@ msgstr "" msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:28 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:31 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:42 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:45 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:66 part/templates/part/navbar.html:69 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 +#: part/templates/part/navbar.html:74 part/templates/part/order_prices.html:12 msgid "Order Price Information" msgstr "" -#: part/templates/part/navbar.html:75 +#: part/templates/part/navbar.html:77 msgid "Order Price" msgstr "" -#: part/templates/part/navbar.html:98 +#: part/templates/part/navbar.html:103 part/templates/part/order_prices.html:93 +#: part/templates/part/part_pricing.html:82 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/navbar.html:106 msgid "Sales Price Information" msgstr "" -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:120 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:123 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:127 part/templates/part/navbar.html:130 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:139 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 +#: part/templates/part/order_prices.html:24 +#: part/templates/part/part_base.html:282 +msgid "Calculate" +msgstr "" + +#: part/templates/part/order_prices.html:31 msgid "Pricing ranges" msgstr "" -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 +#: part/templates/part/order_prices.html:36 +#: part/templates/part/part_pricing.html:22 msgid "Supplier Pricing" msgstr "" -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 +#: part/templates/part/order_prices.html:37 +#: part/templates/part/order_prices.html:62 +#: part/templates/part/order_prices.html:94 +#: part/templates/part/order_prices.html:108 +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 msgid "Unit Cost" msgstr "" -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 +#: part/templates/part/order_prices.html:44 +#: part/templates/part/order_prices.html:69 +#: part/templates/part/order_prices.html:99 +#: part/templates/part/order_prices.html:113 +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 msgid "Total Cost" msgstr "" -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 +#: part/templates/part/order_prices.html:52 +#: part/templates/part/part_pricing.html:40 msgid "No supplier pricing available" msgstr "" -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 +#: part/templates/part/order_prices.html:61 +#: part/templates/part/order_prices.html:128 +#: part/templates/part/part_pricing.html:48 msgid "BOM Pricing" msgstr "" -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 +#: part/templates/part/order_prices.html:77 +#: part/templates/part/part_pricing.html:66 msgid "Note: BOM pricing is incomplete for this part" msgstr "" -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 +#: part/templates/part/order_prices.html:84 +#: part/templates/part/part_pricing.html:73 msgid "No BOM pricing available" msgstr "" -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 +#: part/templates/part/order_prices.html:122 +#: part/templates/part/part_pricing.html:113 msgid "No pricing information is available for this part." msgstr "" -#: part/templates/part/order_prices.html:113 +#: part/templates/part/order_prices.html:138 msgid "Stock Pricing" msgstr "" -#: part/templates/part/order_prices.html:121 +#: part/templates/part/order_prices.html:146 msgid "No stock pricing history is available for this part." msgstr "" -#: part/templates/part/order_prices.html:140 +#: part/templates/part/order_prices.html:165 #, python-format msgid "Single Price - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:152 +#: part/templates/part/order_prices.html:177 #, python-format msgid "Single Price Difference - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:163 +#: part/templates/part/order_prices.html:189 #, python-format msgid "Part Single Price - %(currency)s" msgstr "" @@ -4630,19 +4755,6 @@ msgstr "" msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4660,7 +4772,7 @@ msgid "Part List" msgstr "" #: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: templates/js/company.js:355 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4740,14 +4852,10 @@ msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 -msgid "Calculate" -msgstr "" - #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" @@ -4816,7 +4924,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,7 +4961,7 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" @@ -4922,227 +5030,239 @@ msgstr "" msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:925 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 +#: part/views.py:1027 msgid "Upload Part Image" msgstr "" -#: part/views.py:1022 part/views.py:1057 +#: part/views.py:1033 part/views.py:1068 msgid "Updated part image" msgstr "" -#: part/views.py:1031 +#: part/views.py:1042 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1071 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1082 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1117 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1147 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1168 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1189 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1200 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1334 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1695 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1720 part/views.py:1723 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1729 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1767 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1773 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1777 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2039 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2046 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2055 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2196 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2206 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2213 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2221 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2271 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2285 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 +#: part/views.py:2345 msgid "Edit Part Category" msgstr "" -#: part/views.py:2365 +#: part/views.py:2383 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2389 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2441 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2542 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2598 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2617 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2687 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 +#: part/views.py:2743 msgid "Confim BOM item deletion" msgstr "" -#: report/models.py:180 +#: part/views.py:2831 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2839 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5174,7 +5294,7 @@ msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:195 templates/js/stock.js:1012 msgid "Date" msgstr "" @@ -5197,7 +5317,7 @@ msgid "Moved {n} parts to {loc}" msgstr "" #: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" @@ -5483,12 +5603,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5738,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:593 msgid "No location set" msgstr "" @@ -5630,25 +5750,29 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" @@ -5945,7 +6069,7 @@ msgstr "" msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:1001 users/models.py:187 msgid "Add" msgstr "" @@ -6011,7 +6135,7 @@ msgstr "" msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1575 templates/js/build.js:326 msgid "Create new Stock Item" msgstr "" @@ -6043,14 +6167,6 @@ msgstr "" msgid "Add Stock Tracking Entry" msgstr "" -#: templates/403.html:5 templates/403.html:11 -msgid "Permission Denied" -msgstr "" - -#: templates/403.html:14 -msgid "You do not have permission to view this page." -msgstr "" - #: templates/404.html:5 templates/404.html:11 msgid "Page Not Found" msgstr "" @@ -6119,11 +6235,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6284,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:85 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:86 msgid "Delete Template" msgstr "" @@ -6221,11 +6337,11 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 +#: templates/InvenTree/settings/part.html:44 msgid "Part Parameter Templates" msgstr "" -#: templates/InvenTree/settings/part.html:61 +#: templates/InvenTree/settings/part.html:65 msgid "No part parameter templates found" msgstr "" @@ -6341,47 +6457,51 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 +#: templates/about.html:100 templates/js/modals.js:568 +#: templates/js/modals.js:861 templates/modals.html:29 templates/modals.html:54 #: templates/modals.html:97 msgid "Close" msgstr "" @@ -6442,7 +6562,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:921 msgid "Invalid server response" msgstr "" @@ -6506,7 +6626,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1091 msgid "Open subassembly" msgstr "" @@ -6542,7 +6662,7 @@ msgstr "" msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:470 templates/js/build.js:423 templates/js/build.js:1189 msgid "No BOM items found" msgstr "" @@ -6562,37 +6682,45 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:382 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:325 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:644 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:665 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:735 templates/js/build.js:1153 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:788 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:805 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:966 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:825 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:924 msgid "No parts allocated for" msgstr "" @@ -6612,17 +6740,29 @@ msgstr "" msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:148 templates/js/company.js:347 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:152 templates/js/company.js:351 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:226 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:262 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:263 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:328 msgid "No supplier parts found" msgstr "" @@ -6710,76 +6850,76 @@ msgstr "" msgid "Loading Data" msgstr "" -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:567 templates/js/modals.js:860 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:824 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:921 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 +#: templates/js/modals.js:931 msgid "No Response" msgstr "" -#: templates/js/modals.js:912 +#: templates/js/modals.js:932 msgid "No response from the InvenTree server" msgstr "" -#: templates/js/modals.js:916 +#: templates/js/modals.js:936 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:937 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 +#: templates/js/modals.js:941 msgid "Error 401: Not Authenticated" msgstr "" -#: templates/js/modals.js:922 +#: templates/js/modals.js:942 msgid "Authentication credentials not supplied" msgstr "" -#: templates/js/modals.js:926 +#: templates/js/modals.js:946 msgid "Error 403: Permission Denied" msgstr "" -#: templates/js/modals.js:927 +#: templates/js/modals.js:947 msgid "You do not have the required permissions to access this function" msgstr "" -#: templates/js/modals.js:931 +#: templates/js/modals.js:951 msgid "Error 404: Resource Not Found" msgstr "" -#: templates/js/modals.js:932 +#: templates/js/modals.js:952 msgid "The requested resource could not be located on the server" msgstr "" -#: templates/js/modals.js:936 +#: templates/js/modals.js:956 msgid "Error 408: Timeout" msgstr "" -#: templates/js/modals.js:937 +#: templates/js/modals.js:957 msgid "Connection timeout while requesting data from server" msgstr "" -#: templates/js/modals.js:940 +#: templates/js/modals.js:960 msgid "Error requesting form data" msgstr "" @@ -6795,6 +6935,10 @@ msgstr "" msgid "No sales orders found" msgstr "" +#: templates/js/order.js:343 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +6967,39 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:323 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:990 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:806 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7097,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:853 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:868 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:882 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:883 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1022 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1069 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1088 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1107 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1125 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1148 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1156 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1188 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1200 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1201 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1325 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1366 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1389 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1417 msgid "Uninstall Stock Item" msgstr "" @@ -7267,56 +7411,56 @@ msgstr "" msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" @@ -7560,35 +7704,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:174 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:182 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:187 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:191 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/ru/LC_MESSAGES/django.po b/InvenTree/locale/ru/LC_MESSAGES/django.po index d61e19d068..0b04ba9921 100644 --- a/InvenTree/locale/ru/LC_MESSAGES/django.po +++ b/InvenTree/locale/ru/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:41\n" +"POT-Creation-Date: 2021-06-24 21:38+0000\n" +"PO-Revision-Date: 2021-06-24 21:40\n" "Last-Translator: \n" "Language-Team: Russian\n" "Language: ru_RU\n" @@ -77,7 +77,7 @@ msgstr "Выбрать категорию" msgid "Duplicate serial: {n}" msgstr "Дублировать серийный номер: {n}" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 +#: InvenTree/helpers.py:384 order/models.py:248 order/models.py:358 #: stock/views.py:1795 msgid "Invalid quantity provided" msgstr "недопустимое количество" @@ -122,9 +122,9 @@ msgstr "Комментарий" msgid "File comment" msgstr "Комментарий к файлу" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:2022 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1179 msgid "User" msgstr "Пользователь" @@ -132,34 +132,35 @@ msgstr "Пользователь" msgid "upload date" msgstr "дата загрузки" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:107 InvenTree/models.py:108 company/models.py:396 +#: label/models.py:102 part/models.py:671 part/models.py:2163 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:235 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:972 msgid "Name" msgstr "Название" #: InvenTree/models.py:114 build/models.py:135 #: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: company/models.py:532 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 #: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: order/models.py:104 order/templates/order/purchase_order_detail.html:147 +#: part/models.py:695 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 +#: templates/js/build.js:833 templates/js/build.js:1101 #: templates/js/company.js:56 templates/js/order.js:183 #: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:984 +#: templates/js/stock.js:1029 msgid "Description" msgstr "Описание" @@ -191,15 +192,15 @@ msgstr "Польский" msgid "Turkish" msgstr "Турецкий" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "Проверка фонового работника не удалась" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "Сервер электронной почты не настроен" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "Ошибка проверки состояния системы InvenTree" @@ -372,27 +373,27 @@ msgstr "Перегрузка не может превысить 100%" msgid "Overage must be an integer value or a percentage" msgstr "Превышение должно быть целым числом или процентом" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "Удалить элемент" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "Установите флажок для подтверждения удаления элемента" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "Редактировать информацию о пользователе" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "Установить пароль" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "Пароли должны совпадать" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "Информация о системе" @@ -445,11 +446,11 @@ msgid "Order target date" msgstr "Срок выполнения заказа" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 order/forms.py:114 order/forms.py:149 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 +#: templates/js/build.js:880 templates/js/order.js:200 #: templates/js/order.js:298 msgid "Target Date" msgstr "Целевая дата" @@ -462,22 +463,21 @@ msgstr "Целевая дата для сборки. Сборка будет п #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 +#: build/templates/build/detail.html:31 common/models.py:720 +#: company/forms.py:191 company/templates/company/supplier_part_pricing.html:77 +#: order/forms.py:193 order/forms.py:211 order/forms.py:246 order/forms.py:268 +#: order/forms.py:285 order/models.py:617 order/models.py:841 #: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/order_wizard/select_parts.html:34 #: order/templates/order/purchase_order_detail.html:179 #: order/templates/order/sales_order_detail.html:70 #: order/templates/order/sales_order_detail.html:77 #: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 +#: order/templates/order/sales_order_detail.html:234 part/forms.py:342 +#: part/forms.py:372 part/forms.py:388 part/forms.py:404 part/models.py:2293 +#: part/templates/part/internal_prices.html:98 +#: part/templates/part/order_prices.html:202 +#: part/templates/part/part_pricing.html:16 #: part/templates/part/sale_prices.html:85 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 @@ -486,9 +486,10 @@ msgstr "Целевая дата для сборки. Сборка будет п #: stock/forms.py:175 stock/forms.py:308 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:571 +#: templates/js/build.js:1111 templates/js/order.js:393 +#: templates/js/part.js:796 templates/js/stock.js:1164 +#: templates/js/stock.js:1383 msgid "Quantity" msgstr "Количество" @@ -500,7 +501,7 @@ msgstr "Количество элементов для сборки" msgid "Enter quantity for build output" msgstr "Введите количество для вывода сборки" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:240 stock/forms.py:118 msgid "Serial Numbers" msgstr "Серийные номера" @@ -529,12 +530,12 @@ msgid "Mark build as complete" msgstr "Пометить сборку как завершенную" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:347 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:585 templates/js/order.js:378 +#: templates/js/stock.js:643 templates/js/stock.js:1056 msgid "Location" msgstr "Расположение" @@ -543,13 +544,13 @@ msgid "Location of completed parts" msgstr "Расположение укомплектованных частей" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:469 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:867 #: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: templates/js/stock.js:630 templates/js/stock.js:1133 +#: templates/js/stock.js:1399 msgid "Status" msgstr "Статус" @@ -583,16 +584,16 @@ msgstr "Выберите количество запасов для распре #: build/models.py:66 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "Порядок сборки" #: build/models.py:67 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:57 +#: part/templates/part/navbar.html:60 templates/InvenTree/index.html:183 #: templates/InvenTree/search.html:185 #: templates/InvenTree/settings/tabs.html:34 users/models.py:43 msgid "Build Orders" @@ -602,12 +603,12 @@ msgstr "Порядок сборки" msgid "Build Order Reference" msgstr "Ссылка на заказ" -#: build/models.py:128 order/models.py:101 order/models.py:618 +#: build/models.py:128 order/models.py:102 order/models.py:619 #: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: order/templates/order/sales_order_detail.html:229 part/models.py:2302 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:660 templates/js/build.js:1105 msgid "Reference" msgstr "" @@ -626,27 +627,27 @@ msgstr "" #: build/models.py:153 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 +#: build/templates/build/detail.html:26 company/models.py:663 +#: order/models.py:661 order/models.py:717 +#: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:132 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:214 part/models.py:321 +#: part/models.py:1975 part/models.py:1987 part/models.py:2002 +#: part/models.py:2020 part/models.py:2095 part/models.py:2191 +#: part/models.py:2277 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:551 templates/js/build.js:838 +#: templates/js/build.js:1078 templates/js/company.js:140 +#: templates/js/company.js:339 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1371 msgid "Part" msgstr "" @@ -710,16 +711,16 @@ msgstr "" msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 +#: build/models.py:220 order/models.py:108 part/models.py:867 #: part/templates/part/detail.html:126 templates/js/order.js:293 msgid "Creation Date" msgstr "" -#: build/models.py:224 order/models.py:474 +#: build/models.py:224 order/models.py:475 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:228 order/models.py:221 templates/js/build.js:885 msgid "Completion Date" msgstr "" @@ -736,9 +737,9 @@ msgid "User who issued this build order" msgstr "" #: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/templates/build/detail.html:105 order/models.py:122 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:871 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "" @@ -757,26 +758,26 @@ msgstr "" msgid "External Link" msgstr "" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:258 part/models.py:729 stock/models.py:462 msgid "Link to external URL" msgstr "" #: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: company/models.py:132 company/models.py:539 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:126 +#: order/models.py:621 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:243 +#: order/templates/order/sales_order_detail.html:309 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:856 +#: part/templates/part/navbar.html:142 #: report/templates/report/inventree_build_order_base.html:173 #: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 #: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:699 msgid "Notes" msgstr "" @@ -809,11 +810,11 @@ msgstr "" msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1188 order/models.py:815 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1192 order/models.py:818 msgid "Allocation quantity must be greater than zero" msgstr "" @@ -827,7 +828,7 @@ msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" #: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: templates/InvenTree/search.html:183 templates/js/build.js:811 #: templates/navbar.html:29 msgid "Build" msgstr "" @@ -836,15 +837,13 @@ msgstr "" msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1333 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:928 +#: templates/js/order.js:366 templates/js/order.js:371 +#: templates/js/stock.js:1115 msgid "Stock Item" msgstr "" @@ -880,7 +879,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:743 msgid "Unallocate stock" msgstr "" @@ -917,15 +916,15 @@ msgstr "" #: order/templates/order/sales_order_detail.html:160 #: report/templates/report/inventree_test_report_base.html:75 #: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: templates/js/build.js:569 msgid "Serial Number" msgstr "" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:133 +#: part/templates/part/navbar.html:136 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "" @@ -1037,11 +1036,10 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:715 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 #: stock/templates/stock/item_base.html:279 templates/js/order.js:245 @@ -1185,7 +1183,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:85 order/models.py:678 +#: order/templates/order/purchase_order_detail.html:239 +#: order/templates/order/receive_parts.html:25 stock/forms.py:169 +#: stock/forms.py:375 msgid "Destination" msgstr "" @@ -1194,15 +1195,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1406 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:875 msgid "Created" msgstr "" @@ -1210,7 +1211,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:853 msgid "Completed" msgstr "" @@ -1248,9 +1249,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:17 +#: templates/js/stock.js:1044 msgid "Details" msgstr "" @@ -1285,8 +1286,8 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 +#: stock/templates/stock/item_base.html:497 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "" @@ -1411,8 +1412,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:670 +#: templates/js/build.js:935 templates/js/build.js:1118 msgid "Available" msgstr "" @@ -1598,8 +1599,8 @@ msgstr "" msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 +#: common/models.py:153 part/models.py:2193 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:259 templates/js/table_filters.js:25 #: templates/js/table_filters.js:315 msgid "Template" msgstr "" @@ -1608,7 +1609,7 @@ msgstr "" msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 +#: common/models.py:160 part/models.py:819 part/templates/part/detail.html:170 #: templates/js/table_filters.js:128 templates/js/table_filters.js:327 msgid "Assembly" msgstr "" @@ -1617,7 +1618,7 @@ msgstr "" msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 +#: common/models.py:167 part/models.py:825 part/templates/part/detail.html:180 #: templates/js/table_filters.js:331 msgid "Component" msgstr "" @@ -1626,7 +1627,7 @@ msgstr "" msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:174 part/models.py:836 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" @@ -1634,7 +1635,7 @@ msgstr "" msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 +#: common/models.py:181 part/models.py:841 part/templates/part/detail.html:210 #: templates/js/table_filters.js:339 msgid "Salable" msgstr "" @@ -1643,7 +1644,7 @@ msgstr "" msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 +#: common/models.py:188 part/models.py:831 part/templates/part/detail.html:190 #: templates/js/table_filters.js:33 templates/js/table_filters.js:343 msgid "Trackable" msgstr "" @@ -1652,7 +1653,7 @@ msgstr "" msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:195 part/models.py:851 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" @@ -1669,160 +1670,185 @@ msgstr "" msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" +#: common/models.py:209 +msgid "Show Price in Forms" msgstr "" #: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" +msgid "Display part price in some forms" msgstr "" #: common/models.py:216 -msgid "Page Size" +msgid "Internal Prices" msgstr "" #: common/models.py:217 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:223 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:224 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:230 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:231 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:237 +msgid "Page Size" +msgstr "" + +#: common/models.py:238 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:248 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:249 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:255 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:256 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:262 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:263 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:269 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:270 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:272 part/templates/part/detail.html:121 msgid "days" msgstr "" -#: common/models.py:256 +#: common/models.py:277 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:278 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:284 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:285 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:291 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:292 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:298 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:299 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:305 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:306 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:311 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:312 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:316 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:317 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:322 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:323 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:546 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:548 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:583 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:606 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:617 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:640 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:721 company/forms.py:192 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 +#: common/models.py:729 company/templates/company/supplier_part_pricing.html:82 +#: part/templates/part/internal_prices.html:103 #: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:730 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:822 msgid "Default" msgstr "" @@ -1843,7 +1869,9 @@ msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:582 +#: part/templates/part/bom_upload/upload_file.html:27 msgid "Upload File" msgstr "" @@ -1877,29 +1905,29 @@ msgstr "" msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:133 templates/js/part.js:787 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:135 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:143 company/models.py:321 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:149 company/models.py:328 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:151 company/models.py:327 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 #: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:408 msgid "MPN" msgstr "" @@ -1952,11 +1980,11 @@ msgstr "" msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:121 company/models.py:333 company/models.py:526 +#: order/models.py:106 part/models.py:728 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:188 templates/js/company.js:419 +#: templates/js/part.js:498 msgid "Link" msgstr "" @@ -1964,7 +1992,7 @@ msgstr "" msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:129 part/models.py:738 msgid "Image" msgstr "" @@ -1992,12 +2020,12 @@ msgstr "" msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:305 company/models.py:497 stock/models.py:407 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:309 company/models.py:501 order/views.py:1597 msgid "Select part" msgstr "" @@ -2008,7 +2036,7 @@ msgstr "" #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 #: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:390 msgid "Manufacturer" msgstr "" @@ -2020,87 +2048,112 @@ msgstr "" msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:390 company/models.py:520 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:397 +msgid "Parameter name" +msgstr "" + +#: company/models.py:403 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:241 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:404 +msgid "Parameter value" +msgstr "" + +#: company/models.py:410 part/models.py:813 part/models.py:2165 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:247 +msgid "Units" +msgstr "" + +#: company/models.py:411 +msgid "Parameter units" +msgstr "" + +#: company/models.py:507 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:193 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:48 templates/js/company.js:364 #: templates/js/order.js:170 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:508 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:513 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 #: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:514 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:521 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:527 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:533 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:538 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2305 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 +#: company/models.py:544 company/templates/company/supplier_part_base.html:109 #: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: templates/js/stock.js:695 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:544 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:546 part/models.py:1608 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:546 msgid "Order multiple" msgstr "" #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:562 msgid "Assigned Stock" msgstr "" @@ -2165,11 +2218,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 +#: company/templates/company/detail.html:67 order/models.py:464 #: order/templates/order/sales_order_base.html:94 stock/models.py:449 #: stock/models.py:450 stock/templates/stock/item_base.html:262 #: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: templates/js/stock.js:1097 msgid "Customer" msgstr "" @@ -2215,7 +2268,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:66 #: company/templates/company/detail_supplier_part.html:66 #: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: templates/js/stock.js:1312 msgid "New Part" msgstr "" @@ -2248,13 +2301,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 +#: order/templates/order/order_wizard/select_parts.html:44 #: order/templates/order/purchase_order_detail.html:50 msgid "Create new supplier part" msgstr "" @@ -2262,12 +2314,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 #: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/supplier.html:17 templates/js/stock.js:1318 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 +#: company/templates/company/manufacturer_part_suppliers.html:82 #: company/views.py:64 order/templates/order/purchase_orders.html:185 #: part/templates/part/supplier.html:50 msgid "New Supplier" @@ -2319,8 +2371,9 @@ msgid "There are %(count)s suppliers defined for this manufacturer part. If you msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:63 part/templates/part/navbar.html:86 +#: part/templates/part/navbar.html:89 templates/InvenTree/search.html:316 #: templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,13 +2385,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:38 stock/api.py:54 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2360,11 +2413,25 @@ msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:1002 users/models.py:191 msgid "Delete" msgstr "" -#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:34 +#: part/templates/part/category_navbar.html:37 +#: part/templates/part/navbar.html:24 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:48 +msgid "New Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:83 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" @@ -2379,13 +2446,13 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:35 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 +#: templates/InvenTree/search.html:198 templates/js/stock.js:996 #: templates/stats.html:93 templates/stats.html:102 users/models.py:42 msgid "Stock Items" msgstr "" @@ -2396,7 +2463,7 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 +#: part/templates/part/navbar.html:112 part/templates/part/navbar.html:115 #: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 @@ -2408,7 +2475,7 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 +#: part/templates/part/navbar.html:92 part/templates/part/navbar.html:95 #: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 @@ -2442,7 +2509,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:7 #: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:380 msgid "Supplier Part" msgstr "" @@ -2490,8 +2557,8 @@ msgstr "" msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 company/views.py:855 +#: part/templates/part/sale_prices.html:17 part/views.py:2751 msgid "Add Price Break" msgstr "" @@ -2510,8 +2577,8 @@ msgstr "" msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 +#: company/views.py:70 part/templates/part/navbar.html:80 +#: part/templates/part/navbar.html:83 templates/InvenTree/search.html:306 #: templates/navbar.html:36 msgid "Manufacturers" msgstr "" @@ -2533,20 +2600,20 @@ msgstr "" msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:169 part/views.py:948 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:198 part/views.py:980 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:205 part/views.py:987 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:214 part/views.py:996 msgid "Supplied URL is not a valid image file" msgstr "" @@ -2594,27 +2661,35 @@ msgstr "" msgid "Delete Manufacturer Part" msgstr "" -#: company/views.py:528 +#: company/views.py:514 +msgid "Add Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:548 +msgid "Edit Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:588 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:639 templates/js/stock.js:1319 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:783 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 +#: company/views.py:860 part/views.py:2755 msgid "Added new price break" msgstr "" -#: company/views.py:855 part/views.py:2781 +#: company/views.py:916 part/views.py:2799 msgid "Edit Price Break" msgstr "" -#: company/views.py:870 part/views.py:2795 +#: company/views.py:931 part/views.py:2813 msgid "Delete Price Break" msgstr "" @@ -2638,7 +2713,7 @@ msgstr "" msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:124 report/models.py:297 msgid "Enabled" msgstr "" @@ -2662,7 +2737,7 @@ msgstr "" msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:144 report/models.py:290 msgid "Filename Pattern" msgstr "" @@ -2674,8 +2749,8 @@ msgstr "" msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:245 label/models.py:298 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" @@ -2696,237 +2771,239 @@ msgstr "" msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:86 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 +#: order/forms.py:108 msgid "Purchase Order reference" msgstr "" -#: order/forms.py:110 +#: order/forms.py:115 msgid "Target date for order delivery. Order will be overdue after this date." msgstr "" -#: order/forms.py:138 +#: order/forms.py:143 msgid "Enter sales order number" msgstr "" -#: order/forms.py:145 order/models.py:475 +#: order/forms.py:150 order/models.py:476 msgid "Target date for order completion. Order will be overdue after this date." msgstr "" -#: order/forms.py:236 +#: order/forms.py:242 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:248 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 +#: order/models.py:102 msgid "Order reference" msgstr "" -#: order/models.py:103 +#: order/models.py:104 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:106 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:114 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:121 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:126 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:185 order/models.py:469 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:194 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 +#: order/models.py:197 order/templates/order/order_base.html:98 #: templates/js/order.js:179 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:197 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:204 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:209 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:210 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:215 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:216 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:222 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 +#: order/models.py:246 part/views.py:1686 stock/models.py:304 #: stock/models.py:1020 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:251 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:349 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:353 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:355 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:465 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:479 templates/js/order.js:303 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:486 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:530 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:617 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:619 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:621 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:647 order/models.py:715 templates/js/order.js:353 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:648 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 #: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: templates/js/stock.js:669 templates/js/stock.js:1078 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:662 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 +#: order/models.py:665 order/templates/order/order_base.html:131 #: order/templates/order/purchase_order_detail.html:219 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:665 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:672 stock/models.py:542 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:690 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:673 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:681 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:724 part/templates/part/navbar.html:109 +#: part/templates/part/order_prices.html:107 +#: part/templates/part/part_pricing.html:97 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:725 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:800 order/models.py:802 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:806 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:808 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:811 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:821 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:826 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:837 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:838 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:841 msgid "Enter stock allocation quantity" msgstr "" @@ -2955,7 +3032,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2977,8 +3054,8 @@ msgstr "" #: order/templates/order/order_base.html:180 #: order/templates/order/purchase_order_detail.html:100 #: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: stock/templates/stock/location.html:191 templates/js/stock.js:736 +#: templates/js/stock.js:1324 msgid "New Location" msgstr "" @@ -3081,28 +3158,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3135,15 +3216,20 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +#: order/templates/order/so_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,8 +3239,8 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/sales_order_detail.html:22 order/views.py:1321 +#: order/views.py:1404 msgid "Add Line Item" msgstr "" @@ -3162,25 +3248,31 @@ msgstr "" msgid "No line items found" msgstr "" +#: order/templates/order/purchase_order_detail.html:142 +#: order/templates/order/sales_order_detail.html:223 +msgid "Total" +msgstr "" + #: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/sales_order_detail.html:246 msgid "Unit Price" msgstr "" #: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/sales_order_detail.html:253 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:255 +#: order/templates/order/sales_order_detail.html:359 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:256 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:261 msgid "Receive line item" msgstr "" @@ -3201,7 +3293,7 @@ msgstr "" #: part/templates/part/category_navbar.html:29 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 #: users/models.py:40 msgid "Parts" @@ -3216,7 +3308,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3316,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3265,17 +3357,17 @@ msgid "Sales Order Items" msgstr "" #: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: templates/js/build.js:724 templates/js/build.js:1141 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:610 +#: templates/js/build.js:946 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:612 +#: templates/js/build.js:947 msgid "Delete stock allocation" msgstr "" @@ -3283,50 +3375,50 @@ msgstr "" msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:206 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:274 templates/js/build.js:675 +#: templates/js/build.js:942 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:276 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:313 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:343 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:346 templates/js/build.js:738 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:349 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:353 templates/js/build.js:731 +#: templates/js/build.js:1149 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:356 +#: order/templates/order/sales_order_detail.html:465 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:360 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:471 msgid "Update Unit Price" msgstr "" @@ -3367,10 +3459,6 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - #: order/views.py:104 msgid "Add Purchase Order Attachment" msgstr "" @@ -3471,90 +3559,94 @@ msgstr "" msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:1012 +msgid "Update prices" +msgstr "" + +#: order/views.py:1270 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 +#: order/views.py:1330 msgid "Supplier part must be specified" msgstr "" -#: order/views.py:1326 +#: order/views.py:1336 msgid "Supplier must match for Part and Order" msgstr "" -#: order/views.py:1457 order/views.py:1475 +#: order/views.py:1467 order/views.py:1485 msgid "Edit Line Item" msgstr "" -#: order/views.py:1491 order/views.py:1503 +#: order/views.py:1501 order/views.py:1513 msgid "Delete Line Item" msgstr "" -#: order/views.py:1496 order/views.py:1508 +#: order/views.py:1506 order/views.py:1518 msgid "Deleted line item" msgstr "" -#: order/views.py:1521 +#: order/views.py:1531 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1576 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1592 msgid "Select line item" msgstr "" -#: order/views.py:1613 -#, python-brace-format -msgid "No matching item for serial {serial}" -msgstr "" - #: order/views.py:1623 #, python-brace-format +msgid "No matching item for serial {serial}" +msgstr "" + +#: order/views.py:1633 +#, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1641 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1695 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1769 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1784 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1856 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1862 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1865 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1870 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 +#: part/bom.py:138 part/models.py:72 part/models.py:747 #: part/templates/part/category.html:66 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3632,7 +3724,7 @@ msgstr "" msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:122 part/models.py:2191 msgid "Parent Part" msgstr "" @@ -3708,7 +3800,7 @@ msgstr "" msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:344 part/models.py:2286 msgid "Sub part" msgstr "" @@ -3728,7 +3820,7 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:82 part/models.py:2237 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" @@ -3739,365 +3831,360 @@ msgstr "" msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:448 part/models.py:460 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:557 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:561 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:566 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:645 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:670 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:677 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:678 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:689 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:690 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:696 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:701 part/templates/part/category.html:73 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:702 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:709 part/models.py:2236 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:710 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:715 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "" -#: part/models.py:731 +#: part/models.py:716 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:722 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:723 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:745 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:792 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:793 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:800 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:801 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:806 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:807 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:814 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:820 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:826 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:832 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:837 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:842 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:846 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 #: templates/js/table_filters.js:241 templates/js/table_filters.js:310 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:847 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:852 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:857 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:863 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:865 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:869 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1608 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2063 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2080 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2100 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2101 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2106 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2107 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 +#: part/models.py:2112 templates/js/part.js:726 #: templates/js/table_filters.js:227 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2113 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2118 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2119 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2124 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2125 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2158 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2163 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2165 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2193 part/models.py:2242 part/models.py:2243 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2247 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2248 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2278 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2287 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2293 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2295 templates/js/bom.js:216 templates/js/bom.js:285 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2295 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2298 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2299 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2302 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2305 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2311 templates/js/bom.js:302 templates/js/bom.js:309 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2312 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2317 templates/js/bom.js:294 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2318 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 +#: part/models.py:2394 part/views.py:1692 part/views.py:1744 #: stock/models.py:294 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2403 part/models.py:2405 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2408 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2527 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2563 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 @@ -4112,8 +4199,8 @@ msgstr "" msgid "Deleting this entry will remove the BOM row from the following part" msgstr "" -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:50 +#: part/templates/part/navbar.html:53 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4247,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:1987 msgid "Export Bill of Materials" msgstr "" @@ -4177,7 +4264,7 @@ msgid "All selected BOM items will be deleted" msgstr "" #: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: templates/js/stock.js:1313 msgid "Create New Part" msgstr "" @@ -4258,7 +4345,7 @@ msgstr "" msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:29 part/views.py:2397 msgid "Create new part category" msgstr "" @@ -4318,7 +4405,7 @@ msgid "View grid display" msgstr "" #: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: stock/templates/stock/location.html:192 templates/js/stock.js:737 msgid "Create new location" msgstr "" @@ -4373,14 +4460,8 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 -#: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" -msgstr "" - #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:21 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" @@ -4408,7 +4489,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:13 msgid "Part Details" msgstr "" @@ -4488,6 +4569,36 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/internal_prices.html:11 +#: part/templates/part/navbar.html:100 +msgid "Internal Price Information" +msgstr "" + +#: part/templates/part/internal_prices.html:19 part/views.py:2822 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/internal_prices.html:28 templates/403.html:5 +#: templates/403.html:11 +msgid "Permission Denied" +msgstr "" + +#: part/templates/part/internal_prices.html:31 templates/403.html:14 +msgid "You do not have permission to view this page." +msgstr "" + +#: part/templates/part/internal_prices.html:59 +msgid "No internal price break information found" +msgstr "" + +#: part/templates/part/internal_prices.html:110 +msgid "Edit internal price break" +msgstr "" + +#: part/templates/part/internal_prices.html:111 +msgid "Delete internal price break" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4501,127 +4612,141 @@ msgstr "" msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:28 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:31 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:42 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:45 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:66 part/templates/part/navbar.html:69 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 +#: part/templates/part/navbar.html:74 part/templates/part/order_prices.html:12 msgid "Order Price Information" msgstr "" -#: part/templates/part/navbar.html:75 +#: part/templates/part/navbar.html:77 msgid "Order Price" msgstr "" -#: part/templates/part/navbar.html:98 +#: part/templates/part/navbar.html:103 part/templates/part/order_prices.html:93 +#: part/templates/part/part_pricing.html:82 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/navbar.html:106 msgid "Sales Price Information" msgstr "" -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:120 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:123 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:127 part/templates/part/navbar.html:130 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:139 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 +#: part/templates/part/order_prices.html:24 +#: part/templates/part/part_base.html:282 +msgid "Calculate" +msgstr "" + +#: part/templates/part/order_prices.html:31 msgid "Pricing ranges" msgstr "" -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 +#: part/templates/part/order_prices.html:36 +#: part/templates/part/part_pricing.html:22 msgid "Supplier Pricing" msgstr "" -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 +#: part/templates/part/order_prices.html:37 +#: part/templates/part/order_prices.html:62 +#: part/templates/part/order_prices.html:94 +#: part/templates/part/order_prices.html:108 +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 msgid "Unit Cost" msgstr "" -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 +#: part/templates/part/order_prices.html:44 +#: part/templates/part/order_prices.html:69 +#: part/templates/part/order_prices.html:99 +#: part/templates/part/order_prices.html:113 +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 msgid "Total Cost" msgstr "" -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 +#: part/templates/part/order_prices.html:52 +#: part/templates/part/part_pricing.html:40 msgid "No supplier pricing available" msgstr "" -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 +#: part/templates/part/order_prices.html:61 +#: part/templates/part/order_prices.html:128 +#: part/templates/part/part_pricing.html:48 msgid "BOM Pricing" msgstr "" -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 +#: part/templates/part/order_prices.html:77 +#: part/templates/part/part_pricing.html:66 msgid "Note: BOM pricing is incomplete for this part" msgstr "" -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 +#: part/templates/part/order_prices.html:84 +#: part/templates/part/part_pricing.html:73 msgid "No BOM pricing available" msgstr "" -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 +#: part/templates/part/order_prices.html:122 +#: part/templates/part/part_pricing.html:113 msgid "No pricing information is available for this part." msgstr "" -#: part/templates/part/order_prices.html:113 +#: part/templates/part/order_prices.html:138 msgid "Stock Pricing" msgstr "" -#: part/templates/part/order_prices.html:121 +#: part/templates/part/order_prices.html:146 msgid "No stock pricing history is available for this part." msgstr "" -#: part/templates/part/order_prices.html:140 +#: part/templates/part/order_prices.html:165 #, python-format msgid "Single Price - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:152 +#: part/templates/part/order_prices.html:177 #, python-format msgid "Single Price Difference - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:163 +#: part/templates/part/order_prices.html:189 #, python-format msgid "Part Single Price - %(currency)s" msgstr "" @@ -4630,19 +4755,6 @@ msgstr "" msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4660,7 +4772,7 @@ msgid "Part List" msgstr "" #: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: templates/js/company.js:355 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4740,14 +4852,10 @@ msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 -msgid "Calculate" -msgstr "" - #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" @@ -4816,7 +4924,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,7 +4961,7 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" @@ -4922,227 +5030,239 @@ msgstr "" msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:925 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 +#: part/views.py:1027 msgid "Upload Part Image" msgstr "" -#: part/views.py:1022 part/views.py:1057 +#: part/views.py:1033 part/views.py:1068 msgid "Updated part image" msgstr "" -#: part/views.py:1031 +#: part/views.py:1042 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1071 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1082 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1117 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1147 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1168 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1189 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1200 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1334 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1695 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1720 part/views.py:1723 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1729 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1767 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1773 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1777 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2039 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2046 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2055 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2196 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2206 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2213 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2221 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2271 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2285 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 +#: part/views.py:2345 msgid "Edit Part Category" msgstr "" -#: part/views.py:2365 +#: part/views.py:2383 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2389 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2441 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2542 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2598 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2617 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2687 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 +#: part/views.py:2743 msgid "Confim BOM item deletion" msgstr "" -#: report/models.py:180 +#: part/views.py:2831 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2839 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5174,7 +5294,7 @@ msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:195 templates/js/stock.js:1012 msgid "Date" msgstr "" @@ -5197,7 +5317,7 @@ msgid "Moved {n} parts to {loc}" msgstr "" #: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" @@ -5483,12 +5603,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5738,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:593 msgid "No location set" msgstr "" @@ -5630,25 +5750,29 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" @@ -5945,7 +6069,7 @@ msgstr "" msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:1001 users/models.py:187 msgid "Add" msgstr "" @@ -6011,7 +6135,7 @@ msgstr "" msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1575 templates/js/build.js:326 msgid "Create new Stock Item" msgstr "" @@ -6043,14 +6167,6 @@ msgstr "" msgid "Add Stock Tracking Entry" msgstr "" -#: templates/403.html:5 templates/403.html:11 -msgid "Permission Denied" -msgstr "" - -#: templates/403.html:14 -msgid "You do not have permission to view this page." -msgstr "" - #: templates/404.html:5 templates/404.html:11 msgid "Page Not Found" msgstr "" @@ -6119,11 +6235,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6284,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:85 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:86 msgid "Delete Template" msgstr "" @@ -6221,11 +6337,11 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 +#: templates/InvenTree/settings/part.html:44 msgid "Part Parameter Templates" msgstr "" -#: templates/InvenTree/settings/part.html:61 +#: templates/InvenTree/settings/part.html:65 msgid "No part parameter templates found" msgstr "" @@ -6341,47 +6457,51 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 +#: templates/about.html:100 templates/js/modals.js:568 +#: templates/js/modals.js:861 templates/modals.html:29 templates/modals.html:54 #: templates/modals.html:97 msgid "Close" msgstr "" @@ -6442,7 +6562,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:921 msgid "Invalid server response" msgstr "" @@ -6506,7 +6626,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1091 msgid "Open subassembly" msgstr "" @@ -6542,7 +6662,7 @@ msgstr "" msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:470 templates/js/build.js:423 templates/js/build.js:1189 msgid "No BOM items found" msgstr "" @@ -6562,37 +6682,45 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:382 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:325 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:644 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:665 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:735 templates/js/build.js:1153 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:788 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:805 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:966 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:825 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:924 msgid "No parts allocated for" msgstr "" @@ -6612,17 +6740,29 @@ msgstr "" msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:148 templates/js/company.js:347 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:152 templates/js/company.js:351 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:226 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:262 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:263 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:328 msgid "No supplier parts found" msgstr "" @@ -6710,76 +6850,76 @@ msgstr "" msgid "Loading Data" msgstr "" -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:567 templates/js/modals.js:860 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:824 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:921 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 +#: templates/js/modals.js:931 msgid "No Response" msgstr "" -#: templates/js/modals.js:912 +#: templates/js/modals.js:932 msgid "No response from the InvenTree server" msgstr "" -#: templates/js/modals.js:916 +#: templates/js/modals.js:936 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:937 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 +#: templates/js/modals.js:941 msgid "Error 401: Not Authenticated" msgstr "" -#: templates/js/modals.js:922 +#: templates/js/modals.js:942 msgid "Authentication credentials not supplied" msgstr "" -#: templates/js/modals.js:926 +#: templates/js/modals.js:946 msgid "Error 403: Permission Denied" msgstr "" -#: templates/js/modals.js:927 +#: templates/js/modals.js:947 msgid "You do not have the required permissions to access this function" msgstr "" -#: templates/js/modals.js:931 +#: templates/js/modals.js:951 msgid "Error 404: Resource Not Found" msgstr "" -#: templates/js/modals.js:932 +#: templates/js/modals.js:952 msgid "The requested resource could not be located on the server" msgstr "" -#: templates/js/modals.js:936 +#: templates/js/modals.js:956 msgid "Error 408: Timeout" msgstr "" -#: templates/js/modals.js:937 +#: templates/js/modals.js:957 msgid "Connection timeout while requesting data from server" msgstr "" -#: templates/js/modals.js:940 +#: templates/js/modals.js:960 msgid "Error requesting form data" msgstr "" @@ -6795,6 +6935,10 @@ msgstr "" msgid "No sales orders found" msgstr "" +#: templates/js/order.js:343 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +6967,39 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:323 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:990 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:806 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7097,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:853 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:868 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:882 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:883 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1022 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1069 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1088 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1107 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1125 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1148 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1156 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1188 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1200 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1201 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1325 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1366 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1389 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1417 msgid "Uninstall Stock Item" msgstr "" @@ -7267,56 +7411,56 @@ msgstr "" msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" @@ -7560,35 +7704,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:174 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:182 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:187 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:191 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/tr/LC_MESSAGES/django.po b/InvenTree/locale/tr/LC_MESSAGES/django.po index e30c1ed591..20d48e6e5b 100644 --- a/InvenTree/locale/tr/LC_MESSAGES/django.po +++ b/InvenTree/locale/tr/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:41\n" +"POT-Creation-Date: 2021-06-24 21:38+0000\n" +"PO-Revision-Date: 2021-06-24 21:40\n" "Last-Translator: \n" "Language-Team: Turkish\n" "Language: tr_TR\n" @@ -19,11 +19,11 @@ msgstr "" #: InvenTree/api.py:64 msgid "API endpoint not found" -msgstr "API uçnoktası bulunmadı" +msgstr "API uç noktası bulunamadı" #: InvenTree/api.py:110 msgid "No action specified" -msgstr "Hiçbir eylem belirtilmedi" +msgstr "İşlem belirtilmedi" #: InvenTree/api.py:124 msgid "No matching action found" @@ -77,7 +77,7 @@ msgstr "Kategori Seçin" msgid "Duplicate serial: {n}" msgstr "Tekrarlanan seri {n}" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 +#: InvenTree/helpers.py:384 order/models.py:248 order/models.py:358 #: stock/views.py:1795 msgid "Invalid quantity provided" msgstr "Geçersiz veri sağlandı" @@ -104,7 +104,7 @@ msgstr "Seri numarası bulunamadı" #: InvenTree/helpers.py:457 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" -msgstr "Benzersiz serinin numaraları ({s}) miktarla eşleşmeli ({q})" +msgstr "Benzersiz seri numaralarının sayısı ({s}) girilen miktarla eşleşmeli ({q})" #: InvenTree/models.py:59 stock/models.py:1763 msgid "Attachment" @@ -120,56 +120,57 @@ msgstr "Yorum" #: InvenTree/models.py:62 msgid "File comment" -msgstr "Yorum" +msgstr "Dosya yorumu" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:2022 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1179 msgid "User" msgstr "Kullanıcı" #: InvenTree/models.py:72 msgid "upload date" -msgstr "Yükleme tarihi" +msgstr "yükleme tarihi" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:107 InvenTree/models.py:108 company/models.py:396 +#: label/models.py:102 part/models.py:671 part/models.py:2163 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:235 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:972 msgid "Name" msgstr "Adı" #: InvenTree/models.py:114 build/models.py:135 #: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: company/models.py:532 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 #: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: order/models.py:104 order/templates/order/purchase_order_detail.html:147 +#: part/models.py:695 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 +#: templates/js/build.js:833 templates/js/build.js:1101 #: templates/js/company.js:56 templates/js/order.js:183 #: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:984 +#: templates/js/stock.js:1029 msgid "Description" msgstr "Açıklama" #: InvenTree/models.py:115 msgid "Description (optional)" -msgstr "Açıklama(opsiyonel)" +msgstr "Açıklama (isteğe bağlı)" #: InvenTree/models.py:123 msgid "parent" -msgstr "ebeveyn" +msgstr "üst" #: InvenTree/settings.py:503 msgid "English" @@ -191,15 +192,15 @@ msgstr "Polonyaca" msgid "Turkish" msgstr "Türkçe" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "Arka plan çalışanı kontrolü başarısız oldu" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "E-posta arka ucu yapılandırılmadı" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "InvenTree sistem sağlık kontrolü başarısız" @@ -258,79 +259,79 @@ msgstr "Reddedildi" #: InvenTree/status_codes.py:272 msgid "Legacy stock tracking entry" -msgstr "" +msgstr "Eski stok izleme girişi" #: InvenTree/status_codes.py:274 msgid "Stock item created" -msgstr "" +msgstr "Stok kalemi oluşturuldu" #: InvenTree/status_codes.py:276 msgid "Edited stock item" -msgstr "" +msgstr "Düzenlenen stok kalemi" #: InvenTree/status_codes.py:277 msgid "Assigned serial number" -msgstr "" +msgstr "Atanan seri numarası" #: InvenTree/status_codes.py:279 msgid "Stock counted" -msgstr "" +msgstr "Stok sayıldı" #: InvenTree/status_codes.py:280 msgid "Stock manually added" -msgstr "" +msgstr "Stok manuel olarak eklendi" #: InvenTree/status_codes.py:281 msgid "Stock manually removed" -msgstr "" +msgstr "Stok manuel olarak çıkarıldı" #: InvenTree/status_codes.py:283 msgid "Location changed" -msgstr "" +msgstr "Konum değişti" #: InvenTree/status_codes.py:285 msgid "Installed into assembly" -msgstr "" +msgstr "Montajda kullanıldı" #: InvenTree/status_codes.py:286 msgid "Removed from assembly" -msgstr "" +msgstr "Montajdan çıkarıldı" #: InvenTree/status_codes.py:288 msgid "Installed component item" -msgstr "" +msgstr "Bileşen ögesinde kullanıldı" #: InvenTree/status_codes.py:289 msgid "Removed component item" -msgstr "" +msgstr "Bileşen ögesinden çıkarıldı" #: InvenTree/status_codes.py:291 msgid "Split from parent item" -msgstr "" +msgstr "Üst ögeden ayır" #: InvenTree/status_codes.py:292 msgid "Split child item" -msgstr "" +msgstr "Alt ögeyi ayır" #: InvenTree/status_codes.py:294 templates/js/table_filters.js:181 msgid "Sent to customer" -msgstr "" +msgstr "Müşteriye gönderildi" #: InvenTree/status_codes.py:295 msgid "Returned from customer" -msgstr "" +msgstr "Müşteriden geri döndü" #: InvenTree/status_codes.py:297 msgid "Build order output created" -msgstr "" +msgstr "Yapım emri çıktısı oluşturuldu" #: InvenTree/status_codes.py:298 msgid "Build order output completed" -msgstr "" +msgstr "Yapım emri çıktısı tamamlandı" #: InvenTree/status_codes.py:300 msgid "Received against purchase order" -msgstr "" +msgstr "Satın alma emri karşılığında alındı" #: InvenTree/status_codes.py:315 msgid "Production" @@ -338,11 +339,11 @@ msgstr "Üretim" #: InvenTree/validators.py:22 msgid "Not a valid currency code" -msgstr "Geçerli para birimi yok" +msgstr "Geçerli bir para birimi kodu değil" #: InvenTree/validators.py:50 msgid "Invalid character in part name" -msgstr "Parça adında geçersiniz karakter bulunuyor" +msgstr "Parça adında geçersiz karakter" #: InvenTree/validators.py:63 #, python-brace-format @@ -353,131 +354,130 @@ msgstr "IPN regex kalıbıyla eşleşmelidir {pat}" #: InvenTree/validators.py:105 #, python-brace-format msgid "Reference must match pattern {pattern}" -msgstr "" +msgstr "Referans {pattern} deseniyle mutlaka eşleşmeli" #: InvenTree/validators.py:113 #, python-brace-format msgid "Illegal character in name ({x})" -msgstr "" +msgstr "({x}) adında geçersiz karakter" #: InvenTree/validators.py:132 InvenTree/validators.py:148 msgid "Overage value must not be negative" -msgstr "" +msgstr "Fazlalık değeri negatif olmamalıdır" #: InvenTree/validators.py:150 msgid "Overage must not exceed 100%" -msgstr "" +msgstr "Fazlalık %100'ü geçmemelidir" #: InvenTree/validators.py:157 msgid "Overage must be an integer value or a percentage" -msgstr "" +msgstr "Fazlalık bir tamsayı veya yüzde olmalıdır" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" -msgstr "" +msgstr "Ögeyi Sil" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" -msgstr "" +msgstr "Öge silme işlemini onaylamak için kutuyu işaretleyin" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" -msgstr "" +msgstr "Kullanıcı Bilgisini Düzenle" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" -msgstr "" +msgstr "Şifre Belirle" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" -msgstr "" +msgstr "Parola alanları eşleşmelidir" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" -msgstr "" +msgstr "Sistem Bilgisi" #: barcodes/api.py:53 barcodes/api.py:150 msgid "Must provide barcode_data parameter" -msgstr "" +msgstr "Barcode_data parametresini sağlamalıdır" #: barcodes/api.py:126 msgid "No match found for barcode data" -msgstr "" +msgstr "Barkod verisi için eşleşme bulunamadı" #: barcodes/api.py:128 msgid "Match found for barcode data" -msgstr "" +msgstr "Barkod verisi için eşleşme bulundu" #: barcodes/api.py:153 msgid "Must provide stockitem parameter" -msgstr "" +msgstr "Stok kalemi parametresi sağlamalıdır" #: barcodes/api.py:160 msgid "No matching stock item found" -msgstr "" +msgstr "Eşleşen stok kalemi bulunamadı" #: barcodes/api.py:190 msgid "Barcode already matches StockItem object" -msgstr "" +msgstr "Barkod başka bir stok kalemi nesnesi ile eşleşmektedir" #: barcodes/api.py:194 msgid "Barcode already matches StockLocation object" -msgstr "" +msgstr "Barkod başka bir stok konumu nesnesi ile eşleşmektedir" #: barcodes/api.py:198 msgid "Barcode already matches Part object" -msgstr "" +msgstr "Barkod başka bir parça nesnesi ile eşleşmektedir" #: barcodes/api.py:204 barcodes/api.py:216 msgid "Barcode hash already matches StockItem object" -msgstr "" +msgstr "Barkod karması (hash) zaten stok kalemi nesnesiyle eşleşiyor" #: barcodes/api.py:222 msgid "Barcode associated with StockItem" -msgstr "" +msgstr "Barkod başka bir stok kalemiyle ilişkili" #: build/forms.py:37 msgid "Build Order reference" -msgstr "" +msgstr "Yapım İşi Emri referansı" #: build/forms.py:38 msgid "Order target date" -msgstr "" +msgstr "Emir hedef tarihi" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 order/forms.py:114 order/forms.py:149 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 +#: templates/js/build.js:880 templates/js/order.js:200 #: templates/js/order.js:298 msgid "Target Date" -msgstr "" +msgstr "Hedeflenen tarih" #: build/forms.py:43 build/models.py:225 msgid "Target date for build completion. Build will be overdue after this date." -msgstr "" +msgstr "Yapım işinin tamamlanması için hedef tarih. Bu tarihten sonra yapım işi gecikmiş olacak." #: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1346 #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 +#: build/templates/build/detail.html:31 common/models.py:720 +#: company/forms.py:191 company/templates/company/supplier_part_pricing.html:77 +#: order/forms.py:193 order/forms.py:211 order/forms.py:246 order/forms.py:268 +#: order/forms.py:285 order/models.py:617 order/models.py:841 #: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/order_wizard/select_parts.html:34 #: order/templates/order/purchase_order_detail.html:179 #: order/templates/order/sales_order_detail.html:70 #: order/templates/order/sales_order_detail.html:77 #: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 +#: order/templates/order/sales_order_detail.html:234 part/forms.py:342 +#: part/forms.py:372 part/forms.py:388 part/forms.py:404 part/models.py:2293 +#: part/templates/part/internal_prices.html:98 +#: part/templates/part/order_prices.html:202 +#: part/templates/part/part_pricing.html:16 #: part/templates/part/sale_prices.html:85 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 @@ -486,266 +486,267 @@ msgstr "" #: stock/forms.py:175 stock/forms.py:308 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:571 +#: templates/js/build.js:1111 templates/js/order.js:393 +#: templates/js/part.js:796 templates/js/stock.js:1164 +#: templates/js/stock.js:1383 msgid "Quantity" -msgstr "" +msgstr "Miktar" #: build/forms.py:49 msgid "Number of items to build" -msgstr "" +msgstr "Yapılacak öge sayısı" #: build/forms.py:91 msgid "Enter quantity for build output" -msgstr "" +msgstr "Yapım işi çıktısı için miktarını girin" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:240 stock/forms.py:118 msgid "Serial Numbers" -msgstr "" +msgstr "Seri Numaraları" #: build/forms.py:97 msgid "Enter serial numbers for build outputs" -msgstr "" +msgstr "Yapım işi çıktısı için seri numaraları girin" #: build/forms.py:103 msgid "Confirm creation of build output" -msgstr "" +msgstr "Yapım işi çıktısının oluşturulmasını onaylayın" #: build/forms.py:124 msgid "Confirm deletion of build output" -msgstr "" +msgstr "Yapım işi çıktısının silinmesini onaylayın" #: build/forms.py:145 msgid "Confirm unallocation of stock" -msgstr "" +msgstr "Stok tahsisinin iptalini onayla" #: build/forms.py:169 msgid "Confirm stock allocation" -msgstr "" +msgstr "Stok tahsisini onayla" #: build/forms.py:186 msgid "Mark build as complete" -msgstr "" +msgstr "Yapım işini tamamlandı olarak işaretle" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:347 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:585 templates/js/order.js:378 +#: templates/js/stock.js:643 templates/js/stock.js:1056 msgid "Location" -msgstr "" +msgstr "Konum" #: build/forms.py:211 msgid "Location of completed parts" -msgstr "" +msgstr "Tamamlanmış parçaların konumu" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:469 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:867 #: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: templates/js/stock.js:630 templates/js/stock.js:1133 +#: templates/js/stock.js:1399 msgid "Status" -msgstr "" +msgstr "Durum" #: build/forms.py:216 msgid "Build output stock status" -msgstr "" +msgstr "Yapım işi çıktısı stok durumu" #: build/forms.py:223 msgid "Confirm incomplete" -msgstr "" +msgstr "Eksik olarak onayla" #: build/forms.py:224 msgid "Confirm completion with incomplete stock allocation" -msgstr "" +msgstr "Eksik parça tahsisi ile tamamlamayı onayla" #: build/forms.py:227 msgid "Confirm build completion" -msgstr "" +msgstr "Yapım işinin tamamlandığını onaylayın" #: build/forms.py:252 msgid "Confirm cancel" -msgstr "" +msgstr "İptali Onayla" #: build/forms.py:252 build/views.py:66 msgid "Confirm build cancellation" -msgstr "" +msgstr "Yapım işi iptalini onayla" #: build/forms.py:266 msgid "Select quantity of stock to allocate" -msgstr "" +msgstr "Tahsis edilecek stok miktarını seçiniz" #: build/models.py:66 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" -msgstr "" +msgstr "Yapım İşi Emri" #: build/models.py:67 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:57 +#: part/templates/part/navbar.html:60 templates/InvenTree/index.html:183 #: templates/InvenTree/search.html:185 #: templates/InvenTree/settings/tabs.html:34 users/models.py:43 msgid "Build Orders" -msgstr "" +msgstr "Yapım İşi Emirleri" #: build/models.py:127 msgid "Build Order Reference" -msgstr "" +msgstr "Yapım İşi Emri Referansı" -#: build/models.py:128 order/models.py:101 order/models.py:618 +#: build/models.py:128 order/models.py:102 order/models.py:619 #: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: order/templates/order/sales_order_detail.html:229 part/models.py:2302 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:660 templates/js/build.js:1105 msgid "Reference" -msgstr "" +msgstr "Referans" #: build/models.py:138 msgid "Brief description of the build" -msgstr "" +msgstr "Yapım işinin kısa açıklaması" #: build/models.py:147 build/templates/build/build_base.html:163 #: build/templates/build/detail.html:77 msgid "Parent Build" -msgstr "" +msgstr "Üst Yapım İşi" #: build/models.py:148 msgid "BuildOrder to which this build is allocated" -msgstr "" +msgstr "Bu yapım işinin tahsis edildiği yapım işi emri" #: build/models.py:153 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 +#: build/templates/build/detail.html:26 company/models.py:663 +#: order/models.py:661 order/models.py:717 +#: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:132 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:214 part/models.py:321 +#: part/models.py:1975 part/models.py:1987 part/models.py:2002 +#: part/models.py:2020 part/models.py:2095 part/models.py:2191 +#: part/models.py:2277 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:551 templates/js/build.js:838 +#: templates/js/build.js:1078 templates/js/company.js:140 +#: templates/js/company.js:339 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1371 msgid "Part" -msgstr "" +msgstr "Parça" #: build/models.py:161 msgid "Select part to build" -msgstr "" +msgstr "Yapım işi için parça seçin" #: build/models.py:166 msgid "Sales Order Reference" -msgstr "" +msgstr "Satış Emri Referansı" #: build/models.py:170 msgid "SalesOrder to which this build is allocated" -msgstr "" +msgstr "Bu yapım işinin tahsis edildiği satış emri" #: build/models.py:175 msgid "Source Location" -msgstr "" +msgstr "Kaynak Konum" #: build/models.py:179 msgid "Select location to take stock from for this build (leave blank to take from any stock location)" -msgstr "" +msgstr "Bu yapım işi için stok alınacak konumu seçin (her hangi bir stok konumundan alınması için boş bırakın)" #: build/models.py:184 msgid "Destination Location" -msgstr "" +msgstr "Hedef Konum" #: build/models.py:188 msgid "Select location where the completed items will be stored" -msgstr "" +msgstr "Tamamlanmış ögelerin saklanacağı konumu seçiniz" #: build/models.py:192 msgid "Build Quantity" -msgstr "" +msgstr "Yapım İşi Miktarı" #: build/models.py:195 msgid "Number of stock items to build" -msgstr "" +msgstr "Yapım işi stok kalemlerinin sayısı" #: build/models.py:199 msgid "Completed items" -msgstr "" +msgstr "Tamamlanmış ögeler" #: build/models.py:201 msgid "Number of stock items which have been completed" -msgstr "" +msgstr "Tamamlanan stok kalemlerinin sayısı" #: build/models.py:205 part/templates/part/part_base.html:167 msgid "Build Status" -msgstr "" +msgstr "Yapım İşi Durumu" #: build/models.py:209 msgid "Build status code" -msgstr "" +msgstr "Yapım işi durum kodu" #: build/models.py:213 stock/models.py:466 msgid "Batch Code" -msgstr "" +msgstr "Sıra numarası" #: build/models.py:217 msgid "Batch code for this build output" -msgstr "" +msgstr "Yapım işi çıktısı için sıra numarası" -#: build/models.py:220 order/models.py:107 part/models.py:882 +#: build/models.py:220 order/models.py:108 part/models.py:867 #: part/templates/part/detail.html:126 templates/js/order.js:293 msgid "Creation Date" -msgstr "" +msgstr "Oluşturulma tarihi" -#: build/models.py:224 order/models.py:474 +#: build/models.py:224 order/models.py:475 msgid "Target completion date" -msgstr "" +msgstr "Hedef tamamlama tarihi" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:228 order/models.py:221 templates/js/build.js:885 msgid "Completion Date" -msgstr "" +msgstr "Tamamlama tarihi" #: build/models.py:234 msgid "completed by" -msgstr "" +msgstr "tamamlayan" #: build/models.py:242 msgid "Issued by" -msgstr "" +msgstr "Veren" #: build/models.py:243 msgid "User who issued this build order" -msgstr "" +msgstr "Bu yapım işi emrini veren kullanıcı" #: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/templates/build/detail.html:105 order/models.py:122 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:871 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" -msgstr "" +msgstr "Sorumlu" #: build/models.py:252 msgid "User responsible for this build order" -msgstr "" +msgstr "Bu yapım işi emrinden sorumlu kullanıcı" #: build/models.py:257 build/templates/build/detail.html:91 #: company/templates/company/manufacturer_part_base.html:79 @@ -755,161 +756,159 @@ msgstr "" #: part/templates/part/detail.html:83 part/templates/part/part_base.html:94 #: stock/models.py:460 stock/templates/stock/item_base.html:345 msgid "External Link" -msgstr "" +msgstr "Harici Bağlantı" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:258 part/models.py:729 stock/models.py:462 msgid "Link to external URL" -msgstr "" +msgstr "Harici URL'ye bağlantı" #: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: company/models.py:132 company/models.py:539 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:126 +#: order/models.py:621 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:243 +#: order/templates/order/sales_order_detail.html:309 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:856 +#: part/templates/part/navbar.html:142 #: report/templates/report/inventree_build_order_base.html:173 #: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 #: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:699 msgid "Notes" -msgstr "" +msgstr "Notlar" #: build/models.py:263 msgid "Extra build notes" -msgstr "" +msgstr "Yapım işi için ekstra notlar" #: build/models.py:740 msgid "No build output specified" -msgstr "" +msgstr "Yapım işi çıktısı belirtilmedi" #: build/models.py:743 msgid "Build output is already completed" -msgstr "" +msgstr "Yapım işi çıktısı zaten tamamlanmış" #: build/models.py:746 msgid "Build output does not match Build Order" -msgstr "" +msgstr "Yapım işi çıktısı, yapım işi emri ile eşleşmiyor" #: build/models.py:1152 msgid "BuildItem must be unique for build, stock_item and install_into" -msgstr "" +msgstr "Yapım işi ögesi; yapım işi, stok kalemi ve kurulacak yer için benzersiz olmalıdır" #: build/models.py:1177 msgid "Build item must specify a build output, as master part is marked as trackable" -msgstr "" +msgstr "Ana parça izlenebilir olarak işaretlendiğinden, yapım işi çıktısı için bir yapım işi ögesi belirtmelidir" #: build/models.py:1181 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" -msgstr "" +msgstr "Tahsis edilecek miktar ({n}) mevcut miktarı ({q}) geçmemeli" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1188 order/models.py:815 msgid "StockItem is over-allocated" -msgstr "" +msgstr "Stok kalemi fazladan tahsis edilmiş" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1192 order/models.py:818 msgid "Allocation quantity must be greater than zero" -msgstr "" +msgstr "Tahsis edilen miktar sıfırdan büyük olmalıdır" #: build/models.py:1196 msgid "Quantity must be 1 for serialized stock" -msgstr "" +msgstr "Seri numaralı stok için miktar bir olmalı" #: build/models.py:1256 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" -msgstr "" +msgstr "{p} parçasının malzeme listesindeki seçili stok kalemi bulunamadı" #: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: templates/InvenTree/search.html:183 templates/js/build.js:811 #: templates/navbar.html:29 msgid "Build" -msgstr "" +msgstr "Yapım İşi" #: build/models.py:1317 msgid "Build to allocate parts" -msgstr "" +msgstr "Yapım işi için tahsis edilen parçalar" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1333 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:928 +#: templates/js/order.js:366 templates/js/order.js:371 +#: templates/js/stock.js:1115 msgid "Stock Item" -msgstr "" +msgstr "Stok Kalemi" #: build/models.py:1334 msgid "Source stock item" -msgstr "" +msgstr "Kaynak stok kalemi" #: build/models.py:1347 msgid "Stock quantity to allocate to build" -msgstr "" +msgstr "Yapım işi için tahsis edilen stok miktarı" #: build/models.py:1355 msgid "Install into" -msgstr "" +msgstr "Kurulduğu yer" #: build/models.py:1356 msgid "Destination stock item" -msgstr "" +msgstr "Hedef stok kalemi" #: build/templates/build/allocate.html:7 msgid "Allocate Parts" -msgstr "" +msgstr "Parçaları Tahsis Et" #: build/templates/build/allocate.html:15 msgid "Allocate Stock to Build" -msgstr "" +msgstr "Yapım İşi için Stok Tahsis Et" #: build/templates/build/allocate.html:22 msgid "Allocate stock to build" -msgstr "" +msgstr "Yapım işi için stok tahsis et" #: build/templates/build/allocate.html:23 msgid "Auto Allocate" -msgstr "" +msgstr "Otomatik Tahsis Et" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:743 msgid "Unallocate stock" -msgstr "" +msgstr "Stok tahsisini kaldır" #: build/templates/build/allocate.html:26 build/views.py:319 build/views.py:805 msgid "Unallocate Stock" -msgstr "" +msgstr "Stok Tahsisini Kaldır" #: build/templates/build/allocate.html:29 msgid "Order required parts" -msgstr "" +msgstr "Gerekli parçaları sipariş edin" #: build/templates/build/allocate.html:30 #: company/templates/company/detail_manufacturer_part.html:33 #: company/templates/company/detail_supplier_part.html:32 order/views.py:986 #: part/templates/part/category.html:127 msgid "Order Parts" -msgstr "" +msgstr "Parça Siparişi" #: build/templates/build/allocate.html:36 msgid "Untracked stock has been fully allocated for this Build Order" -msgstr "" +msgstr "Takip edilmeyen stok yapım işi emri için tamamen tahsis edildi" #: build/templates/build/allocate.html:40 msgid "Untracked stock has not been fully allocated for this Build Order" -msgstr "" +msgstr "Takip edilmeyen stok yapım işi emri için tamamen tahsis edilemedi" #: build/templates/build/allocate.html:47 msgid "This Build Order does not have any associated untracked BOM items" -msgstr "" +msgstr "Bu yapım işi emri, herhangi bir takip edilmeyen malzeme listesi öğesine sahip değil" #: build/templates/build/allocation_card.html:21 #: build/templates/build/complete_output.html:46 @@ -917,60 +916,60 @@ msgstr "" #: order/templates/order/sales_order_detail.html:160 #: report/templates/report/inventree_test_report_base.html:75 #: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: templates/js/build.js:569 msgid "Serial Number" -msgstr "" +msgstr "Seri Numara" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:133 +#: part/templates/part/navbar.html:136 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" -msgstr "" +msgstr "Ekler" #: build/templates/build/auto_allocate.html:9 msgid "Automatically Allocate Stock" -msgstr "" +msgstr "Stoku Otomatik Olarak Tahsis Et" #: build/templates/build/auto_allocate.html:10 msgid "The following stock items will be allocated to the specified build output" -msgstr "" +msgstr "Aşağıdaki stok kalemleri, belirtilen yapım işi çıktısı için tahsis edilecek" #: build/templates/build/auto_allocate.html:37 msgid "No stock items found that can be automatically allocated to this build" -msgstr "" +msgstr "Bu yapım işi için otomatik tahsis edilecek stok kalemleri bulunamadı" #: build/templates/build/auto_allocate.html:39 msgid "Stock items will have to be manually allocated" -msgstr "" +msgstr "Stok kalemleri manuel olarak tahsis edilecek" #: build/templates/build/build_base.html:18 #, python-format msgid "This Build Order is allocated to Sales Order %(link)s" -msgstr "" +msgstr "Bu yapım işi emri, %(link)s sipariş emrine tahsis edilmiştir" #: build/templates/build/build_base.html:25 #, python-format msgid "This Build Order is a child of Build Order %(link)s" -msgstr "" +msgstr "Bu yapım işi emri, %(link)s yapım iş emrinin altıdır" #: build/templates/build/build_base.html:32 msgid "Build Order is ready to mark as completed" -msgstr "" +msgstr "Yapım işi tamamlandı olarak işaretlenmeye hazır" #: build/templates/build/build_base.html:37 msgid "Build Order cannot be completed as outstanding outputs remain" -msgstr "" +msgstr "Bekleyen çıktılar kaldığı için yapım işi emri tamamlanamıyor" #: build/templates/build/build_base.html:42 msgid "Required build quantity has not yet been completed" -msgstr "" +msgstr "Gerekli yapım işi miktarı henüz tamamlanmadı" #: build/templates/build/build_base.html:47 msgid "Stock has not been fully allocated to this Build Order" -msgstr "" +msgstr "Stok, yapım işi emri için tamamen tahsis edilemedi" #: build/templates/build/build_base.html:75 #: company/templates/company/company_base.html:40 @@ -982,7 +981,7 @@ msgstr "" #: stock/templates/stock/item_base.html:62 #: stock/templates/stock/location.html:31 msgid "Admin view" -msgstr "" +msgstr "Yönetici görünümü" #: build/templates/build/build_base.html:81 #: build/templates/build/build_base.html:150 @@ -993,115 +992,114 @@ msgstr "" #: templates/js/table_filters.js:245 templates/js/table_filters.js:264 #: templates/js/table_filters.js:281 msgid "Overdue" -msgstr "" +msgstr "Vadesi geçmiş" #: build/templates/build/build_base.html:90 msgid "Print actions" -msgstr "" +msgstr "Yazdırma işlemleri" #: build/templates/build/build_base.html:94 msgid "Print Build Order" -msgstr "" +msgstr "Yapım İşi Emrini Yazdır" #: build/templates/build/build_base.html:100 #: build/templates/build/build_base.html:225 msgid "Complete Build" -msgstr "" +msgstr "Tamamlanmış Yapım İşi" #: build/templates/build/build_base.html:105 msgid "Build actions" -msgstr "" +msgstr "Yapım İşi işlemleri" #: build/templates/build/build_base.html:109 msgid "Edit Build" -msgstr "" +msgstr "Yapım İşini Düzenle" #: build/templates/build/build_base.html:111 #: build/templates/build/build_base.html:209 build/views.py:57 msgid "Cancel Build" -msgstr "" +msgstr "Yapım İşini İptal Et" #: build/templates/build/build_base.html:124 #: build/templates/build/detail.html:11 msgid "Build Details" -msgstr "" +msgstr "Yapım İşi Detayları" #: build/templates/build/build_base.html:150 #, python-format msgid "This build was due on %(target)s" -msgstr "" +msgstr "Bu yapım işinin %(target)s tarihinde süresi doluyor" #: build/templates/build/build_base.html:157 #: build/templates/build/detail.html:64 msgid "Progress" -msgstr "" +msgstr "İlerleme" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:715 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 #: stock/templates/stock/item_base.html:279 templates/js/order.js:245 msgid "Sales Order" -msgstr "" +msgstr "Sipariş Emri" #: build/templates/build/build_base.html:177 #: build/templates/build/detail.html:98 #: report/templates/report/inventree_build_order_base.html:153 msgid "Issued By" -msgstr "" +msgstr "Veren" #: build/templates/build/build_base.html:217 msgid "Incomplete Outputs" -msgstr "" +msgstr "Tamamlanmamış Çıktılar" #: build/templates/build/build_base.html:218 msgid "Build Order cannot be completed as incomplete build outputs remain" -msgstr "" +msgstr "Tamamlanmamış yapım işi çıktıları kaldığı için yapım işi emri tamamlanamıyor" #: build/templates/build/build_children.html:10 #: build/templates/build/navbar.html:36 msgid "Child Build Orders" -msgstr "" +msgstr "Alt Yapım İşi Emrileri" #: build/templates/build/build_output.html:15 msgid "Incomplete Build Outputs" -msgstr "" +msgstr "Tamamlanmamış Yapım İşi Çıktıları" #: build/templates/build/build_output.html:22 msgid "Create new build output" -msgstr "" +msgstr "Yeni yapım işi çıktısı oluştur" #: build/templates/build/build_output.html:23 msgid "Create New Output" -msgstr "" +msgstr "Yeni Çıktı Oluştur" #: build/templates/build/build_output.html:36 msgid "Create a new build output" -msgstr "" +msgstr "Yeni bir yapım işi çıktısı oluştur" #: build/templates/build/build_output.html:37 msgid "No incomplete build outputs remain." -msgstr "" +msgstr "Tamamlanmamış yapım işi çıktısı kalmadı." #: build/templates/build/build_output.html:38 msgid "Create a new build output using the button above" -msgstr "" +msgstr "Yukarıdaki düğmeyi kullanarak yeni bir yapım işi çıktısı oluştur" #: build/templates/build/build_output.html:49 msgid "Completed Build Outputs" -msgstr "" +msgstr "Tamamlanmış Yapım İşi Çıktıları" #: build/templates/build/build_output_create.html:7 msgid "The Bill of Materials contains trackable parts" -msgstr "" +msgstr "Bu Malzeme Listesi takip edilebilir parçalar içeriyor" #: build/templates/build/build_output_create.html:8 msgid "Build outputs must be generated individually." -msgstr "" +msgstr "Yapım işi çıktıları ayrı ayrı oluşturulmalıdır." #: build/templates/build/build_output_create.html:9 msgid "Multiple build outputs will be created based on the quantity specified." @@ -1109,11 +1107,11 @@ msgstr "" #: build/templates/build/build_output_create.html:15 msgid "Trackable parts can have serial numbers specified" -msgstr "" +msgstr "Takip edilebilir parçaların seri numaraları belirtilmiş olmalı" #: build/templates/build/build_output_create.html:16 msgid "Enter serial numbers to generate multiple single build outputs" -msgstr "" +msgstr "Birden çok tek yapım işi çıktısı oluşturmak için seri numaraları girin" #: build/templates/build/cancel.html:5 msgid "Are you sure you wish to cancel this build?" @@ -1121,312 +1119,315 @@ msgstr "" #: build/templates/build/complete.html:8 msgid "Build Order is complete" -msgstr "" +msgstr "Yapım işi emri tamamlandı" #: build/templates/build/complete.html:12 msgid "Build Order is incomplete" -msgstr "" +msgstr "Yapım işi emri eksik" #: build/templates/build/complete.html:15 msgid "Incompleted build outputs remain" -msgstr "" +msgstr "Eksik yapım işi çıktıları kaldı" #: build/templates/build/complete.html:18 msgid "Required build quantity has not been completed" -msgstr "" +msgstr "Gerekli yapım işi miktarı tamamlanmadı" #: build/templates/build/complete.html:21 msgid "Required stock has not been fully allocated" -msgstr "" +msgstr "Gerekli stok tamamen tahsis edilemedi" #: build/templates/build/complete_output.html:10 msgid "Stock allocation is complete for this output" -msgstr "" +msgstr "Bu çıktı için stok tahsisi tamamlandı" #: build/templates/build/complete_output.html:14 msgid "Stock allocation is incomplete" -msgstr "" +msgstr "Stok tahsisi tamamlanmamış" #: build/templates/build/complete_output.html:20 msgid "tracked parts have not been fully allocated" -msgstr "" +msgstr "takip edilebilir parçalar tamamen tahsis edilemedi" #: build/templates/build/complete_output.html:41 msgid "The following items will be created" -msgstr "" +msgstr "Aşağıdaki ögeler oluşturulacak" #: build/templates/build/create_build_item.html:7 msgid "Select a stock item to allocate to the selected build output" -msgstr "" +msgstr "Seçili yapım işi emri için tahsis edilecek bir stok kalemi seçiniz" #: build/templates/build/create_build_item.html:11 #, python-format msgid "The allocated stock will be installed into the following build output:
          %(output)s" -msgstr "" +msgstr "Tahsis edilen stok bu yapım işi çıktısının kurulmasında kullanılacak:
          %(output)s" #: build/templates/build/create_build_item.html:17 #, python-format msgid "No stock available for %(part)s" -msgstr "" +msgstr "%(part)s için mevcut stok yok" #: build/templates/build/delete_build_item.html:8 msgid "Are you sure you want to unallocate this stock?" -msgstr "" +msgstr "Bu stokun tahsisinin iptal etmek istediğinizden emin misiniz?" #: build/templates/build/delete_build_item.html:11 msgid "The selected stock will be unallocated from the build output" -msgstr "" +msgstr "Bu yapım işi için seçili stok tahsisi iptal edilecek" #: build/templates/build/detail.html:35 msgid "Stock Source" -msgstr "" +msgstr "Stok Kaynağı" #: build/templates/build/detail.html:40 msgid "Stock can be taken from any available location." -msgstr "" +msgstr "Stok herhangi bir konumdan alınabilir." -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:85 order/models.py:678 +#: order/templates/order/purchase_order_detail.html:239 +#: order/templates/order/receive_parts.html:25 stock/forms.py:169 +#: stock/forms.py:375 msgid "Destination" -msgstr "" +msgstr "Hedef" #: build/templates/build/detail.html:53 msgid "Destination location not specified" -msgstr "" +msgstr "Hedef konumu belirtilmedi" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1406 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" -msgstr "" +msgstr "Toplu" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:875 msgid "Created" -msgstr "" +msgstr "Oluşturuldu" #: build/templates/build/detail.html:127 msgid "No target date set" -msgstr "" +msgstr "Hedef tarih ayarlanmadı" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:853 msgid "Completed" -msgstr "" +msgstr "Tamamlandı" #: build/templates/build/detail.html:136 msgid "Build not complete" -msgstr "" +msgstr "Yapım İşi tamamlanmadı" #: build/templates/build/edit_build_item.html:7 msgid "Alter the quantity of stock allocated to the build output" -msgstr "" +msgstr "Yapım işi çıktısına tahsis edilen stok miktarını değiştir" #: build/templates/build/index.html:28 build/views.py:678 msgid "New Build Order" -msgstr "" +msgstr "Yeni Yapım İşi Emri" #: build/templates/build/index.html:37 build/templates/build/index.html:38 msgid "Print Build Orders" -msgstr "" +msgstr "Yapım İşi Emirlerini Yazdır" #: build/templates/build/index.html:43 #: order/templates/order/purchase_orders.html:27 #: order/templates/order/sales_orders.html:27 msgid "Display calendar view" -msgstr "" +msgstr "Takvim görünümünü görüntüle" #: build/templates/build/index.html:46 #: order/templates/order/purchase_orders.html:30 #: order/templates/order/sales_orders.html:30 msgid "Display list view" -msgstr "" +msgstr "Liste görünümünü görüntüle" #: build/templates/build/navbar.html:12 msgid "Build Order Details" -msgstr "" +msgstr "Yapım İşi Emri Detayları" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:17 +#: templates/js/stock.js:1044 msgid "Details" -msgstr "" +msgstr "Detaylar" #: build/templates/build/navbar.html:21 build/templates/build/navbar.html:24 #: build/views.py:91 msgid "Allocate Stock" -msgstr "" +msgstr "Stok Tahsis Et" #: build/templates/build/navbar.html:29 build/templates/build/navbar.html:32 msgid "Build Outputs" -msgstr "" +msgstr "Yapım İşi Çıktıları" #: build/templates/build/navbar.html:39 msgid "Child Builds" -msgstr "" +msgstr "Alt Yapım İşleri" #: build/templates/build/navbar.html:50 msgid "Build Order Notes" -msgstr "" +msgstr "Yapım İşi Emri Notları" #: build/templates/build/notes.html:12 msgid "Build Notes" -msgstr "" +msgstr "Yapım İşi Notları" #: build/templates/build/notes.html:14 company/templates/company/notes.html:13 #: order/templates/order/order_notes.html:15 #: order/templates/order/sales_order_notes.html:16 #: part/templates/part/notes.html:14 stock/templates/stock/item_notes.html:15 msgid "Edit notes" -msgstr "" +msgstr "Notları Düzenle" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 +#: stock/templates/stock/item_base.html:497 #: stock/templates/stock/item_notes.html:26 msgid "Save" -msgstr "" +msgstr "Kaydet" #: build/templates/build/unallocate.html:10 msgid "Are you sure you wish to unallocate all stock for this build?" -msgstr "" +msgstr "Bu yapım işi için tahsis edilen tüm stokları kaldırmak istediğinizden emin misiniz?" #: build/templates/build/unallocate.html:12 msgid "All incomplete stock allocations will be removed from the build" -msgstr "" +msgstr "Tüm eksik stok tahsisleri yapım işinden kaldırılacak" #: build/views.py:77 msgid "Build was cancelled" -msgstr "" +msgstr "Yapım işi iptal edildi" #: build/views.py:138 msgid "Allocated stock to build output" -msgstr "" +msgstr "Yapım işi çıktısına stok tahsis edildi" #: build/views.py:150 msgid "Create Build Output" -msgstr "" +msgstr "Yapım İşi Çıktısı Oluştur" #: build/views.py:168 msgid "Maximum output quantity is " -msgstr "" +msgstr "Maksimum çıktı miktarı " #: build/views.py:184 stock/views.py:1821 msgid "Serial numbers already exist" -msgstr "" +msgstr "Seri numaraları zaten mevcut" #: build/views.py:193 msgid "Serial numbers required for trackable build output" -msgstr "" +msgstr "Seri numaraları takip edilebilir yapım işi çıktıları için gerekli" #: build/views.py:259 msgid "Delete Build Output" -msgstr "" +msgstr "Yapım İşi Çıktısı Sil" #: build/views.py:280 build/views.py:370 msgid "Confirm unallocation of build stock" -msgstr "" +msgstr "Yapım işi stoku tahsisinin iptalini onayla" #: build/views.py:281 build/views.py:371 stock/views.py:425 msgid "Check the confirmation box" -msgstr "" +msgstr "Onay kutusunu işaretleyin" #: build/views.py:293 msgid "Build output does not match build" -msgstr "" +msgstr "Yapım işi çıktısı yapım işi ile eşleşmiyor" #: build/views.py:295 build/views.py:496 msgid "Build output must be specified" -msgstr "" +msgstr "Yapım işi çıktısı belirtilmeli" #: build/views.py:307 msgid "Build output deleted" -msgstr "" +msgstr "Yapım işi çıktısı silindi" #: build/views.py:405 msgid "Complete Build Order" -msgstr "" +msgstr "Tamamlanmış Yapım İşi Emri" #: build/views.py:411 msgid "Build order cannot be completed - incomplete outputs remain" -msgstr "" +msgstr "Yapım işi emri tamamlanamadı - eksik çıktılar kaldı" #: build/views.py:422 msgid "Completed build order" -msgstr "" +msgstr "Tamamlanmış yapım işi emri" #: build/views.py:438 msgid "Complete Build Output" -msgstr "" +msgstr "Tamamlanmış Yapım İşi Çıktısı" #: build/views.py:480 msgid "Invalid stock status value selected" -msgstr "" +msgstr "Geçersiz stok durum değeri seçildi" #: build/views.py:487 msgid "Quantity to complete cannot exceed build output quantity" -msgstr "" +msgstr "Tamamlanacak miktar yapım işi çıktı miktarını aşamaz" #: build/views.py:493 msgid "Confirm completion of incomplete build" -msgstr "" +msgstr "Eksik yapım işinin tamamlandığını onaylayın" #: build/views.py:592 msgid "Build output completed" -msgstr "" +msgstr "Yapım işi çıktısı tamamlandı" #: build/views.py:732 msgid "Created new build" -msgstr "" +msgstr "Yeni yapım işi oluşturuldu" #: build/views.py:753 msgid "Edit Build Order Details" -msgstr "" +msgstr "Yapım İşi Emri Detaylarını Düzenle" #: build/views.py:786 msgid "Edited build" -msgstr "" +msgstr "Yapım işi düzenlendi" #: build/views.py:795 msgid "Delete Build Order" -msgstr "" +msgstr "Yapım İşi Emrini Sil" #: build/views.py:810 msgid "Removed parts from build allocation" -msgstr "" +msgstr "Yapım işinden tahsis edilen parçalar çıkarıldı" #: build/views.py:822 msgid "Allocate stock to build output" -msgstr "" +msgstr "Yapım işi çıktısına stok tahsis edildi" #: build/views.py:865 msgid "Item must be currently in stock" -msgstr "" +msgstr "Öge stokta bulunmalı" #: build/views.py:871 msgid "Stock item is over-allocated" -msgstr "" +msgstr "Stok kalemi fazladan tahsis edilmiş" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:670 +#: templates/js/build.js:935 templates/js/build.js:1118 msgid "Available" -msgstr "" +msgstr "Mevcut" #: build/views.py:874 msgid "Stock item must be selected" -msgstr "" +msgstr "Stok kalemi seçilmeli" #: build/views.py:1037 msgid "Edit Stock Allocation" -msgstr "" +msgstr "Stok Tahsisini Düzenle" #: build/views.py:1041 msgid "Updated Build Item" -msgstr "" +msgstr "Yapım İşi Ögesini Güncelle" #: build/views.py:1070 msgid "Add Build Order Attachment" @@ -1435,56 +1436,56 @@ msgstr "" #: build/views.py:1083 order/views.py:115 order/views.py:167 part/views.py:173 #: stock/views.py:277 msgid "Added attachment" -msgstr "" +msgstr "Ek eklendi" #: build/views.py:1119 order/views.py:194 order/views.py:215 msgid "Edit Attachment" -msgstr "" +msgstr "Ek Düzenle" #: build/views.py:1129 order/views.py:198 order/views.py:219 msgid "Attachment updated" -msgstr "" +msgstr "Ek güncellendi" #: build/views.py:1139 order/views.py:234 order/views.py:248 msgid "Delete Attachment" -msgstr "" +msgstr "Eki Sil" #: build/views.py:1144 order/views.py:240 order/views.py:254 stock/views.py:333 msgid "Deleted attachment" -msgstr "" +msgstr "Eki sil" #: common/files.py:64 msgid "Unsupported file format: {ext.upper()}" -msgstr "" +msgstr "Desteklenmeyen dosya formatı: {ext.upper()}" #: common/files.py:69 msgid "Error reading file (invalid format)" -msgstr "" +msgstr "Dosya okurken hata (geçersiz biçim)" #: common/files.py:71 msgid "Error reading file (incorrect dimension)" -msgstr "" +msgstr "Dosya okurken hata (hatalı ölçüler)" #: common/files.py:73 msgid "Error reading file (data could be corrupted)" -msgstr "" +msgstr "Dosya okurken hata (veri bozulmuş olabilir)" #: common/forms.py:39 templates/attachment_table.html:15 msgid "File" -msgstr "" +msgstr "Dosya" #: common/forms.py:40 msgid "Select file to upload" -msgstr "" +msgstr "Yüklenecek dosyayı seç" #: common/forms.py:55 msgid "{name.title()} File" -msgstr "" +msgstr "{name.title()} Dosya" #: common/forms.py:56 #, python-brace-format msgid "Select {name} file to upload" -msgstr "" +msgstr "{name} dosyasını yüklemek için seçin" #: common/models.py:59 msgid "InvenTree Instance Name" @@ -1524,7 +1525,7 @@ msgstr "" #: common/models.py:86 msgid "Allow download of remote images and files from external URL" -msgstr "" +msgstr "Harici URL'den resim ve dosyaların indirilmesine izin ver" #: common/models.py:92 msgid "Barcode Support" @@ -1536,27 +1537,27 @@ msgstr "" #: common/models.py:99 msgid "IPN Regex" -msgstr "" +msgstr "DPN Regex" #: common/models.py:100 msgid "Regular expression pattern for matching Part IPN" -msgstr "" +msgstr "Parça DPN eşleştirmesi için Düzenli İfade Kalıbı (Regex)" #: common/models.py:104 msgid "Allow Duplicate IPN" -msgstr "" +msgstr "Yinelenen DPN'ye İzin Ver" #: common/models.py:105 msgid "Allow multiple parts to share the same IPN" -msgstr "" +msgstr "Birden çok parçanın aynı DPN'yi paylaşmasına izin ver" #: common/models.py:111 msgid "Allow Editing IPN" -msgstr "" +msgstr "DPN Düzenlemeye İzin Ver" #: common/models.py:112 msgid "Allow changing the IPN value while editing a part" -msgstr "" +msgstr "Parçayı düzenlerken DPN değiştirmeye izin ver" #: common/models.py:118 msgid "Copy Part BOM Data" @@ -1584,11 +1585,11 @@ msgstr "" #: common/models.py:139 msgid "Copy Category Parameter Templates" -msgstr "" +msgstr "Kategori Paremetre Sablonu Kopyala" #: common/models.py:140 msgid "Copy category parameter templates when creating a part" -msgstr "" +msgstr "Parça oluştururken kategori parametre şablonlarını kopyala" #: common/models.py:146 msgid "Recent Part Count" @@ -1598,68 +1599,68 @@ msgstr "" msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 +#: common/models.py:153 part/models.py:2193 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:259 templates/js/table_filters.js:25 #: templates/js/table_filters.js:315 msgid "Template" -msgstr "" +msgstr "Şablon" #: common/models.py:154 msgid "Parts are templates by default" -msgstr "" +msgstr "Parçaları varsayılan olan şablondur" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 +#: common/models.py:160 part/models.py:819 part/templates/part/detail.html:170 #: templates/js/table_filters.js:128 templates/js/table_filters.js:327 msgid "Assembly" -msgstr "" +msgstr "Montaj" #: common/models.py:161 msgid "Parts can be assembled from other components by default" -msgstr "" +msgstr "Parçalar varsayılan olarak başka bileşenlerden monte edilebilir" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 +#: common/models.py:167 part/models.py:825 part/templates/part/detail.html:180 #: templates/js/table_filters.js:331 msgid "Component" -msgstr "" +msgstr "Bileşen" #: common/models.py:168 msgid "Parts can be used as sub-components by default" -msgstr "" +msgstr "Parçalar varsayılan olarak alt bileşen olarak kullanılabilir" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:174 part/models.py:836 part/templates/part/detail.html:200 msgid "Purchaseable" -msgstr "" +msgstr "Satın Alınabilir" #: common/models.py:175 msgid "Parts are purchaseable by default" -msgstr "" +msgstr "Parçalar varsayılan olarak satın alınabilir" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 +#: common/models.py:181 part/models.py:841 part/templates/part/detail.html:210 #: templates/js/table_filters.js:339 msgid "Salable" -msgstr "" +msgstr "Satılabilir" #: common/models.py:182 msgid "Parts are salable by default" -msgstr "" +msgstr "Parçalar varsayılan olarak satılabilir" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 +#: common/models.py:188 part/models.py:831 part/templates/part/detail.html:190 #: templates/js/table_filters.js:33 templates/js/table_filters.js:343 msgid "Trackable" -msgstr "" +msgstr "Takip Edilebilir" #: common/models.py:189 msgid "Parts are trackable by default" -msgstr "" +msgstr "Parçalar varsayılan olarak takip edilebilir" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:195 part/models.py:851 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" -msgstr "" +msgstr "Sanal" #: common/models.py:196 msgid "Parts are virtual by default" -msgstr "" +msgstr "Parçalar varsayılan olarak sanaldır" #: common/models.py:202 msgid "Show Quantity in Forms" @@ -1669,160 +1670,185 @@ msgstr "" msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" +#: common/models.py:209 +msgid "Show Price in Forms" msgstr "" #: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" +msgid "Display part price in some forms" msgstr "" #: common/models.py:216 -msgid "Page Size" +msgid "Internal Prices" msgstr "" #: common/models.py:217 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:223 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:224 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:230 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:231 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:237 +msgid "Page Size" +msgstr "" + +#: common/models.py:238 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:248 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:249 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:255 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:256 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:262 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:263 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:269 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:270 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:272 part/templates/part/detail.html:121 msgid "days" msgstr "" -#: common/models.py:256 +#: common/models.py:277 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:278 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:284 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:285 msgid "Enable ownership control over stock locations and items" -msgstr "" +msgstr "Stok konumu ve ögeler üzerinde sahiplik kontrolünü etkinleştirin" -#: common/models.py:270 +#: common/models.py:291 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:292 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:298 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:299 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:305 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:306 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:311 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:312 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:316 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:317 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:322 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:323 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:546 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:548 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:583 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:606 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:617 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:640 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:721 company/forms.py:192 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 +#: common/models.py:729 company/templates/company/supplier_part_pricing.html:82 +#: part/templates/part/internal_prices.html:103 #: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:730 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:822 msgid "Default" msgstr "" @@ -1843,9 +1869,11 @@ msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:582 +#: part/templates/part/bom_upload/upload_file.html:27 msgid "Upload File" -msgstr "" +msgstr "Dosya Yükle" #: common/views.py:185 order/templates/order/order_wizard/match_fields.html:52 #: order/views.py:583 part/templates/part/bom_upload/select_fields.html:58 @@ -1877,29 +1905,29 @@ msgstr "" msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:133 templates/js/part.js:787 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:135 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:143 company/models.py:321 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:149 company/models.py:328 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:151 company/models.py:327 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 #: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:408 msgid "MPN" msgstr "" @@ -1952,11 +1980,11 @@ msgstr "" msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:121 company/models.py:333 company/models.py:526 +#: order/models.py:106 part/models.py:728 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:188 templates/js/company.js:419 +#: templates/js/part.js:498 msgid "Link" msgstr "" @@ -1964,7 +1992,7 @@ msgstr "" msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:129 part/models.py:738 msgid "Image" msgstr "" @@ -1992,12 +2020,12 @@ msgstr "" msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:305 company/models.py:497 stock/models.py:407 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:309 company/models.py:501 order/views.py:1597 msgid "Select part" msgstr "" @@ -2008,7 +2036,7 @@ msgstr "" #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 #: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:390 msgid "Manufacturer" msgstr "" @@ -2020,89 +2048,114 @@ msgstr "" msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:390 company/models.py:520 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:397 +msgid "Parameter name" +msgstr "" + +#: company/models.py:403 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:241 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:404 +msgid "Parameter value" +msgstr "" + +#: company/models.py:410 part/models.py:813 part/models.py:2165 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:247 +msgid "Units" +msgstr "" + +#: company/models.py:411 +msgid "Parameter units" +msgstr "" + +#: company/models.py:507 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:193 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:48 templates/js/company.js:364 #: templates/js/order.js:170 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:508 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:513 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 #: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:514 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:521 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:527 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:533 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:538 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2305 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 +#: company/models.py:544 company/templates/company/supplier_part_base.html:109 #: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: templates/js/stock.js:695 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:544 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:546 part/models.py:1608 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:546 msgid "Order multiple" msgstr "" #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:562 msgid "Assigned Stock" -msgstr "" +msgstr "Atanan Stok" #: company/templates/company/company_base.html:9 #: company/templates/company/company_base.html:35 @@ -2122,7 +2175,7 @@ msgstr "" #: company/templates/company/company_base.html:46 order/views.py:311 msgid "Create Purchase Order" -msgstr "" +msgstr "Satın Alma Emri Oluştur" #: company/templates/company/company_base.html:51 msgid "Edit company information" @@ -2165,13 +2218,13 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 +#: company/templates/company/detail.html:67 order/models.py:464 #: order/templates/order/sales_order_base.html:94 stock/models.py:449 #: stock/models.py:450 stock/templates/stock/item_base.html:262 #: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: templates/js/stock.js:1097 msgid "Customer" -msgstr "" +msgstr "Müşteri" #: company/templates/company/detail_manufacturer_part.html:11 #: templates/InvenTree/search.html:149 @@ -2205,17 +2258,17 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:36 #: company/templates/company/detail_supplier_part.html:35 msgid "Delete parts" -msgstr "" +msgstr "Parçaları sil" #: company/templates/company/detail_manufacturer_part.html:36 #: company/templates/company/detail_supplier_part.html:35 msgid "Delete Parts" -msgstr "" +msgstr "Parçaları Sil" #: company/templates/company/detail_manufacturer_part.html:66 #: company/templates/company/detail_supplier_part.html:66 #: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: templates/js/stock.js:1312 msgid "New Part" msgstr "" @@ -2237,7 +2290,7 @@ msgstr "" #: company/templates/company/detail_stock.html:10 msgid "Supplier Stock" -msgstr "" +msgstr "Tedarikçi Stoku" #: company/templates/company/detail_stock.html:37 #: company/templates/company/supplier_part_stock.html:34 @@ -2248,26 +2301,25 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" -msgstr "" +msgstr "Tedarikçi Parçaları" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 +#: order/templates/order/order_wizard/select_parts.html:44 #: order/templates/order/purchase_order_detail.html:50 msgid "Create new supplier part" -msgstr "" +msgstr "Yeni tedarikçi parçası oluştur" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 #: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/supplier.html:17 templates/js/stock.js:1318 msgid "New Supplier Part" -msgstr "" +msgstr "Yeni Tedarikçi Parçası" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 +#: company/templates/company/manufacturer_part_suppliers.html:82 #: company/views.py:64 order/templates/order/purchase_orders.html:185 #: part/templates/part/supplier.html:50 msgid "New Supplier" @@ -2287,7 +2339,7 @@ msgstr "" #: company/templates/company/supplier_part_orders.html:17 #: part/templates/part/orders.html:17 part/templates/part/part_base.html:58 msgid "Order part" -msgstr "" +msgstr "Parça siparişi" #: company/templates/company/manufacturer_part_base.html:41 msgid "Edit manufacturer part" @@ -2316,11 +2368,12 @@ msgstr "" #: company/templates/company/manufacturer_part_delete.html:36 #, python-format msgid "There are %(count)s suppliers defined for this manufacturer part. If you delete it, the following supplier parts will also be deleted:" -msgstr "" +msgstr "Bu üretici parçası için tanımlanmış %(count)s tedarikçi bulunmaktadır. Bunu silerseniz, aşağıdaki tedarikçi parçaları da silinecektir:" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:63 part/templates/part/navbar.html:86 +#: part/templates/part/navbar.html:89 templates/InvenTree/search.html:316 #: templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,16 +2385,16 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:38 stock/api.py:54 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" -msgstr "" +msgstr "Stok" #: company/templates/company/manufacturer_part_navbar.html:26 msgid "Manufacturer Part Orders" @@ -2355,16 +2408,30 @@ msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 #: part/templates/part/supplier.html:22 msgid "Delete supplier parts" -msgstr "" +msgstr "Tedarikçi parçalarını sil" #: company/templates/company/manufacturer_part_suppliers.html:22 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:1002 users/models.py:191 msgid "Delete" msgstr "" -#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:34 +#: part/templates/part/category_navbar.html:37 +#: part/templates/part/navbar.html:24 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:48 +msgid "New Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:83 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" @@ -2379,16 +2446,16 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:35 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 +#: templates/InvenTree/search.html:198 templates/js/stock.js:996 #: templates/stats.html:93 templates/stats.html:102 users/models.py:42 msgid "Stock Items" -msgstr "" +msgstr "Stok Kalemleri" #: company/templates/company/navbar.html:47 #: company/templates/company/navbar.html:56 @@ -2396,25 +2463,25 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 +#: part/templates/part/navbar.html:112 part/templates/part/navbar.html:115 #: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 #: users/models.py:45 msgid "Sales Orders" -msgstr "" +msgstr "Satış Emirleri" #: company/templates/company/navbar.html:50 #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 +#: part/templates/part/navbar.html:92 part/templates/part/navbar.html:95 #: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 #: users/models.py:44 msgid "Purchase Orders" -msgstr "" +msgstr "Satın Alma Emirleri" #: company/templates/company/notes.html:11 msgid "Company Notes" @@ -2423,59 +2490,59 @@ msgstr "" #: company/templates/company/purchase_orders.html:18 #: order/templates/order/purchase_orders.html:20 msgid "Create new purchase order" -msgstr "" +msgstr "Yeni satın alma emri oluştur" #: company/templates/company/purchase_orders.html:19 #: order/templates/order/purchase_orders.html:21 msgid "New Purchase Order" -msgstr "" +msgstr "Yeni Satın Alma Emri" #: company/templates/company/sales_orders.html:19 #: order/templates/order/sales_orders.html:20 msgid "Create new sales order" -msgstr "" +msgstr "Yeni satış emri oluştur" #: company/templates/company/sales_orders.html:20 #: order/templates/order/sales_orders.html:21 msgid "New Sales Order" -msgstr "" +msgstr "Yeni Satış Emri" #: company/templates/company/supplier_part_base.html:7 #: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:380 msgid "Supplier Part" -msgstr "" +msgstr "Tedarikçi Parçası" #: company/templates/company/supplier_part_base.html:40 msgid "Edit supplier part" -msgstr "" +msgstr "Tedarikçi parçasını düzenle" #: company/templates/company/supplier_part_base.html:44 msgid "Delete supplier part" -msgstr "" +msgstr "Tedarikçi parçasını sil" #: company/templates/company/supplier_part_base.html:56 #: company/templates/company/supplier_part_detail.html:10 msgid "Supplier Part Details" -msgstr "" +msgstr "Tedarikçi Parçası Detayları" #: company/templates/company/supplier_part_delete.html:5 msgid "Are you sure you want to delete the following Supplier Parts?" -msgstr "" +msgstr "Aşağıdaki Tedarikçi Parçalarını silmek istediğinizden emin misin?" #: company/templates/company/supplier_part_navbar.html:12 #: company/templates/company/supplier_part_stock.html:10 msgid "Supplier Part Stock" -msgstr "" +msgstr "Tedarikçi Parça Stoku" #: company/templates/company/supplier_part_navbar.html:19 #: company/templates/company/supplier_part_orders.html:10 msgid "Supplier Part Orders" -msgstr "" +msgstr "Tedarikçi Parçası Emirleri" #: company/templates/company/supplier_part_navbar.html:26 msgid "Supplier Part Pricing" -msgstr "" +msgstr "Tedarikçi Parçası Fiyatlandırması" #: company/templates/company/supplier_part_navbar.html:29 msgid "Pricing" @@ -2490,8 +2557,8 @@ msgstr "" msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 company/views.py:855 +#: part/templates/part/sale_prices.html:17 part/views.py:2751 msgid "Add Price Break" msgstr "" @@ -2510,8 +2577,8 @@ msgstr "" msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 +#: company/views.py:70 part/templates/part/navbar.html:80 +#: part/templates/part/navbar.html:83 templates/InvenTree/search.html:306 #: templates/navbar.html:36 msgid "Manufacturers" msgstr "" @@ -2533,22 +2600,22 @@ msgstr "" msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:169 part/views.py:948 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:198 part/views.py:980 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:205 part/views.py:987 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:214 part/views.py:996 msgid "Supplied URL is not a valid image file" -msgstr "" +msgstr "Sağlanan URL geçerli bir resim dosyası değil" #: company/views.py:243 msgid "Update Company Image" @@ -2594,57 +2661,65 @@ msgstr "" msgid "Delete Manufacturer Part" msgstr "" -#: company/views.py:528 +#: company/views.py:514 +msgid "Add Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:548 +msgid "Edit Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:588 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:639 templates/js/stock.js:1319 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:783 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 +#: company/views.py:860 part/views.py:2755 msgid "Added new price break" msgstr "" -#: company/views.py:855 part/views.py:2781 +#: company/views.py:916 part/views.py:2799 msgid "Edit Price Break" msgstr "" -#: company/views.py:870 part/views.py:2795 +#: company/views.py:931 part/views.py:2813 msgid "Delete Price Break" msgstr "" #: label/api.py:56 report/api.py:201 msgid "No valid objects provided to template" -msgstr "" +msgstr "Şablon için geçerli bir nesne sağlanmadı" #: label/models.py:103 msgid "Label name" -msgstr "" +msgstr "Etiket adı" #: label/models.py:110 msgid "Label description" -msgstr "" +msgstr "Etiket tanımı" #: label/models.py:117 stock/forms.py:202 msgid "Label" -msgstr "" +msgstr "Etiket" #: label/models.py:118 msgid "Label template file" -msgstr "" +msgstr "Etiket şablon listesi" -#: label/models.py:124 report/models.py:274 +#: label/models.py:124 report/models.py:297 msgid "Enabled" msgstr "" #: label/models.py:125 msgid "Label template is enabled" -msgstr "" +msgstr "Etiket sablonu etkinleştirildi" #: label/models.py:130 msgid "Width [mm]" @@ -2652,7 +2727,7 @@ msgstr "" #: label/models.py:131 msgid "Label width, specified in mm" -msgstr "" +msgstr "Etiket genişliği mm olarak belirtilmeli" #: label/models.py:137 msgid "Height [mm]" @@ -2660,22 +2735,22 @@ msgstr "" #: label/models.py:138 msgid "Label height, specified in mm" -msgstr "" +msgstr "Etiket yüksekliği mm olarak belirtilmeli" -#: label/models.py:144 +#: label/models.py:144 report/models.py:290 msgid "Filename Pattern" -msgstr "" +msgstr "Dosya Adı Deseni" #: label/models.py:145 msgid "Pattern for generating label filenames" -msgstr "" +msgstr "Etiket dosya adları oluşturma için desen" #: label/models.py:244 label/models.py:297 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:245 label/models.py:298 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" @@ -2696,239 +2771,241 @@ msgstr "" msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:86 msgid "Receive parts to this location" -msgstr "" +msgstr "Parçaları bu konuma alın" -#: order/forms.py:103 +#: order/forms.py:108 msgid "Purchase Order reference" msgstr "" -#: order/forms.py:110 +#: order/forms.py:115 msgid "Target date for order delivery. Order will be overdue after this date." msgstr "" -#: order/forms.py:138 +#: order/forms.py:143 msgid "Enter sales order number" msgstr "" -#: order/forms.py:145 order/models.py:475 +#: order/forms.py:150 order/models.py:476 msgid "Target date for order completion. Order will be overdue after this date." msgstr "" -#: order/forms.py:236 -msgid "Enter stock item serial numbers" -msgstr "" - #: order/forms.py:242 +msgid "Enter stock item serial numbers" +msgstr "Stok kalemi seri numaları girin" + +#: order/forms.py:248 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 +#: order/models.py:102 msgid "Order reference" msgstr "" -#: order/models.py:103 +#: order/models.py:104 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:106 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:114 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:121 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:126 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:185 order/models.py:469 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:194 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 +#: order/models.py:197 order/templates/order/order_base.html:98 #: templates/js/order.js:179 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:197 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:204 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:209 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:210 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:215 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:216 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:222 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 +#: order/models.py:246 part/views.py:1686 stock/models.py:304 #: stock/models.py:1020 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:251 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:349 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:353 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:355 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:465 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:479 templates/js/order.js:303 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:486 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:530 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:617 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:619 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:621 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:647 order/models.py:715 templates/js/order.js:353 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:648 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 #: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: templates/js/stock.js:669 templates/js/stock.js:1078 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:662 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 +#: order/models.py:665 order/templates/order/order_base.html:131 #: order/templates/order/purchase_order_detail.html:219 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:665 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:672 stock/models.py:542 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:690 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:673 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:681 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:724 part/templates/part/navbar.html:109 +#: part/templates/part/order_prices.html:107 +#: part/templates/part/part_pricing.html:97 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:725 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:800 order/models.py:802 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:806 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:808 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:811 msgid "Allocation quantity cannot exceed stock quantity" -msgstr "" +msgstr "Tahsis miktarı stok miktarını aşamaz" -#: order/models.py:797 +#: order/models.py:821 msgid "Quantity must be 1 for serialized stock item" -msgstr "" +msgstr "Seri numaralı stok kalemi için miktar bir olmalı" -#: order/models.py:802 +#: order/models.py:826 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:837 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:838 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:841 msgid "Enter stock allocation quantity" -msgstr "" +msgstr "Stok tahsis miktarını girin" #: order/templates/order/delete_attachment.html:5 #: stock/templates/stock/attachment_delete.html:5 @@ -2952,10 +3029,10 @@ msgstr "" #: order/templates/order/order_base.html:64 msgid "Export order to file" -msgstr "" +msgstr "Emiri dosya çıkar" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2977,16 +3054,16 @@ msgstr "" #: order/templates/order/order_base.html:180 #: order/templates/order/purchase_order_detail.html:100 #: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: stock/templates/stock/location.html:191 templates/js/stock.js:736 +#: templates/js/stock.js:1324 msgid "New Location" -msgstr "" +msgstr "Yeni Konum" #: order/templates/order/order_base.html:181 #: order/templates/order/purchase_order_detail.html:101 #: stock/templates/stock/location.html:42 msgid "Create new stock location" -msgstr "" +msgstr "Yeni stok konumu oluştur" #: order/templates/order/order_cancel.html:8 msgid "Cancelling this order means that the order and line items will no longer be editable." @@ -3015,7 +3092,7 @@ msgstr "" #: order/templates/order/order_wizard/match_fields.html:9 #: part/templates/part/bom_upload/select_fields.html:21 msgid "Missing selections for the following required columns" -msgstr "" +msgstr "Aşağıdaki gerekli sütunlar için eksik seçimler" #: order/templates/order/order_wizard/match_fields.html:20 msgid "Duplicate selections found, see below. Fix them then retry submitting." @@ -3036,7 +3113,7 @@ msgstr "" #: order/templates/order/order_wizard/match_fields.html:35 #: part/templates/part/bom_upload/select_fields.html:41 msgid "File Fields" -msgstr "" +msgstr "Dosya Alanları" #: order/templates/order/order_wizard/match_fields.html:42 #: part/templates/part/bom_upload/select_fields.html:47 @@ -3066,11 +3143,11 @@ msgstr "" #: order/templates/order/order_wizard/match_parts.html:28 msgid "Select Supplier Part" -msgstr "" +msgstr "Tedarikçi Parçası Seçin" #: order/templates/order/order_wizard/po_upload.html:11 msgid "Upload File for Purchase Order" -msgstr "" +msgstr "Sipariş Emri için Dosya Yükle" #: order/templates/order/order_wizard/po_upload.html:18 #, python-format @@ -3081,28 +3158,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" -msgstr "" +msgstr "Adım 1/2 - Parça Tedarikçileri Seçin" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3135,15 +3216,20 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +#: order/templates/order/so_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,8 +3239,8 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/sales_order_detail.html:22 order/views.py:1321 +#: order/views.py:1404 msgid "Add Line Item" msgstr "" @@ -3162,25 +3248,31 @@ msgstr "" msgid "No line items found" msgstr "" +#: order/templates/order/purchase_order_detail.html:142 +#: order/templates/order/sales_order_detail.html:223 +msgid "Total" +msgstr "" + #: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/sales_order_detail.html:246 msgid "Unit Price" msgstr "" #: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/sales_order_detail.html:253 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:255 +#: order/templates/order/sales_order_detail.html:359 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:256 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:261 msgid "Receive line item" msgstr "" @@ -3201,11 +3293,11 @@ msgstr "" #: part/templates/part/category_navbar.html:29 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 #: users/models.py:40 msgid "Parts" -msgstr "" +msgstr "Parçalar" #: order/templates/order/receive_parts.html:15 msgid "Select parts to receive against this order" @@ -3216,7 +3308,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3316,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3254,7 +3346,7 @@ msgstr "" #: part/templates/part/bom_duplicate.html:12 #: stock/templates/stock/stockitem_convert.html:13 msgid "Warning" -msgstr "" +msgstr "Uyarı" #: order/templates/order/sales_order_cancel.html:9 msgid "Cancelling this order means that the order will no longer be editable." @@ -3265,68 +3357,68 @@ msgid "Sales Order Items" msgstr "" #: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: templates/js/build.js:724 templates/js/build.js:1141 msgid "Actions" -msgstr "" +msgstr "İşlemler" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:610 +#: templates/js/build.js:946 msgid "Edit stock allocation" -msgstr "" +msgstr "Stok tahsisini düzenle" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:612 +#: templates/js/build.js:947 msgid "Delete stock allocation" -msgstr "" +msgstr "Stok tahsisini sil" #: order/templates/order/sales_order_detail.html:176 msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:206 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:274 templates/js/build.js:675 +#: templates/js/build.js:942 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:276 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:313 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:343 msgid "Allocate serial numbers" -msgstr "" +msgstr "Seri numaralarını tahsis et" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:346 templates/js/build.js:738 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:349 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:353 templates/js/build.js:731 +#: templates/js/build.js:1149 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:356 +#: order/templates/order/sales_order_detail.html:465 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:360 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:471 msgid "Update Unit Price" msgstr "" @@ -3340,7 +3432,7 @@ msgstr "" #: order/templates/order/sales_order_ship.html:12 msgid "Ensure that the order allocation is correct before shipping the order." -msgstr "" +msgstr "Emri göndermeden önce emir tahsisinin doğru olduğundan emin olun." #: order/templates/order/sales_order_ship.html:18 msgid "Some line items in this order have been over-allocated" @@ -3356,21 +3448,17 @@ msgstr "" #: order/templates/order/so_allocate_by_serial.html:9 msgid "Allocate stock items by serial number" -msgstr "" +msgstr "Seri numarası ile stok kalemlerini tahsis et" #: order/templates/order/so_allocation_delete.html:7 msgid "This action will unallocate the following stock from the Sales Order" -msgstr "" +msgstr "Bu işlem Sipariş Emrinden belirtilen stok kalemleri tahsis edemedi" #: order/templates/order/so_attachments.html:12 #: order/templates/order/so_navbar.html:26 msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - #: order/views.py:104 msgid "Add Purchase Order Attachment" msgstr "" @@ -3471,93 +3559,97 @@ msgstr "" msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:1012 +msgid "Update prices" +msgstr "" + +#: order/views.py:1270 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 +#: order/views.py:1330 msgid "Supplier part must be specified" msgstr "" -#: order/views.py:1326 +#: order/views.py:1336 msgid "Supplier must match for Part and Order" msgstr "" -#: order/views.py:1457 order/views.py:1475 +#: order/views.py:1467 order/views.py:1485 msgid "Edit Line Item" msgstr "" -#: order/views.py:1491 order/views.py:1503 +#: order/views.py:1501 order/views.py:1513 msgid "Delete Line Item" msgstr "" -#: order/views.py:1496 order/views.py:1508 +#: order/views.py:1506 order/views.py:1518 msgid "Deleted line item" msgstr "" -#: order/views.py:1521 +#: order/views.py:1531 msgid "Allocate Serial Numbers" -msgstr "" +msgstr "Seri Numaralarını Tahsis Et" -#: order/views.py:1566 +#: order/views.py:1576 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1592 msgid "Select line item" msgstr "" -#: order/views.py:1613 -#, python-brace-format -msgid "No matching item for serial {serial}" -msgstr "" - #: order/views.py:1623 #, python-brace-format -msgid "{serial} is not in stock" -msgstr "" +msgid "No matching item for serial {serial}" +msgstr "{serial} seri numarası için eşleşen öge bulunamadı" -#: order/views.py:1631 +#: order/views.py:1633 +#, python-brace-format +msgid "{serial} is not in stock" +msgstr "{serial} stokta yok" + +#: order/views.py:1641 #, python-brace-format msgid "{serial} already allocated to an order" -msgstr "" +msgstr "{serial} zaten bir emirde tahsis edilmiş" -#: order/views.py:1685 +#: order/views.py:1695 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1769 msgid "Edit Allocation Quantity" -msgstr "" +msgstr "Tahsis Miktarını Düzenle" -#: order/views.py:1774 +#: order/views.py:1784 msgid "Remove allocation" -msgstr "" +msgstr "Tahsisi Sil" -#: order/views.py:1846 +#: order/views.py:1856 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1862 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1865 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1870 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 +#: part/bom.py:138 part/models.py:72 part/models.py:747 #: part/templates/part/category.html:66 part/templates/part/detail.html:90 msgid "Default Location" -msgstr "" +msgstr "Varsayılan Konum" #: part/bom.py:139 part/templates/part/part_base.html:124 msgid "Available Stock" @@ -3566,23 +3658,23 @@ msgstr "" #: part/bom.py:379 #, python-brace-format msgid "Unsupported file format: {f}" -msgstr "" +msgstr "Geçersiz dosya biçimi: {f}" #: part/bom.py:384 msgid "Error reading BOM file (invalid data)" -msgstr "" +msgstr "Malzeme listesi okurken hata (geçersiz data)" #: part/bom.py:386 msgid "Error reading BOM file (incorrect row size)" -msgstr "" +msgstr "Malzeme listesi okurken hata (geçersiz satır boyutu)" #: part/forms.py:89 stock/forms.py:265 msgid "File Format" -msgstr "" +msgstr "Dosya Biçimi" #: part/forms.py:89 stock/forms.py:265 msgid "Select output file format" -msgstr "" +msgstr "Çıktı dosyası biçimi seçin" #: part/forms.py:91 msgid "Cascading" @@ -3630,9 +3722,9 @@ msgstr "" #: part/forms.py:101 msgid "Include part supplier data in exported BOM" -msgstr "" +msgstr "Dışa aktarılan malzeme listesine parça tedarikçisi verilerini dahil edin" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:122 part/models.py:2191 msgid "Parent Part" msgstr "" @@ -3658,11 +3750,11 @@ msgstr "" #: part/forms.py:165 msgid "BOM file" -msgstr "" +msgstr "Malzeme Listesi Dosyası" #: part/forms.py:165 msgid "Select BOM file to upload" -msgstr "" +msgstr "Yüklemek için Malzeme Listesi dosyası seçin" #: part/forms.py:184 msgid "Related Part" @@ -3694,21 +3786,21 @@ msgstr "" #: part/forms.py:237 msgid "Include category parameter templates" -msgstr "" +msgstr "Kategori parametre şablonlarını dahil et" #: part/forms.py:242 msgid "Include parent categories parameter templates" -msgstr "" +msgstr "Üst kategorilerin parametre şablonlarını dahil et" #: part/forms.py:322 msgid "Add parameter template to same level categories" -msgstr "" +msgstr "Parametre şablonunu aynı seviyedeki kategorilere ekle" #: part/forms.py:326 msgid "Add parameter template to all categories" -msgstr "" +msgstr "Parametre şablonunu tüm kategorilere ekle" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:344 part/models.py:2286 msgid "Sub part" msgstr "" @@ -3718,7 +3810,7 @@ msgstr "" #: part/models.py:73 msgid "Default location for parts in this category" -msgstr "" +msgstr "Bu kategori içindeki parçalar için varsayılan konum" #: part/models.py:76 msgid "Default keywords" @@ -3728,7 +3820,7 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:82 part/models.py:2237 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" @@ -3737,367 +3829,362 @@ msgstr "" #: part/templates/part/category.html:94 templates/InvenTree/search.html:127 #: templates/stats.html:84 users/models.py:39 msgid "Part Categories" -msgstr "" +msgstr "Parça Kategorileri" -#: part/models.py:446 part/models.py:458 +#: part/models.py:448 part/models.py:460 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:557 msgid "Next available serial numbers are" -msgstr "" +msgstr "Sonraki kullanılabilir seri numaraları" -#: part/models.py:559 +#: part/models.py:561 msgid "Next available serial number is" -msgstr "" +msgstr "Sonraki müsait seri numarası" -#: part/models.py:564 +#: part/models.py:566 msgid "Most recent serial number is" -msgstr "" +msgstr "En son seri numarası" -#: part/models.py:643 +#: part/models.py:645 msgid "Duplicate IPN not allowed in part settings" -msgstr "" +msgstr "Yinelenen DPN'ye parça ayarlarında izin verilmiyor" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:670 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:677 msgid "Is Template" -msgstr "" +msgstr "Şablon Mu" -#: part/models.py:693 +#: part/models.py:678 msgid "Is this part a template part?" -msgstr "" +msgstr "Bu parça bir şablon parçası mı?" -#: part/models.py:704 +#: part/models.py:689 msgid "Is this part a variant of another part?" -msgstr "" +msgstr "Bu parça başka bir parçanın çeşidi mi?" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:690 part/templates/part/detail.html:60 msgid "Variant Of" -msgstr "" +msgstr "Çeşidi" -#: part/models.py:711 +#: part/models.py:696 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:701 part/templates/part/category.html:73 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:702 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:709 part/models.py:2236 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:710 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:715 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" -msgstr "" +msgstr "DPN" -#: part/models.py:731 +#: part/models.py:716 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:722 msgid "Part revision or version number" -msgstr "" +msgstr "Parça revizyon veya versiyon numarası" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:723 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" -msgstr "" +msgstr "Revizyon" -#: part/models.py:760 +#: part/models.py:745 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:792 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:793 msgid "Default supplier part" -msgstr "" +msgstr "Varsayılan tedarikçi parçası" -#: part/models.py:815 +#: part/models.py:800 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:801 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:806 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:807 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:814 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:820 msgid "Can this part be built from other parts?" -msgstr "" +msgstr "Bu parça diğer parçalardan yapılabilir mi?" -#: part/models.py:841 +#: part/models.py:826 msgid "Can this part be used to build other parts?" -msgstr "" +msgstr "Bu parça diğer parçaların yapımında kullanılabilir mi?" -#: part/models.py:847 +#: part/models.py:832 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:837 msgid "Can this part be purchased from external suppliers?" -msgstr "" +msgstr "Bu parça dış tedarikçilerden satın alınabilir mi?" -#: part/models.py:857 +#: part/models.py:842 msgid "Can this part be sold to customers?" -msgstr "" +msgstr "Bu parça müşterilere satılabilir mi?" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:846 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 #: templates/js/table_filters.js:241 templates/js/table_filters.js:310 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:847 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:852 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:857 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:863 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:865 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:869 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1608 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2063 msgid "Test templates can only be created for trackable parts" -msgstr "" +msgstr "Test şablonları sadece takip edilebilir paçalar için oluşturulabilir" -#: part/models.py:2057 +#: part/models.py:2080 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2100 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2101 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2106 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2107 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 +#: part/models.py:2112 templates/js/part.js:726 #: templates/js/table_filters.js:227 msgid "Required" -msgstr "" +msgstr "Gerekli" -#: part/models.py:2090 +#: part/models.py:2113 msgid "Is this test required to pass?" -msgstr "" +msgstr "Testi geçmesi için bu gerekli mi?" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2118 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2119 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2124 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2125 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2158 msgid "Parameter template name must be unique" -msgstr "" +msgstr "Parametre şablon adı benzersiz olmalıdır" -#: part/models.py:2140 +#: part/models.py:2163 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2165 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2193 part/models.py:2242 part/models.py:2243 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" -msgstr "" +msgstr "Parametre Şablonu" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2247 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2248 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2278 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2287 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2293 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2295 templates/js/bom.js:216 templates/js/bom.js:285 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2295 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2298 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2299 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2302 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2305 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2311 templates/js/bom.js:302 templates/js/bom.js:309 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2312 msgid "This BOM item is inherited by BOMs for variant parts" -msgstr "" +msgstr "Bu malzeme listesi, çeşit parçalar listesini kalıtsalıdır" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2317 templates/js/bom.js:294 msgid "Allow Variants" -msgstr "" +msgstr "Çeşide İzin Ver" -#: part/models.py:2295 +#: part/models.py:2318 msgid "Stock items for variant parts can be used for this BOM item" -msgstr "" +msgstr "Çeşit parçaların stok kalemleri bu malzeme listesinde kullanılabilir" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 +#: part/models.py:2394 part/views.py:1692 part/views.py:1744 #: stock/models.py:294 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2403 part/models.py:2405 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2408 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2527 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2563 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 @@ -4112,8 +4199,8 @@ msgstr "" msgid "Deleting this entry will remove the BOM row from the following part" msgstr "" -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:50 +#: part/templates/part/navbar.html:53 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4247,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:1987 msgid "Export Bill of Materials" msgstr "" @@ -4177,7 +4264,7 @@ msgid "All selected BOM items will be deleted" msgstr "" #: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: templates/js/stock.js:1313 msgid "Create New Part" msgstr "" @@ -4227,11 +4314,11 @@ msgstr "" #: part/templates/part/bom_upload/upload_file.html:21 msgid "The BOM file must contain the required named columns as provided in the " -msgstr "" +msgstr "Malzeme Listesi dosyası gerekli sütün adlarını sağlandığı şekilde içermelidir " #: part/templates/part/bom_upload/upload_file.html:21 msgid "BOM Upload Template" -msgstr "" +msgstr "Malzeme Listesi Şablonu Yükle" #: part/templates/part/bom_upload/upload_file.html:22 msgid "Each part must already exist in the database" @@ -4258,7 +4345,7 @@ msgstr "" msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:29 part/views.py:2397 msgid "Create new part category" msgstr "" @@ -4272,7 +4359,7 @@ msgstr "" #: part/templates/part/category.html:50 part/templates/part/category.html:89 msgid "Category Details" -msgstr "" +msgstr "Kategori Detayları" #: part/templates/part/category.html:55 msgid "Category Path" @@ -4287,11 +4374,11 @@ msgstr "" #: part/templates/part/category_navbar.html:18 #: part/templates/part/subcategory.html:16 msgid "Subcategories" -msgstr "" +msgstr "Alt kategoriler" #: part/templates/part/category.html:84 msgid "Parts (Including subcategories)" -msgstr "" +msgstr "Parçalar (Alt kategoriler dahil)" #: part/templates/part/category.html:113 msgid "Export Part Data" @@ -4299,11 +4386,11 @@ msgstr "" #: part/templates/part/category.html:125 msgid "Set category" -msgstr "" +msgstr "Kategori ayarla" #: part/templates/part/category.html:125 msgid "Set Category" -msgstr "" +msgstr "Kategori Ayarla" #: part/templates/part/category.html:128 msgid "Export Data" @@ -4318,9 +4405,9 @@ msgid "View grid display" msgstr "" #: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: stock/templates/stock/location.html:192 templates/js/stock.js:737 msgid "Create new location" -msgstr "" +msgstr "Yeni konum oluştur" #: part/templates/part/category.html:214 part/templates/part/category.html:244 msgid "New Category" @@ -4336,7 +4423,7 @@ msgstr "" #: part/templates/part/category.html:251 stock/views.py:1391 msgid "Create new Stock Location" -msgstr "" +msgstr "Yeni Stok konumu oluştur" #: part/templates/part/category_delete.html:5 msgid "Are you sure you want to delete category" @@ -4345,11 +4432,11 @@ msgstr "" #: part/templates/part/category_delete.html:8 #, python-format msgid "This category contains %(count)s child categories" -msgstr "" +msgstr "Bu kategori %(count)s alt kategori içermektedir" #: part/templates/part/category_delete.html:9 msgid "If this category is deleted, these child categories will be moved to the" -msgstr "" +msgstr "Bu kategori silinirse, alt kategoriler taşınacaktır" #: part/templates/part/category_delete.html:11 msgid "category" @@ -4373,14 +4460,8 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 -#: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" -msgstr "" - #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:21 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" @@ -4408,17 +4489,17 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:13 msgid "Part Details" msgstr "" #: part/templates/part/detail.html:42 part/templates/part/part_base.html:188 msgid "Latest Serial Number" -msgstr "" +msgstr "Son Seri Numarası" #: part/templates/part/detail.html:47 msgid "No serial numbers recorded" -msgstr "" +msgstr "Seri numaraları kaydedildi" #: part/templates/part/detail.html:120 msgid "Stock Expiry Time" @@ -4438,11 +4519,11 @@ msgstr "" #: part/templates/part/detail.html:163 msgid "Part is a template part (variants can be made from this part)" -msgstr "" +msgstr "Bu parça bir şablon parçadır (Bu parçanın çeşitleri yapılabilir)" #: part/templates/part/detail.html:165 msgid "Part is not a template part" -msgstr "" +msgstr "Parça şablon parçası değil" #: part/templates/part/detail.html:173 msgid "Part can be assembled from other parts" @@ -4462,15 +4543,15 @@ msgstr "" #: part/templates/part/detail.html:193 msgid "Part stock is tracked by serial number" -msgstr "" +msgstr "Parça stoku seri numarası ile takip edilebilir" #: part/templates/part/detail.html:195 msgid "Part stock is not tracked by serial number" -msgstr "" +msgstr "Parça stoku seri numarası ile takip edilemez" #: part/templates/part/detail.html:203 part/templates/part/detail.html:205 msgid "Part can be purchased from external suppliers" -msgstr "" +msgstr "Bu parça harici tedarikçilerden satın alınabilir" #: part/templates/part/detail.html:213 msgid "Part can be sold to customers" @@ -4488,6 +4569,36 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/internal_prices.html:11 +#: part/templates/part/navbar.html:100 +msgid "Internal Price Information" +msgstr "" + +#: part/templates/part/internal_prices.html:19 part/views.py:2822 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/internal_prices.html:28 templates/403.html:5 +#: templates/403.html:11 +msgid "Permission Denied" +msgstr "" + +#: part/templates/part/internal_prices.html:31 templates/403.html:14 +msgid "You do not have permission to view this page." +msgstr "" + +#: part/templates/part/internal_prices.html:59 +msgid "No internal price break information found" +msgstr "" + +#: part/templates/part/internal_prices.html:110 +msgid "Edit internal price break" +msgstr "" + +#: part/templates/part/internal_prices.html:111 +msgid "Delete internal price break" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4501,127 +4612,141 @@ msgstr "" msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:28 part/templates/part/variants.html:11 msgid "Part Variants" -msgstr "" +msgstr "Parça Çeşitleri" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:31 msgid "Variants" -msgstr "" +msgstr "Çeşitler" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:42 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:45 msgid "Allocations" -msgstr "" +msgstr "Tahsisler" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:66 part/templates/part/navbar.html:69 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 +#: part/templates/part/navbar.html:74 part/templates/part/order_prices.html:12 msgid "Order Price Information" msgstr "" -#: part/templates/part/navbar.html:75 +#: part/templates/part/navbar.html:77 msgid "Order Price" msgstr "" -#: part/templates/part/navbar.html:98 +#: part/templates/part/navbar.html:103 part/templates/part/order_prices.html:93 +#: part/templates/part/part_pricing.html:82 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/navbar.html:106 msgid "Sales Price Information" msgstr "" -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:120 part/templates/part/part_tests.html:10 msgid "Part Test Templates" -msgstr "" +msgstr "Parça Test Şablonları" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:123 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:127 part/templates/part/navbar.html:130 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:139 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 +#: part/templates/part/order_prices.html:24 +#: part/templates/part/part_base.html:282 +msgid "Calculate" +msgstr "" + +#: part/templates/part/order_prices.html:31 msgid "Pricing ranges" msgstr "" -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 +#: part/templates/part/order_prices.html:36 +#: part/templates/part/part_pricing.html:22 msgid "Supplier Pricing" msgstr "" -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 +#: part/templates/part/order_prices.html:37 +#: part/templates/part/order_prices.html:62 +#: part/templates/part/order_prices.html:94 +#: part/templates/part/order_prices.html:108 +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 msgid "Unit Cost" msgstr "" -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 +#: part/templates/part/order_prices.html:44 +#: part/templates/part/order_prices.html:69 +#: part/templates/part/order_prices.html:99 +#: part/templates/part/order_prices.html:113 +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 msgid "Total Cost" msgstr "" -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 +#: part/templates/part/order_prices.html:52 +#: part/templates/part/part_pricing.html:40 msgid "No supplier pricing available" msgstr "" -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 +#: part/templates/part/order_prices.html:61 +#: part/templates/part/order_prices.html:128 +#: part/templates/part/part_pricing.html:48 msgid "BOM Pricing" msgstr "" -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 +#: part/templates/part/order_prices.html:77 +#: part/templates/part/part_pricing.html:66 msgid "Note: BOM pricing is incomplete for this part" msgstr "" -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 +#: part/templates/part/order_prices.html:84 +#: part/templates/part/part_pricing.html:73 msgid "No BOM pricing available" msgstr "" -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 +#: part/templates/part/order_prices.html:122 +#: part/templates/part/part_pricing.html:113 msgid "No pricing information is available for this part." msgstr "" -#: part/templates/part/order_prices.html:113 +#: part/templates/part/order_prices.html:138 msgid "Stock Pricing" msgstr "" -#: part/templates/part/order_prices.html:121 +#: part/templates/part/order_prices.html:146 msgid "No stock pricing history is available for this part." msgstr "" -#: part/templates/part/order_prices.html:140 +#: part/templates/part/order_prices.html:165 #, python-format msgid "Single Price - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:152 +#: part/templates/part/order_prices.html:177 #, python-format msgid "Single Price Difference - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:163 +#: part/templates/part/order_prices.html:189 #, python-format msgid "Part Single Price - %(currency)s" msgstr "" @@ -4630,37 +4755,24 @@ msgstr "" msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" #: part/templates/part/params.html:68 msgid "New Template" -msgstr "" +msgstr "Yeni Şablon" #: part/templates/part/params.html:69 msgid "Create New Parameter Template" -msgstr "" +msgstr "Yeni Parametre Şablonu Oluştur" #: part/templates/part/part_app_base.html:12 msgid "Part List" msgstr "" #: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: templates/js/company.js:355 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4672,7 +4784,7 @@ msgstr "" #: stock/templates/stock/item_base.html:75 #: stock/templates/stock/location.html:51 msgid "Barcode actions" -msgstr "" +msgstr "Barkod işlemleri" #: part/templates/part/part_base.html:42 #: stock/templates/stock/item_base.html:77 @@ -4684,7 +4796,7 @@ msgstr "" #: stock/templates/stock/item_base.html:93 #: stock/templates/stock/location.html:54 msgid "Print Label" -msgstr "" +msgstr "Etiket Yazdır" #: part/templates/part/part_base.html:48 msgid "Show pricing information" @@ -4696,7 +4808,7 @@ msgstr "" #: part/templates/part/part_base.html:67 msgid "Part actions" -msgstr "" +msgstr "Parça işlemleri" #: part/templates/part/part_base.html:70 msgid "Duplicate part" @@ -4717,7 +4829,7 @@ msgstr "" #: part/templates/part/part_base.html:113 #, python-format msgid "This part is a variant of %(link)s" -msgstr "" +msgstr "Bu parça %(link)s parçasının bir çeşididir" #: part/templates/part/part_base.html:130 templates/js/table_filters.js:161 msgid "In Stock" @@ -4725,11 +4837,11 @@ msgstr "" #: part/templates/part/part_base.html:143 templates/InvenTree/index.html:131 msgid "Required for Build Orders" -msgstr "" +msgstr "Yapım İşi Emirleri için Gerekli" #: part/templates/part/part_base.html:150 msgid "Required for Sales Orders" -msgstr "" +msgstr "Satış Emirleri için Gerekli" #: part/templates/part/part_base.html:157 msgid "Allocated to Orders" @@ -4740,17 +4852,13 @@ msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 -msgid "Calculate" -msgstr "" - #: part/templates/part/part_tests.html:17 msgid "Add Test Template" -msgstr "" +msgstr "Test Şablonu Ekle" #: part/templates/part/part_thumb.html:20 msgid "Select from existing images" @@ -4779,7 +4887,7 @@ msgstr "" #: part/templates/part/partial_delete.html:44 #, python-format msgid "There are %(count)s suppliers defined for this part. If you delete this part, the following supplier parts will also be deleted:" -msgstr "" +msgstr "Bu parçası için tanımlanmış %(count)s tedarikçi bulunmaktadır. Bu parçayı silerseniz, aşağıdaki tedarikçi parçaları da silinecektir:" #: part/templates/part/partial_delete.html:55 #, python-format @@ -4804,29 +4912,29 @@ msgstr "" #: part/templates/part/set_category.html:9 msgid "Set category for the following parts" -msgstr "" +msgstr "Aşağıdaki parçalara kategori ayarla" #: part/templates/part/stock.html:10 msgid "Part Stock" -msgstr "" +msgstr "Parça Stoku" #: part/templates/part/stock.html:16 #, python-format msgid "Showing stock for all variants of %(full_name)s" -msgstr "" +msgstr "%(full_name)s için tüm çeşitlerin stokları gösteriliyor" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" -msgstr "" +msgstr "Stok Yok" #: part/templates/part/stock_count.html:9 templates/InvenTree/index.html:130 msgid "Low Stock" -msgstr "" +msgstr "Düşük Stok" #: part/templates/part/supplier.html:10 msgid "Part Suppliers" -msgstr "" +msgstr "Parça Tedarikçileri" #: part/templates/part/track.html:10 msgid "Part Tracking" @@ -4838,22 +4946,22 @@ msgstr "" #: part/templates/part/variant_part.html:9 msgid "Create new part variant" -msgstr "" +msgstr "Yeni parça çeşidi oluştur" #: part/templates/part/variant_part.html:10 #, python-format msgid "Create a new variant of template '%(full_name)s'." -msgstr "" +msgstr "%(full_name)s şablonu için yeni bir çeşit oluştur." #: part/templates/part/variants.html:19 msgid "Create new variant" -msgstr "" +msgstr "Yeni çeşit oluştur" #: part/templates/part/variants.html:20 msgid "New Variant" -msgstr "" +msgstr "Yeni Çeşit" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" @@ -4887,15 +4995,15 @@ msgstr "" #: part/views.py:248 msgid "Create Test Template" -msgstr "" +msgstr "Test Şablonu Oluştur" #: part/views.py:275 msgid "Edit Test Template" -msgstr "" +msgstr "Test Şablonu Düzenle" #: part/views.py:289 msgid "Delete Test Template" -msgstr "" +msgstr "Test Şablonu Sil" #: part/views.py:296 msgid "Set Part Category" @@ -4908,7 +5016,7 @@ msgstr "" #: part/views.py:381 msgid "Create Variant" -msgstr "" +msgstr "Çeşit Oluştur" #: part/views.py:466 msgid "Copied part" @@ -4922,233 +5030,245 @@ msgstr "" msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:925 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 +#: part/views.py:1027 msgid "Upload Part Image" msgstr "" -#: part/views.py:1022 part/views.py:1057 +#: part/views.py:1033 part/views.py:1068 msgid "Updated part image" msgstr "" -#: part/views.py:1031 +#: part/views.py:1042 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1071 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1082 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1117 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1147 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1168 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1189 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1200 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1334 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1695 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1720 part/views.py:1723 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1729 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1767 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1773 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1777 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2039 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2046 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2055 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2196 msgid "Create Part Parameter Template" -msgstr "" +msgstr "Parça Parametre Şablonu Oluştur" -#: part/views.py:2188 +#: part/views.py:2206 msgid "Edit Part Parameter Template" -msgstr "" +msgstr "Parça Parametre Şablonu Düzenle" -#: part/views.py:2195 +#: part/views.py:2213 msgid "Delete Part Parameter Template" -msgstr "" +msgstr "Parça Parametre Şablonu Sil" -#: part/views.py:2203 +#: part/views.py:2221 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2271 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2285 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 +#: part/views.py:2345 msgid "Edit Part Category" msgstr "" -#: part/views.py:2365 +#: part/views.py:2383 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2389 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2441 msgid "Create Category Parameter Template" -msgstr "" +msgstr "Kategori Parametre Şablonu Oluştur" -#: part/views.py:2524 +#: part/views.py:2542 msgid "Edit Category Parameter Template" -msgstr "" +msgstr "Kategori Parametre Şablonu Düzenle" -#: part/views.py:2580 +#: part/views.py:2598 msgid "Delete Category Parameter Template" -msgstr "" +msgstr "Kategori Parametre Şablonu Sil" -#: part/views.py:2599 +#: part/views.py:2617 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2687 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 +#: part/views.py:2743 msgid "Confim BOM item deletion" msgstr "" -#: report/models.py:180 +#: part/views.py:2831 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2839 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" -msgstr "" +msgstr "Şablon adı" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" -msgstr "" +msgstr "Rapor şablon dosyası" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" -msgstr "" +msgstr "Rapor şablon tanımı" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" +msgstr "Revizyon numarası raporla (otomatik artış)" + +#: report/models.py:291 +msgid "Pattern for generating report filenames" msgstr "" -#: report/models.py:275 +#: report/models.py:298 msgid "Report template is enabled" -msgstr "" +msgstr "Rapor şablonu etkin" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" -msgstr "" +msgstr "Stok kalemi sorgu filtreleri (anahter=değer [key=value] olarak virgülle ayrılmış liste)" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" #: report/templates/report/inventree_build_order_base.html:147 msgid "Required For" -msgstr "" +msgstr "İçin Gerekli Olan" #: report/templates/report/inventree_po_report.html:85 #: report/templates/report/inventree_so_report.html:85 @@ -5174,7 +5294,7 @@ msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:195 templates/js/stock.js:1012 msgid "Date" msgstr "" @@ -5189,7 +5309,7 @@ msgstr "" #: stock/api.py:212 #, python-brace-format msgid "Updated stock for {n} items" -msgstr "" +msgstr "{n} öge için stok güncellendi" #: stock/api.py:281 #, python-brace-format @@ -5197,54 +5317,54 @@ msgid "Moved {n} parts to {loc}" msgstr "" #: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" #: stock/forms.py:115 stock/forms.py:419 msgid "Expiration date for this stock item" -msgstr "" +msgstr "Bu stok kalemi için son kullanma tarihi" #: stock/forms.py:118 msgid "Enter unique serial numbers (or leave blank)" -msgstr "" +msgstr "Benzersiz seri numaraları giriniz (veya boş bırakınız)" #: stock/forms.py:169 msgid "Destination for serialized stock (by default, will remain in current location)" -msgstr "" +msgstr "Seri numaralandırılmış stok için hedef konum(varsayılan olarak, geçerli konumda kalacaktır)" #: stock/forms.py:171 msgid "Serial numbers" -msgstr "" +msgstr "Seri numaraları" #: stock/forms.py:171 msgid "Unique serial numbers (must match quantity)" -msgstr "" +msgstr "Benzersiz seri numaraları (miktar ile eşleşmeli)" #: stock/forms.py:173 stock/forms.py:349 msgid "Add transaction note (optional)" -msgstr "" +msgstr "İşlem notu ekle (isteğe bağlı)" #: stock/forms.py:203 stock/forms.py:259 msgid "Select test report template" -msgstr "" +msgstr "Test raporu şablonu seç" #: stock/forms.py:267 templates/js/table_filters.js:75 #: templates/js/table_filters.js:138 msgid "Include sublocations" -msgstr "" +msgstr "Alt konumları dahil et" #: stock/forms.py:267 msgid "Include stock items in sub locations" -msgstr "" +msgstr "Stok kalemlerine alt konumları dahil et" #: stock/forms.py:302 msgid "Stock item to install" -msgstr "" +msgstr "Kurulacak stok kalemi" #: stock/forms.py:309 msgid "Stock quantity to assign" -msgstr "" +msgstr "Atanacak stok miktarı" #: stock/forms.py:337 msgid "Must not exceed available quantity" @@ -5252,7 +5372,7 @@ msgstr "" #: stock/forms.py:347 msgid "Destination location for uninstalled items" -msgstr "" +msgstr "Sökülen ögeler için hedef konum" #: stock/forms.py:351 msgid "Confirm uninstall" @@ -5260,31 +5380,31 @@ msgstr "" #: stock/forms.py:351 msgid "Confirm removal of installed stock items" -msgstr "" +msgstr "Kurulu stok kalemlerinin kaldırılmasını onayla" #: stock/forms.py:375 msgid "Destination stock location" -msgstr "" +msgstr "Hedef stok konumu" #: stock/forms.py:377 msgid "Add note (required)" -msgstr "" +msgstr "Not ekle (gerekli)" #: stock/forms.py:381 stock/views.py:852 stock/views.py:1051 msgid "Confirm stock adjustment" -msgstr "" +msgstr "Stok ayarlamasını onayla" #: stock/forms.py:381 msgid "Confirm movement of stock items" -msgstr "" +msgstr "Stok kalemlerinin hareketini onaylayın" #: stock/forms.py:383 msgid "Set Default Location" -msgstr "" +msgstr "Varsayılan Konum Ayarla" #: stock/forms.py:383 msgid "Set the destination as the default location for selected parts" -msgstr "" +msgstr "Hedefi seçili parçalar için varsayılan konum olarak ayarla" #: stock/models.py:56 stock/models.py:547 msgid "Owner" @@ -5296,7 +5416,7 @@ msgstr "" #: stock/models.py:275 msgid "StockItem with this serial number already exists" -msgstr "" +msgstr "Bu seri numarasına sahip stok kalemi zaten var" #: stock/models.py:311 #, python-brace-format @@ -5305,11 +5425,11 @@ msgstr "" #: stock/models.py:321 stock/models.py:330 msgid "Quantity must be 1 for item with a serial number" -msgstr "" +msgstr "Seri numarası olan ögenin miktarı bir olmalı" #: stock/models.py:322 msgid "Serial number cannot be set if quantity greater than 1" -msgstr "" +msgstr "Miktar birden büyük ise seri numarası ayarlanamaz" #: stock/models.py:344 msgid "Item cannot belong to itself" @@ -5325,7 +5445,7 @@ msgstr "" #: stock/models.py:399 msgid "Parent Stock Item" -msgstr "" +msgstr "Üst Stok Kalemi" #: stock/models.py:408 msgid "Base part" @@ -5333,11 +5453,11 @@ msgstr "" #: stock/models.py:417 msgid "Select a matching supplier part for this stock item" -msgstr "" +msgstr "Bu stok kalemi için tedarikçi parçası seçin" #: stock/models.py:422 stock/templates/stock/stock_app_base.html:8 msgid "Stock Location" -msgstr "" +msgstr "Stok Konumu" #: stock/models.py:425 msgid "Where is this stock item located?" @@ -5357,7 +5477,7 @@ msgstr "" #: stock/models.py:456 msgid "Serial number for this item" -msgstr "" +msgstr "Bu öge için seri numarası" #: stock/models.py:468 msgid "Batch code for this stock item" @@ -5423,20 +5543,20 @@ msgstr "" #: stock/models.py:1026 msgid "Serial numbers must be a list of integers" -msgstr "" +msgstr "Seri numaraları tam sayı listesi olmalı" #: stock/models.py:1029 msgid "Quantity does not match serial numbers" -msgstr "" +msgstr "Miktar seri numaları ile eşleşmiyor" #: stock/models.py:1036 #, python-brace-format msgid "Serial numbers already exist: {exists}" -msgstr "" +msgstr "Seri numaraları zaten mevcut: {exists}" #: stock/models.py:1194 msgid "StockItem cannot be moved as it is not in stock" -msgstr "" +msgstr "Stok kalemi stokta olmadığı için taşınamaz" #: stock/models.py:1668 msgid "Entry notes" @@ -5483,12 +5603,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5503,11 +5623,11 @@ msgstr "" #: stock/templates/stock/item_base.html:84 templates/stock_table.html:31 msgid "Scan to Location" -msgstr "" +msgstr "Konuma Tara" #: stock/templates/stock/item_base.html:91 msgid "Printing actions" -msgstr "" +msgstr "Yazdırma işlemleri" #: stock/templates/stock/item_base.html:95 #: stock/templates/stock/item_tests.html:27 @@ -5516,7 +5636,7 @@ msgstr "" #: stock/templates/stock/item_base.html:104 msgid "Stock adjustment actions" -msgstr "" +msgstr "Stok ayarlama işlemleri" #: stock/templates/stock/item_base.html:108 #: stock/templates/stock/location.html:65 templates/stock_table.html:57 @@ -5533,7 +5653,7 @@ msgstr "" #: stock/templates/stock/item_base.html:117 msgid "Serialize stock" -msgstr "" +msgstr "Stoku seri numarala" #: stock/templates/stock/item_base.html:121 msgid "Transfer stock" @@ -5558,11 +5678,11 @@ msgstr "" #: stock/templates/stock/item_base.html:140 #: stock/templates/stock/location.html:62 msgid "Stock actions" -msgstr "" +msgstr "Stok işlemleri" #: stock/templates/stock/item_base.html:143 msgid "Convert to variant" -msgstr "" +msgstr "Çeşide çevir" #: stock/templates/stock/item_base.html:146 msgid "Duplicate stock item" @@ -5590,7 +5710,7 @@ msgstr "" #: stock/templates/stock/item_base.html:192 msgid "This stock item has not passed all required tests" -msgstr "" +msgstr "Stok kalemi tüm gerekli testleri geçmedi" #: stock/templates/stock/item_base.html:200 #, python-format @@ -5604,7 +5724,7 @@ msgstr "" #: stock/templates/stock/item_base.html:214 msgid "This stock item is serialized - it has a unique serial number and the quantity cannot be adjusted." -msgstr "" +msgstr "Bu stok kalemi seri numaları - Benzersiz bir seri numarasına sahip ve miktarı ayarlanamaz." #: stock/templates/stock/item_base.html:218 msgid "This stock item cannot be deleted as it has child items" @@ -5618,9 +5738,9 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:593 msgid "No location set" -msgstr "" +msgstr "Konum ayarlanmadı" #: stock/templates/stock/item_base.html:296 msgid "Barcode Identifier" @@ -5630,25 +5750,29 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" -msgstr "" +msgstr "Bu stok kaleminin süresi %(item.expiry_date)s tarihinde sona erdi" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" -msgstr "" +msgstr "Bu stok kaleminin süresi %(item.expiry_date)s tarihinde sona erecek" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" @@ -5671,7 +5795,7 @@ msgstr "" #: stock/templates/stock/item_install.html:7 msgid "Install another StockItem into this item." -msgstr "" +msgstr "Bu ögeye başka bir stok kalemi ekle." #: stock/templates/stock/item_install.html:10 msgid "Stock items can only be installed if they meet the following criteria" @@ -5679,11 +5803,11 @@ msgstr "" #: stock/templates/stock/item_install.html:13 msgid "The StockItem links to a Part which is in the BOM for this StockItem" -msgstr "" +msgstr "Bu stok kalemi, kendi malzeme listesinin bir parçasına bağlıdır" #: stock/templates/stock/item_install.html:14 msgid "The StockItem is currently in stock" -msgstr "" +msgstr "Bu stok kalemi şu anda stokta" #: stock/templates/stock/item_installed.html:11 #: stock/templates/stock/navbar.html:27 @@ -5692,11 +5816,11 @@ msgstr "" #: stock/templates/stock/item_serialize.html:5 msgid "Create serialized items from this stock item." -msgstr "" +msgstr "Bu stok kalemi için seri numaralandırılmış ögeler oluştur." #: stock/templates/stock/item_serialize.html:7 msgid "Select quantity to serialize, and unique serial numbers." -msgstr "" +msgstr "Seri numaralandırılacak miktarı ve benzersiz seri numaralarını seçin." #: stock/templates/stock/item_tests.html:11 #: stock/templates/stock/navbar.html:19 stock/templates/stock/navbar.html:22 @@ -5713,7 +5837,7 @@ msgstr "" #: stock/templates/stock/location.html:20 msgid "You are not in the list of owners of this location. This stock location cannot be edited." -msgstr "" +msgstr "Bu konumun sahipleri listesinde değilsiniz. Bu stok konumu düzenlenemez." #: stock/templates/stock/location.html:37 msgid "All stock items" @@ -5725,34 +5849,34 @@ msgstr "" #: stock/templates/stock/location.html:71 msgid "Location actions" -msgstr "" +msgstr "Konum işlemleri" #: stock/templates/stock/location.html:73 msgid "Edit location" -msgstr "" +msgstr "Konumu düzenle" #: stock/templates/stock/location.html:75 msgid "Delete location" -msgstr "" +msgstr "Konumu sil" #: stock/templates/stock/location.html:87 msgid "Location Details" -msgstr "" +msgstr "Konum Detayları" #: stock/templates/stock/location.html:92 msgid "Location Path" -msgstr "" +msgstr "Konum Yolu" #: stock/templates/stock/location.html:97 msgid "Location Description" -msgstr "" +msgstr "Konum Tanımı" #: stock/templates/stock/location.html:102 #: stock/templates/stock/location_navbar.html:11 #: stock/templates/stock/location_navbar.html:18 #: stock/templates/stock/sublocation.html:16 msgid "Sublocations" -msgstr "" +msgstr "Alt konumlar" #: stock/templates/stock/location.html:112 msgid "Stock Details" @@ -5761,11 +5885,11 @@ msgstr "" #: stock/templates/stock/location.html:117 templates/InvenTree/search.html:279 #: templates/stats.html:97 users/models.py:41 msgid "Stock Locations" -msgstr "" +msgstr "Stok Konumları" #: stock/templates/stock/location_delete.html:7 msgid "Are you sure you want to delete this stock location?" -msgstr "" +msgstr "Bu stok konumunu silmek istediğinizden emin misiniz?" #: stock/templates/stock/navbar.html:11 msgid "Stock Item Tracking" @@ -5801,28 +5925,28 @@ msgstr "" #: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1364 msgid "Convert Stock Item" -msgstr "" +msgstr "Stok Kalemine Dönüştür" #: stock/templates/stock/stockitem_convert.html:8 #, python-format msgid "This stock item is current an instance of %(part)s" -msgstr "" +msgstr "Bu stok kalemi şu anda %(part)s parçasının örneğidir" #: stock/templates/stock/stockitem_convert.html:9 msgid "It can be converted to one of the part variants listed below." -msgstr "" +msgstr "Aşağıda listelenen parça çeşitlerinden birine dönüştürülebilir." #: stock/templates/stock/stockitem_convert.html:14 msgid "This action cannot be easily undone" -msgstr "" +msgstr "Bu işlem kolayca geri alınamaz" #: stock/templates/stock/sublocation.html:23 templates/stock_table.html:37 msgid "Printing Actions" -msgstr "" +msgstr "Yazdırma İşlemleri" #: stock/templates/stock/sublocation.html:27 templates/stock_table.html:41 msgid "Print labels" -msgstr "" +msgstr "Etiketleri yazdır" #: stock/templates/stock/tracking_delete.html:6 msgid "Are you sure you want to delete this stock tracking entry?" @@ -5830,16 +5954,16 @@ msgstr "" #: stock/views.py:123 msgid "Edit Stock Location" -msgstr "" +msgstr "Stok konumunu düzenle" #: stock/views.py:230 stock/views.py:1343 stock/views.py:1465 #: stock/views.py:1830 msgid "Owner is required (ownership control is enabled)" -msgstr "" +msgstr "Sahip gerekli (sahip kontrolü etkinleştirildi)" #: stock/views.py:245 msgid "Stock Location QR code" -msgstr "" +msgstr "Stok Konumu QR Kodu" #: stock/views.py:265 msgid "Add Stock Item Attachment" @@ -5867,7 +5991,7 @@ msgstr "" #: stock/views.py:385 msgid "Specify a valid location" -msgstr "" +msgstr "Geçerli bir konum belirtiniz" #: stock/views.py:396 msgid "Stock item returned from customer" @@ -5945,7 +6069,7 @@ msgstr "" msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:1001 users/models.py:187 msgid "Add" msgstr "" @@ -5968,7 +6092,7 @@ msgstr "" #: stock/views.py:1107 msgid "No action performed" -msgstr "" +msgstr "Herhangi bir işlem gerçekleştirilmedi" #: stock/views.py:1122 #, python-brace-format @@ -6009,9 +6133,9 @@ msgstr "" #: stock/views.py:1482 msgid "Serialize Stock" -msgstr "" +msgstr "Stoku Seri Numarala" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1575 templates/js/build.js:326 msgid "Create new Stock Item" msgstr "" @@ -6025,7 +6149,7 @@ msgstr "" #: stock/views.py:1899 msgid "Delete Stock Location" -msgstr "" +msgstr "Stok Konumunu Sil" #: stock/views.py:1912 msgid "Delete Stock Item" @@ -6043,14 +6167,6 @@ msgstr "" msgid "Add Stock Tracking Entry" msgstr "" -#: templates/403.html:5 templates/403.html:11 -msgid "Permission Denied" -msgstr "" - -#: templates/403.html:14 -msgid "You do not have permission to view this page." -msgstr "" - #: templates/404.html:5 templates/404.html:11 msgid "Page Not Found" msgstr "" @@ -6119,13 +6235,13 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" -msgstr "" +msgstr "Stok konumu ayarlanmadı" #: templates/InvenTree/settings/appearance.html:10 msgid "Theme Settings" @@ -6157,25 +6273,25 @@ msgstr "" #: templates/InvenTree/settings/category.html:9 msgid "Category Settings" -msgstr "" +msgstr "Kategori Ayarları" #: templates/InvenTree/settings/category.html:25 msgid "Category Parameter Templates" -msgstr "" +msgstr "Kategori Parametre Şablonu" #: templates/InvenTree/settings/category.html:52 msgid "No category parameter templates found" -msgstr "" +msgstr "Kategori parametre şablonu bulunamadı" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:85 msgid "Edit Template" -msgstr "" +msgstr "Şablonu Düzenle" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:86 msgid "Delete Template" -msgstr "" +msgstr "Şablonu Sil" #: templates/InvenTree/settings/currencies.html:10 msgid "Currency Settings" @@ -6221,13 +6337,13 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 +#: templates/InvenTree/settings/part.html:44 msgid "Part Parameter Templates" -msgstr "" +msgstr "Parça Parametre Şablonu" -#: templates/InvenTree/settings/part.html:61 +#: templates/InvenTree/settings/part.html:65 msgid "No part parameter templates found" -msgstr "" +msgstr "Parça parametre şablonu bulunamadı" #: templates/InvenTree/settings/po.html:9 msgid "Purchase Order Settings" @@ -6341,47 +6457,51 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 +#: templates/about.html:100 templates/js/modals.js:568 +#: templates/js/modals.js:861 templates/modals.html:29 templates/modals.html:54 #: templates/modals.html:97 msgid "Close" msgstr "" @@ -6442,7 +6562,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:921 msgid "Invalid server response" msgstr "" @@ -6472,7 +6592,7 @@ msgstr "" #: templates/js/barcode.js:418 msgid "Check Stock Items into Location" -msgstr "" +msgstr "Stok Kalemlerini bu konuma kaydet" #: templates/js/barcode.js:422 templates/js/barcode.js:547 msgid "Check In" @@ -6488,7 +6608,7 @@ msgstr "" #: templates/js/barcode.js:485 msgid "Stock Item already in this location" -msgstr "" +msgstr "Stok kalemi zaten bu konumda" #: templates/js/barcode.js:492 msgid "Added stock item" @@ -6500,13 +6620,13 @@ msgstr "" #: templates/js/barcode.js:542 msgid "Check Into Location" -msgstr "" +msgstr "Konuma Kaydet" #: templates/js/barcode.js:605 msgid "Barcode does not match a valid location" -msgstr "" +msgstr "Barkod geçerli bir konumla eşleşmiyor" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1091 msgid "Open subassembly" msgstr "" @@ -6542,7 +6662,7 @@ msgstr "" msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:470 templates/js/build.js:423 templates/js/build.js:1189 msgid "No BOM items found" msgstr "" @@ -6562,37 +6682,45 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:382 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:325 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:644 msgid "Required Part" -msgstr "" +msgstr "Gerekli Parça" -#: templates/js/build.js:580 +#: templates/js/build.js:665 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:735 templates/js/build.js:1153 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:788 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:805 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:966 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:825 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:924 msgid "No parts allocated for" msgstr "" @@ -6612,27 +6740,39 @@ msgstr "" msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:148 templates/js/company.js:347 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" -msgstr "" +msgstr "Şablon Parça" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:152 templates/js/company.js:351 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:226 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:262 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:263 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:328 msgid "No supplier parts found" msgstr "" #: templates/js/filters.js:167 templates/js/filters.js:397 msgid "true" -msgstr "" +msgstr "doğru" #: templates/js/filters.js:171 templates/js/filters.js:398 msgid "false" -msgstr "" +msgstr "yanlış" #: templates/js/filters.js:193 msgid "Select filter" @@ -6656,27 +6796,27 @@ msgstr "" #: templates/js/label.js:11 msgid "Stock item(s) must be selected before printing labels" -msgstr "" +msgstr "Etiket yazdırılmadan önce stok kalemleri seçilmeli" #: templates/js/label.js:29 templates/js/label.js:79 msgid "No Labels Found" -msgstr "" +msgstr "Etiket Bulunamadı" #: templates/js/label.js:30 msgid "No labels found which match selected stock item(s)" -msgstr "" +msgstr "Seçili stok kalemleri için etiket bulunamadı" #: templates/js/label.js:61 msgid "Select Stock Locations" -msgstr "" +msgstr "Stok Konumu Seç" #: templates/js/label.js:62 msgid "Stock location(s) must be selected before printing labels" -msgstr "" +msgstr "Etiket yazdırılmadan önce stok konumları seçilmeli" #: templates/js/label.js:80 msgid "No labels found which match selected stock location(s)" -msgstr "" +msgstr "Seçili konumlarla eşleşen etiket bulunamadı" #: templates/js/label.js:154 msgid "stock items selected" @@ -6684,11 +6824,11 @@ msgstr "" #: templates/js/label.js:162 msgid "Select Label" -msgstr "" +msgstr "Etiket Seç" #: templates/js/label.js:177 msgid "Select Label Template" -msgstr "" +msgstr "Etiket Şablonu Seç" #: templates/js/modals.js:265 msgid "Waiting for server..." @@ -6710,76 +6850,76 @@ msgstr "" msgid "Loading Data" msgstr "" -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:567 templates/js/modals.js:860 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:824 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:921 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 +#: templates/js/modals.js:931 msgid "No Response" msgstr "" -#: templates/js/modals.js:912 +#: templates/js/modals.js:932 msgid "No response from the InvenTree server" msgstr "" -#: templates/js/modals.js:916 +#: templates/js/modals.js:936 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:937 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 +#: templates/js/modals.js:941 msgid "Error 401: Not Authenticated" msgstr "" -#: templates/js/modals.js:922 +#: templates/js/modals.js:942 msgid "Authentication credentials not supplied" msgstr "" -#: templates/js/modals.js:926 +#: templates/js/modals.js:946 msgid "Error 403: Permission Denied" msgstr "" -#: templates/js/modals.js:927 +#: templates/js/modals.js:947 msgid "You do not have the required permissions to access this function" -msgstr "" +msgstr "Bu fonksiyona erişmek için gerekli izinlere sahip değilsiniz" -#: templates/js/modals.js:931 +#: templates/js/modals.js:951 msgid "Error 404: Resource Not Found" msgstr "" -#: templates/js/modals.js:932 +#: templates/js/modals.js:952 msgid "The requested resource could not be located on the server" msgstr "" -#: templates/js/modals.js:936 +#: templates/js/modals.js:956 msgid "Error 408: Timeout" msgstr "" -#: templates/js/modals.js:937 +#: templates/js/modals.js:957 msgid "Connection timeout while requesting data from server" msgstr "" -#: templates/js/modals.js:940 +#: templates/js/modals.js:960 msgid "Error requesting form data" msgstr "" @@ -6795,6 +6935,10 @@ msgstr "" msgid "No sales orders found" msgstr "" +#: templates/js/order.js:343 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6821,41 +6965,41 @@ msgstr "" #: templates/js/part.js:194 msgid "No variants found" -msgstr "" +msgstr "Çeşit bulunamadı" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:323 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:990 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" -msgstr "" +msgstr "Sorgu ile eşleşen test şablonu bulunamadı" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:806 msgid "Single Price Difference" msgstr "" @@ -6865,11 +7009,11 @@ msgstr "" #: templates/js/report.js:55 msgid "Select Report Template" -msgstr "" +msgstr "Rapor Şablonu Seç" #: templates/js/report.js:70 msgid "Select Test Report Template" -msgstr "" +msgstr "Test Raporu Şablonu Seç" #: templates/js/report.js:99 msgid "Stock item(s) must be selected before printing reports" @@ -6883,7 +7027,7 @@ msgstr "" #: templates/js/report.js:117 msgid "No report templates found which match selected stock item(s)" -msgstr "" +msgstr "Seçili stok kalemleri için rapor şablonu bulunamadı" #: templates/js/report.js:152 msgid "Select Builds" @@ -6895,7 +7039,7 @@ msgstr "" #: templates/js/report.js:170 msgid "No report templates found which match selected build(s)" -msgstr "" +msgstr "Seçili yapım işleri için rapor şablonu bulunamadı" #: templates/js/report.js:205 msgid "Select Parts" @@ -6907,7 +7051,7 @@ msgstr "" #: templates/js/report.js:224 msgid "No report templates found which match selected part(s)" -msgstr "" +msgstr "Seçili parçalar için rapor şablonu bulunamadı" #: templates/js/report.js:259 msgid "Select Purchase Orders" @@ -6919,7 +7063,7 @@ msgstr "" #: templates/js/report.js:278 templates/js/report.js:332 msgid "No report templates found which match selected orders" -msgstr "" +msgstr "Seçili emirler için rapor şablonu bulunamadı" #: templates/js/report.js:313 msgid "Select Sales Orders" @@ -6953,155 +7097,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" -msgstr "" +msgstr "konumlar" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" -msgstr "" +msgstr "Tanımsız konum" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:853 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:868 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:882 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:883 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1022 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1069 msgid "Location no longer exists" -msgstr "" +msgstr "Konum artık yok" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1088 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1107 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1125 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1148 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1156 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1188 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1200 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1201 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1325 msgid "Create New Location" -msgstr "" +msgstr "Yeni Konum Oluştur" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1366 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1389 msgid "Serial" -msgstr "" +msgstr "Seri No" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1417 msgid "Uninstall Stock Item" msgstr "" @@ -7115,11 +7259,11 @@ msgstr "" #: templates/js/table_filters.js:55 msgid "Allow Variant Stock" -msgstr "" +msgstr "Çeşit Stokuna İzin Ver" #: templates/js/table_filters.js:76 msgid "Include locations" -msgstr "" +msgstr "Konumları dahil et" #: templates/js/table_filters.js:86 templates/js/table_filters.js:87 #: templates/js/table_filters.js:300 @@ -7128,28 +7272,28 @@ msgstr "" #: templates/js/table_filters.js:97 templates/js/table_filters.js:186 msgid "Is Serialized" -msgstr "" +msgstr "Seri Numaralı" #: templates/js/table_filters.js:100 templates/js/table_filters.js:193 msgid "Serial number GTE" -msgstr "" +msgstr "Seri numarası BvE" #: templates/js/table_filters.js:101 templates/js/table_filters.js:194 msgid "Serial number greater than or equal to" -msgstr "" +msgstr "Seri numarası büyük veya eşit" #: templates/js/table_filters.js:104 templates/js/table_filters.js:197 msgid "Serial number LTE" -msgstr "" +msgstr "Seri numarası KvE" #: templates/js/table_filters.js:105 templates/js/table_filters.js:198 msgid "Serial number less than or equal to" -msgstr "" +msgstr "Seri numarası küçük veya eşit" #: templates/js/table_filters.js:108 templates/js/table_filters.js:109 #: templates/js/table_filters.js:189 templates/js/table_filters.js:190 msgid "Serial number" -msgstr "" +msgstr "Seri numarası" #: templates/js/table_filters.js:113 templates/js/table_filters.js:207 msgid "Batch code" @@ -7177,7 +7321,7 @@ msgstr "" #: templates/js/table_filters.js:139 msgid "Include stock in sublocations" -msgstr "" +msgstr "Alt konumlardaki stoku dahil et" #: templates/js/table_filters.js:144 msgid "Show stock items which are depleted" @@ -7205,11 +7349,11 @@ msgstr "" #: templates/js/table_filters.js:171 msgid "Include Variants" -msgstr "" +msgstr "Çeşitleri Dahil Et" #: templates/js/table_filters.js:172 msgid "Include stock items for variant parts" -msgstr "" +msgstr "Çeşit parçaların stok kalemlerini dahil et" #: templates/js/table_filters.js:176 msgid "Installed" @@ -7241,11 +7385,11 @@ msgstr "" #: templates/js/table_filters.js:301 msgid "Include parts in subcategories" -msgstr "" +msgstr "Alt kategorilerdeki parçaları dahil et" #: templates/js/table_filters.js:305 msgid "Has IPN" -msgstr "" +msgstr "DPN Var" #: templates/js/table_filters.js:306 msgid "Part has internal part number" @@ -7267,56 +7411,56 @@ msgstr "" msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" @@ -7482,7 +7626,7 @@ msgstr "" #: templates/stock_table.html:27 msgid "Barcode Actions" -msgstr "" +msgstr "Barkod İşlemleri" #: templates/stock_table.html:43 msgid "Print test reports" @@ -7560,35 +7704,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:174 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:182 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:187 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:191 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/zh/LC_MESSAGES/django.po b/InvenTree/locale/zh/LC_MESSAGES/django.po index 9892439445..34dbe857dc 100644 --- a/InvenTree/locale/zh/LC_MESSAGES/django.po +++ b/InvenTree/locale/zh/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:41\n" +"POT-Creation-Date: 2021-06-24 21:38+0000\n" +"PO-Revision-Date: 2021-06-24 21:40\n" "Last-Translator: \n" "Language-Team: Chinese Simplified\n" "Language: zh_CN\n" @@ -77,7 +77,7 @@ msgstr "选择分类" msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 +#: InvenTree/helpers.py:384 order/models.py:248 order/models.py:358 #: stock/views.py:1795 msgid "Invalid quantity provided" msgstr "" @@ -122,9 +122,9 @@ msgstr "注释" msgid "File comment" msgstr "文件注释" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:2022 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1179 msgid "User" msgstr "用户" @@ -132,34 +132,35 @@ msgstr "用户" msgid "upload date" msgstr "上传日期" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:107 InvenTree/models.py:108 company/models.py:396 +#: label/models.py:102 part/models.py:671 part/models.py:2163 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:235 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:972 msgid "Name" msgstr "名称" #: InvenTree/models.py:114 build/models.py:135 #: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: company/models.py:532 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 #: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: order/models.py:104 order/templates/order/purchase_order_detail.html:147 +#: part/models.py:695 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 +#: templates/js/build.js:833 templates/js/build.js:1101 #: templates/js/company.js:56 templates/js/order.js:183 #: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:984 +#: templates/js/stock.js:1029 msgid "Description" msgstr "" @@ -191,15 +192,15 @@ msgstr "" msgid "Turkish" msgstr "" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "" @@ -372,27 +373,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "" @@ -445,11 +446,11 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 order/forms.py:114 order/forms.py:149 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 +#: templates/js/build.js:880 templates/js/order.js:200 #: templates/js/order.js:298 msgid "Target Date" msgstr "" @@ -462,22 +463,21 @@ msgstr "" #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 +#: build/templates/build/detail.html:31 common/models.py:720 +#: company/forms.py:191 company/templates/company/supplier_part_pricing.html:77 +#: order/forms.py:193 order/forms.py:211 order/forms.py:246 order/forms.py:268 +#: order/forms.py:285 order/models.py:617 order/models.py:841 #: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/order_wizard/select_parts.html:34 #: order/templates/order/purchase_order_detail.html:179 #: order/templates/order/sales_order_detail.html:70 #: order/templates/order/sales_order_detail.html:77 #: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 +#: order/templates/order/sales_order_detail.html:234 part/forms.py:342 +#: part/forms.py:372 part/forms.py:388 part/forms.py:404 part/models.py:2293 +#: part/templates/part/internal_prices.html:98 +#: part/templates/part/order_prices.html:202 +#: part/templates/part/part_pricing.html:16 #: part/templates/part/sale_prices.html:85 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 @@ -486,9 +486,10 @@ msgstr "" #: stock/forms.py:175 stock/forms.py:308 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:571 +#: templates/js/build.js:1111 templates/js/order.js:393 +#: templates/js/part.js:796 templates/js/stock.js:1164 +#: templates/js/stock.js:1383 msgid "Quantity" msgstr "" @@ -500,7 +501,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:240 stock/forms.py:118 msgid "Serial Numbers" msgstr "" @@ -529,12 +530,12 @@ msgid "Mark build as complete" msgstr "" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:347 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:585 templates/js/order.js:378 +#: templates/js/stock.js:643 templates/js/stock.js:1056 msgid "Location" msgstr "" @@ -543,13 +544,13 @@ msgid "Location of completed parts" msgstr "" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:469 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:867 #: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: templates/js/stock.js:630 templates/js/stock.js:1133 +#: templates/js/stock.js:1399 msgid "Status" msgstr "" @@ -583,16 +584,16 @@ msgstr "" #: build/models.py:66 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "" #: build/models.py:67 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:57 +#: part/templates/part/navbar.html:60 templates/InvenTree/index.html:183 #: templates/InvenTree/search.html:185 #: templates/InvenTree/settings/tabs.html:34 users/models.py:43 msgid "Build Orders" @@ -602,12 +603,12 @@ msgstr "" msgid "Build Order Reference" msgstr "" -#: build/models.py:128 order/models.py:101 order/models.py:618 +#: build/models.py:128 order/models.py:102 order/models.py:619 #: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: order/templates/order/sales_order_detail.html:229 part/models.py:2302 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:660 templates/js/build.js:1105 msgid "Reference" msgstr "" @@ -626,27 +627,27 @@ msgstr "" #: build/models.py:153 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 +#: build/templates/build/detail.html:26 company/models.py:663 +#: order/models.py:661 order/models.py:717 +#: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:132 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:214 part/models.py:321 +#: part/models.py:1975 part/models.py:1987 part/models.py:2002 +#: part/models.py:2020 part/models.py:2095 part/models.py:2191 +#: part/models.py:2277 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:551 templates/js/build.js:838 +#: templates/js/build.js:1078 templates/js/company.js:140 +#: templates/js/company.js:339 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1371 msgid "Part" msgstr "" @@ -710,16 +711,16 @@ msgstr "" msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 +#: build/models.py:220 order/models.py:108 part/models.py:867 #: part/templates/part/detail.html:126 templates/js/order.js:293 msgid "Creation Date" msgstr "" -#: build/models.py:224 order/models.py:474 +#: build/models.py:224 order/models.py:475 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:228 order/models.py:221 templates/js/build.js:885 msgid "Completion Date" msgstr "" @@ -736,9 +737,9 @@ msgid "User who issued this build order" msgstr "" #: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/templates/build/detail.html:105 order/models.py:122 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:871 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "" @@ -757,26 +758,26 @@ msgstr "" msgid "External Link" msgstr "" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:258 part/models.py:729 stock/models.py:462 msgid "Link to external URL" msgstr "" #: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: company/models.py:132 company/models.py:539 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:126 +#: order/models.py:621 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:243 +#: order/templates/order/sales_order_detail.html:309 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:856 +#: part/templates/part/navbar.html:142 #: report/templates/report/inventree_build_order_base.html:173 #: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 #: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:699 msgid "Notes" msgstr "" @@ -809,11 +810,11 @@ msgstr "" msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1188 order/models.py:815 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1192 order/models.py:818 msgid "Allocation quantity must be greater than zero" msgstr "" @@ -827,7 +828,7 @@ msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" #: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: templates/InvenTree/search.html:183 templates/js/build.js:811 #: templates/navbar.html:29 msgid "Build" msgstr "" @@ -836,15 +837,13 @@ msgstr "" msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1333 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:928 +#: templates/js/order.js:366 templates/js/order.js:371 +#: templates/js/stock.js:1115 msgid "Stock Item" msgstr "" @@ -880,7 +879,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:743 msgid "Unallocate stock" msgstr "" @@ -917,15 +916,15 @@ msgstr "" #: order/templates/order/sales_order_detail.html:160 #: report/templates/report/inventree_test_report_base.html:75 #: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: templates/js/build.js:569 msgid "Serial Number" msgstr "" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:133 +#: part/templates/part/navbar.html:136 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "" @@ -1037,11 +1036,10 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:715 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 #: stock/templates/stock/item_base.html:279 templates/js/order.js:245 @@ -1185,7 +1183,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:85 order/models.py:678 +#: order/templates/order/purchase_order_detail.html:239 +#: order/templates/order/receive_parts.html:25 stock/forms.py:169 +#: stock/forms.py:375 msgid "Destination" msgstr "" @@ -1194,15 +1195,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1406 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:875 msgid "Created" msgstr "" @@ -1210,7 +1211,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:853 msgid "Completed" msgstr "" @@ -1248,9 +1249,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:17 +#: templates/js/stock.js:1044 msgid "Details" msgstr "" @@ -1285,8 +1286,8 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 +#: stock/templates/stock/item_base.html:497 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "" @@ -1411,8 +1412,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:670 +#: templates/js/build.js:935 templates/js/build.js:1118 msgid "Available" msgstr "" @@ -1598,8 +1599,8 @@ msgstr "" msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 +#: common/models.py:153 part/models.py:2193 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:259 templates/js/table_filters.js:25 #: templates/js/table_filters.js:315 msgid "Template" msgstr "" @@ -1608,7 +1609,7 @@ msgstr "" msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 +#: common/models.py:160 part/models.py:819 part/templates/part/detail.html:170 #: templates/js/table_filters.js:128 templates/js/table_filters.js:327 msgid "Assembly" msgstr "" @@ -1617,7 +1618,7 @@ msgstr "" msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 +#: common/models.py:167 part/models.py:825 part/templates/part/detail.html:180 #: templates/js/table_filters.js:331 msgid "Component" msgstr "" @@ -1626,7 +1627,7 @@ msgstr "" msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:174 part/models.py:836 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" @@ -1634,7 +1635,7 @@ msgstr "" msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 +#: common/models.py:181 part/models.py:841 part/templates/part/detail.html:210 #: templates/js/table_filters.js:339 msgid "Salable" msgstr "" @@ -1643,7 +1644,7 @@ msgstr "" msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 +#: common/models.py:188 part/models.py:831 part/templates/part/detail.html:190 #: templates/js/table_filters.js:33 templates/js/table_filters.js:343 msgid "Trackable" msgstr "" @@ -1652,7 +1653,7 @@ msgstr "" msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:195 part/models.py:851 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" @@ -1669,160 +1670,185 @@ msgstr "" msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" +#: common/models.py:209 +msgid "Show Price in Forms" msgstr "" #: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" +msgid "Display part price in some forms" msgstr "" #: common/models.py:216 -msgid "Page Size" +msgid "Internal Prices" msgstr "" #: common/models.py:217 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:223 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:224 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:230 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:231 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:237 +msgid "Page Size" +msgstr "" + +#: common/models.py:238 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:248 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:249 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:255 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:256 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:262 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:263 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:269 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:270 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:272 part/templates/part/detail.html:121 msgid "days" msgstr "" -#: common/models.py:256 +#: common/models.py:277 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:278 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:284 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:285 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:291 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:292 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:298 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:299 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:305 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:306 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:311 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:312 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:316 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:317 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:322 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:323 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:546 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:548 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:583 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:606 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:617 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:640 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:721 company/forms.py:192 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 +#: common/models.py:729 company/templates/company/supplier_part_pricing.html:82 +#: part/templates/part/internal_prices.html:103 #: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:730 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:822 msgid "Default" msgstr "" @@ -1843,7 +1869,9 @@ msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:582 +#: part/templates/part/bom_upload/upload_file.html:27 msgid "Upload File" msgstr "" @@ -1877,29 +1905,29 @@ msgstr "" msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:133 templates/js/part.js:787 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:135 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:143 company/models.py:321 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:149 company/models.py:328 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:151 company/models.py:327 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 #: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:408 msgid "MPN" msgstr "" @@ -1952,11 +1980,11 @@ msgstr "" msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:121 company/models.py:333 company/models.py:526 +#: order/models.py:106 part/models.py:728 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:188 templates/js/company.js:419 +#: templates/js/part.js:498 msgid "Link" msgstr "" @@ -1964,7 +1992,7 @@ msgstr "" msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:129 part/models.py:738 msgid "Image" msgstr "" @@ -1992,12 +2020,12 @@ msgstr "" msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:305 company/models.py:497 stock/models.py:407 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:309 company/models.py:501 order/views.py:1597 msgid "Select part" msgstr "" @@ -2008,7 +2036,7 @@ msgstr "" #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 #: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:390 msgid "Manufacturer" msgstr "" @@ -2020,87 +2048,112 @@ msgstr "" msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:390 company/models.py:520 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:397 +msgid "Parameter name" +msgstr "" + +#: company/models.py:403 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:241 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:404 +msgid "Parameter value" +msgstr "" + +#: company/models.py:410 part/models.py:813 part/models.py:2165 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:247 +msgid "Units" +msgstr "" + +#: company/models.py:411 +msgid "Parameter units" +msgstr "" + +#: company/models.py:507 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:193 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:48 templates/js/company.js:364 #: templates/js/order.js:170 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:508 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:513 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 #: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:514 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:521 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:527 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:533 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:538 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2305 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:542 part/models.py:1606 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 +#: company/models.py:544 company/templates/company/supplier_part_base.html:109 #: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: templates/js/stock.js:695 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:544 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:546 part/models.py:1608 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:546 msgid "Order multiple" msgstr "" #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:562 msgid "Assigned Stock" msgstr "" @@ -2165,11 +2218,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 +#: company/templates/company/detail.html:67 order/models.py:464 #: order/templates/order/sales_order_base.html:94 stock/models.py:449 #: stock/models.py:450 stock/templates/stock/item_base.html:262 #: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: templates/js/stock.js:1097 msgid "Customer" msgstr "" @@ -2215,7 +2268,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:66 #: company/templates/company/detail_supplier_part.html:66 #: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: templates/js/stock.js:1312 msgid "New Part" msgstr "" @@ -2248,13 +2301,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 +#: order/templates/order/order_wizard/select_parts.html:44 #: order/templates/order/purchase_order_detail.html:50 msgid "Create new supplier part" msgstr "" @@ -2262,12 +2314,12 @@ msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 #: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/supplier.html:17 templates/js/stock.js:1318 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 +#: company/templates/company/manufacturer_part_suppliers.html:82 #: company/views.py:64 order/templates/order/purchase_orders.html:185 #: part/templates/part/supplier.html:50 msgid "New Supplier" @@ -2319,8 +2371,9 @@ msgid "There are %(count)s suppliers defined for this manufacturer part. If you msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:63 part/templates/part/navbar.html:86 +#: part/templates/part/navbar.html:89 templates/InvenTree/search.html:316 #: templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,13 +2385,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:38 stock/api.py:54 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2360,11 +2413,25 @@ msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:1002 users/models.py:191 msgid "Delete" msgstr "" -#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:34 +#: part/templates/part/category_navbar.html:37 +#: part/templates/part/navbar.html:24 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:48 +msgid "New Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:83 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" @@ -2379,13 +2446,13 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:35 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 +#: templates/InvenTree/search.html:198 templates/js/stock.js:996 #: templates/stats.html:93 templates/stats.html:102 users/models.py:42 msgid "Stock Items" msgstr "" @@ -2396,7 +2463,7 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 +#: part/templates/part/navbar.html:112 part/templates/part/navbar.html:115 #: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 @@ -2408,7 +2475,7 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 +#: part/templates/part/navbar.html:92 part/templates/part/navbar.html:95 #: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 @@ -2442,7 +2509,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:7 #: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:380 msgid "Supplier Part" msgstr "" @@ -2490,8 +2557,8 @@ msgstr "" msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 company/views.py:855 +#: part/templates/part/sale_prices.html:17 part/views.py:2751 msgid "Add Price Break" msgstr "" @@ -2510,8 +2577,8 @@ msgstr "" msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 +#: company/views.py:70 part/templates/part/navbar.html:80 +#: part/templates/part/navbar.html:83 templates/InvenTree/search.html:306 #: templates/navbar.html:36 msgid "Manufacturers" msgstr "" @@ -2533,20 +2600,20 @@ msgstr "" msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:169 part/views.py:948 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:198 part/views.py:980 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:205 part/views.py:987 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:214 part/views.py:996 msgid "Supplied URL is not a valid image file" msgstr "" @@ -2594,27 +2661,35 @@ msgstr "" msgid "Delete Manufacturer Part" msgstr "" -#: company/views.py:528 +#: company/views.py:514 +msgid "Add Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:548 +msgid "Edit Manufacturer Part Parameter" +msgstr "" + +#: company/views.py:588 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:639 templates/js/stock.js:1319 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:783 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 +#: company/views.py:860 part/views.py:2755 msgid "Added new price break" msgstr "" -#: company/views.py:855 part/views.py:2781 +#: company/views.py:916 part/views.py:2799 msgid "Edit Price Break" msgstr "" -#: company/views.py:870 part/views.py:2795 +#: company/views.py:931 part/views.py:2813 msgid "Delete Price Break" msgstr "" @@ -2638,7 +2713,7 @@ msgstr "" msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:124 report/models.py:297 msgid "Enabled" msgstr "" @@ -2662,7 +2737,7 @@ msgstr "" msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:144 report/models.py:290 msgid "Filename Pattern" msgstr "" @@ -2674,8 +2749,8 @@ msgstr "" msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:245 label/models.py:298 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" @@ -2696,237 +2771,239 @@ msgstr "" msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:86 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 +#: order/forms.py:108 msgid "Purchase Order reference" msgstr "" -#: order/forms.py:110 +#: order/forms.py:115 msgid "Target date for order delivery. Order will be overdue after this date." msgstr "" -#: order/forms.py:138 +#: order/forms.py:143 msgid "Enter sales order number" msgstr "" -#: order/forms.py:145 order/models.py:475 +#: order/forms.py:150 order/models.py:476 msgid "Target date for order completion. Order will be overdue after this date." msgstr "" -#: order/forms.py:236 +#: order/forms.py:242 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:248 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 +#: order/models.py:102 msgid "Order reference" msgstr "" -#: order/models.py:103 +#: order/models.py:104 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:106 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:114 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:121 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:126 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:185 order/models.py:469 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:194 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 +#: order/models.py:197 order/templates/order/order_base.html:98 #: templates/js/order.js:179 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:197 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:204 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:209 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:210 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:215 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:216 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:222 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 +#: order/models.py:246 part/views.py:1686 stock/models.py:304 #: stock/models.py:1020 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:251 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:349 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:353 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:355 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:465 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:471 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:479 templates/js/order.js:303 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:486 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:530 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:617 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:619 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:621 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:647 order/models.py:715 templates/js/order.js:353 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:648 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 #: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: templates/js/stock.js:669 templates/js/stock.js:1078 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:662 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 +#: order/models.py:665 order/templates/order/order_base.html:131 #: order/templates/order/purchase_order_detail.html:219 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:665 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:672 stock/models.py:542 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:690 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:673 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:681 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:724 part/templates/part/navbar.html:109 +#: part/templates/part/order_prices.html:107 +#: part/templates/part/part_pricing.html:97 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:725 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:800 order/models.py:802 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:806 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:808 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:811 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:821 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:826 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:837 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:838 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:841 msgid "Enter stock allocation quantity" msgstr "" @@ -2955,7 +3032,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2977,8 +3054,8 @@ msgstr "" #: order/templates/order/order_base.html:180 #: order/templates/order/purchase_order_detail.html:100 #: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: stock/templates/stock/location.html:191 templates/js/stock.js:736 +#: templates/js/stock.js:1324 msgid "New Location" msgstr "" @@ -3081,28 +3158,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3135,15 +3216,20 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +#: order/templates/order/so_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,8 +3239,8 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/sales_order_detail.html:22 order/views.py:1321 +#: order/views.py:1404 msgid "Add Line Item" msgstr "" @@ -3162,25 +3248,31 @@ msgstr "" msgid "No line items found" msgstr "" +#: order/templates/order/purchase_order_detail.html:142 +#: order/templates/order/sales_order_detail.html:223 +msgid "Total" +msgstr "" + #: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/sales_order_detail.html:246 msgid "Unit Price" msgstr "" #: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/sales_order_detail.html:253 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:255 +#: order/templates/order/sales_order_detail.html:359 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:256 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:261 msgid "Receive line item" msgstr "" @@ -3201,7 +3293,7 @@ msgstr "" #: part/templates/part/category_navbar.html:29 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 #: users/models.py:40 msgid "Parts" @@ -3216,7 +3308,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3316,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3265,17 +3357,17 @@ msgid "Sales Order Items" msgstr "" #: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: templates/js/build.js:724 templates/js/build.js:1141 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:610 +#: templates/js/build.js:946 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:612 +#: templates/js/build.js:947 msgid "Delete stock allocation" msgstr "" @@ -3283,50 +3375,50 @@ msgstr "" msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:206 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:274 templates/js/build.js:675 +#: templates/js/build.js:942 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:276 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:313 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:343 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:346 templates/js/build.js:738 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:349 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:353 templates/js/build.js:731 +#: templates/js/build.js:1149 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:356 +#: order/templates/order/sales_order_detail.html:465 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:360 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:471 msgid "Update Unit Price" msgstr "" @@ -3367,10 +3459,6 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - #: order/views.py:104 msgid "Add Purchase Order Attachment" msgstr "" @@ -3471,90 +3559,94 @@ msgstr "" msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:1012 +msgid "Update prices" +msgstr "" + +#: order/views.py:1270 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 +#: order/views.py:1330 msgid "Supplier part must be specified" msgstr "" -#: order/views.py:1326 +#: order/views.py:1336 msgid "Supplier must match for Part and Order" msgstr "" -#: order/views.py:1457 order/views.py:1475 +#: order/views.py:1467 order/views.py:1485 msgid "Edit Line Item" msgstr "" -#: order/views.py:1491 order/views.py:1503 +#: order/views.py:1501 order/views.py:1513 msgid "Delete Line Item" msgstr "" -#: order/views.py:1496 order/views.py:1508 +#: order/views.py:1506 order/views.py:1518 msgid "Deleted line item" msgstr "" -#: order/views.py:1521 +#: order/views.py:1531 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1576 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1592 msgid "Select line item" msgstr "" -#: order/views.py:1613 -#, python-brace-format -msgid "No matching item for serial {serial}" -msgstr "" - #: order/views.py:1623 #, python-brace-format +msgid "No matching item for serial {serial}" +msgstr "" + +#: order/views.py:1633 +#, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1641 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1695 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1769 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1784 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1856 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1862 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1865 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1870 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 +#: part/bom.py:138 part/models.py:72 part/models.py:747 #: part/templates/part/category.html:66 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3632,7 +3724,7 @@ msgstr "" msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:122 part/models.py:2191 msgid "Parent Part" msgstr "" @@ -3708,7 +3800,7 @@ msgstr "" msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:344 part/models.py:2286 msgid "Sub part" msgstr "" @@ -3728,7 +3820,7 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:82 part/models.py:2237 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" @@ -3739,365 +3831,360 @@ msgstr "" msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:448 part/models.py:460 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:557 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:561 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:566 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:645 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:670 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:677 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:678 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:689 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:690 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:696 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:701 part/templates/part/category.html:73 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:702 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:709 part/models.py:2236 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:710 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:715 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "" -#: part/models.py:731 +#: part/models.py:716 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:722 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:723 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:745 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:792 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:793 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:800 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:801 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:806 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:807 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:814 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:820 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:826 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:832 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:837 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:842 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:846 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 #: templates/js/table_filters.js:241 templates/js/table_filters.js:310 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:847 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:852 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:857 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:860 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:863 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:865 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:869 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1608 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2063 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2080 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2100 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2101 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2106 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2107 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 +#: part/models.py:2112 templates/js/part.js:726 #: templates/js/table_filters.js:227 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2113 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2118 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2119 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2124 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2125 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2158 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2163 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2165 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2193 part/models.py:2242 part/models.py:2243 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2195 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2247 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2248 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2278 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2287 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2293 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2295 templates/js/bom.js:216 templates/js/bom.js:285 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2295 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2298 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2299 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2302 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2305 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2307 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2311 templates/js/bom.js:302 templates/js/bom.js:309 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2312 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2317 templates/js/bom.js:294 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2318 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 +#: part/models.py:2394 part/views.py:1692 part/views.py:1744 #: stock/models.py:294 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2403 part/models.py:2405 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2408 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2527 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2531 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2563 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 @@ -4112,8 +4199,8 @@ msgstr "" msgid "Deleting this entry will remove the BOM row from the following part" msgstr "" -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:50 +#: part/templates/part/navbar.html:53 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4247,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:1987 msgid "Export Bill of Materials" msgstr "" @@ -4177,7 +4264,7 @@ msgid "All selected BOM items will be deleted" msgstr "" #: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: templates/js/stock.js:1313 msgid "Create New Part" msgstr "" @@ -4258,7 +4345,7 @@ msgstr "" msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:29 part/views.py:2397 msgid "Create new part category" msgstr "" @@ -4318,7 +4405,7 @@ msgid "View grid display" msgstr "" #: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: stock/templates/stock/location.html:192 templates/js/stock.js:737 msgid "Create new location" msgstr "" @@ -4373,14 +4460,8 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 -#: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" -msgstr "" - #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:21 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" @@ -4408,7 +4489,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:13 msgid "Part Details" msgstr "" @@ -4488,6 +4569,36 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/internal_prices.html:11 +#: part/templates/part/navbar.html:100 +msgid "Internal Price Information" +msgstr "" + +#: part/templates/part/internal_prices.html:19 part/views.py:2822 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/internal_prices.html:28 templates/403.html:5 +#: templates/403.html:11 +msgid "Permission Denied" +msgstr "" + +#: part/templates/part/internal_prices.html:31 templates/403.html:14 +msgid "You do not have permission to view this page." +msgstr "" + +#: part/templates/part/internal_prices.html:59 +msgid "No internal price break information found" +msgstr "" + +#: part/templates/part/internal_prices.html:110 +msgid "Edit internal price break" +msgstr "" + +#: part/templates/part/internal_prices.html:111 +msgid "Delete internal price break" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4501,127 +4612,141 @@ msgstr "" msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:28 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:31 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:42 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:45 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:66 part/templates/part/navbar.html:69 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 +#: part/templates/part/navbar.html:74 part/templates/part/order_prices.html:12 msgid "Order Price Information" msgstr "" -#: part/templates/part/navbar.html:75 +#: part/templates/part/navbar.html:77 msgid "Order Price" msgstr "" -#: part/templates/part/navbar.html:98 +#: part/templates/part/navbar.html:103 part/templates/part/order_prices.html:93 +#: part/templates/part/part_pricing.html:82 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/navbar.html:106 msgid "Sales Price Information" msgstr "" -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:120 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:123 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:127 part/templates/part/navbar.html:130 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:139 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 +#: part/templates/part/order_prices.html:24 +#: part/templates/part/part_base.html:282 +msgid "Calculate" +msgstr "" + +#: part/templates/part/order_prices.html:31 msgid "Pricing ranges" msgstr "" -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 +#: part/templates/part/order_prices.html:36 +#: part/templates/part/part_pricing.html:22 msgid "Supplier Pricing" msgstr "" -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 +#: part/templates/part/order_prices.html:37 +#: part/templates/part/order_prices.html:62 +#: part/templates/part/order_prices.html:94 +#: part/templates/part/order_prices.html:108 +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 msgid "Unit Cost" msgstr "" -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 +#: part/templates/part/order_prices.html:44 +#: part/templates/part/order_prices.html:69 +#: part/templates/part/order_prices.html:99 +#: part/templates/part/order_prices.html:113 +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 msgid "Total Cost" msgstr "" -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 +#: part/templates/part/order_prices.html:52 +#: part/templates/part/part_pricing.html:40 msgid "No supplier pricing available" msgstr "" -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 +#: part/templates/part/order_prices.html:61 +#: part/templates/part/order_prices.html:128 +#: part/templates/part/part_pricing.html:48 msgid "BOM Pricing" msgstr "" -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 +#: part/templates/part/order_prices.html:77 +#: part/templates/part/part_pricing.html:66 msgid "Note: BOM pricing is incomplete for this part" msgstr "" -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 +#: part/templates/part/order_prices.html:84 +#: part/templates/part/part_pricing.html:73 msgid "No BOM pricing available" msgstr "" -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 +#: part/templates/part/order_prices.html:122 +#: part/templates/part/part_pricing.html:113 msgid "No pricing information is available for this part." msgstr "" -#: part/templates/part/order_prices.html:113 +#: part/templates/part/order_prices.html:138 msgid "Stock Pricing" msgstr "" -#: part/templates/part/order_prices.html:121 +#: part/templates/part/order_prices.html:146 msgid "No stock pricing history is available for this part." msgstr "" -#: part/templates/part/order_prices.html:140 +#: part/templates/part/order_prices.html:165 #, python-format msgid "Single Price - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:152 +#: part/templates/part/order_prices.html:177 #, python-format msgid "Single Price Difference - %(currency)s" msgstr "" -#: part/templates/part/order_prices.html:163 +#: part/templates/part/order_prices.html:189 #, python-format msgid "Part Single Price - %(currency)s" msgstr "" @@ -4630,19 +4755,6 @@ msgstr "" msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4660,7 +4772,7 @@ msgid "Part List" msgstr "" #: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: templates/js/company.js:355 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4740,14 +4852,10 @@ msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 -msgid "Calculate" -msgstr "" - #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" @@ -4816,7 +4924,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,7 +4961,7 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" @@ -4922,227 +5030,239 @@ msgstr "" msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:925 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 +#: part/views.py:1027 msgid "Upload Part Image" msgstr "" -#: part/views.py:1022 part/views.py:1057 +#: part/views.py:1033 part/views.py:1068 msgid "Updated part image" msgstr "" -#: part/views.py:1031 +#: part/views.py:1042 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1071 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1082 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1117 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1147 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1168 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1189 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1200 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1334 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1695 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1720 part/views.py:1723 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1729 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1767 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1773 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1777 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2039 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2046 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2055 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2196 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2206 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2213 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2221 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2271 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2285 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 +#: part/views.py:2345 msgid "Edit Part Category" msgstr "" -#: part/views.py:2365 +#: part/views.py:2383 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2389 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2441 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2542 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2598 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2617 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2687 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 +#: part/views.py:2743 msgid "Confim BOM item deletion" msgstr "" -#: report/models.py:180 +#: part/views.py:2831 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2839 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5174,7 +5294,7 @@ msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:195 templates/js/stock.js:1012 msgid "Date" msgstr "" @@ -5197,7 +5317,7 @@ msgid "Moved {n} parts to {loc}" msgstr "" #: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" @@ -5483,12 +5603,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5738,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:593 msgid "No location set" msgstr "" @@ -5630,25 +5750,29 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" @@ -5945,7 +6069,7 @@ msgstr "" msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:1001 users/models.py:187 msgid "Add" msgstr "" @@ -6011,7 +6135,7 @@ msgstr "" msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1575 templates/js/build.js:326 msgid "Create new Stock Item" msgstr "" @@ -6043,14 +6167,6 @@ msgstr "" msgid "Add Stock Tracking Entry" msgstr "" -#: templates/403.html:5 templates/403.html:11 -msgid "Permission Denied" -msgstr "" - -#: templates/403.html:14 -msgid "You do not have permission to view this page." -msgstr "" - #: templates/404.html:5 templates/404.html:11 msgid "Page Not Found" msgstr "" @@ -6119,11 +6235,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6284,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:85 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:86 msgid "Delete Template" msgstr "" @@ -6221,11 +6337,11 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 +#: templates/InvenTree/settings/part.html:44 msgid "Part Parameter Templates" msgstr "" -#: templates/InvenTree/settings/part.html:61 +#: templates/InvenTree/settings/part.html:65 msgid "No part parameter templates found" msgstr "" @@ -6341,47 +6457,51 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 +#: templates/about.html:100 templates/js/modals.js:568 +#: templates/js/modals.js:861 templates/modals.html:29 templates/modals.html:54 #: templates/modals.html:97 msgid "Close" msgstr "" @@ -6442,7 +6562,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:921 msgid "Invalid server response" msgstr "" @@ -6506,7 +6626,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1091 msgid "Open subassembly" msgstr "" @@ -6542,7 +6662,7 @@ msgstr "" msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:470 templates/js/build.js:423 templates/js/build.js:1189 msgid "No BOM items found" msgstr "" @@ -6562,37 +6682,45 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:382 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:325 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:644 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:665 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:735 templates/js/build.js:1153 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:788 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:805 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:966 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:825 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:924 msgid "No parts allocated for" msgstr "" @@ -6612,17 +6740,29 @@ msgstr "" msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:148 templates/js/company.js:347 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:152 templates/js/company.js:351 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:226 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:262 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:263 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:328 msgid "No supplier parts found" msgstr "" @@ -6710,76 +6850,76 @@ msgstr "" msgid "Loading Data" msgstr "" -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:567 templates/js/modals.js:860 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:811 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:824 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:921 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 +#: templates/js/modals.js:931 msgid "No Response" msgstr "" -#: templates/js/modals.js:912 +#: templates/js/modals.js:932 msgid "No response from the InvenTree server" msgstr "" -#: templates/js/modals.js:916 +#: templates/js/modals.js:936 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:937 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 +#: templates/js/modals.js:941 msgid "Error 401: Not Authenticated" msgstr "" -#: templates/js/modals.js:922 +#: templates/js/modals.js:942 msgid "Authentication credentials not supplied" msgstr "" -#: templates/js/modals.js:926 +#: templates/js/modals.js:946 msgid "Error 403: Permission Denied" msgstr "" -#: templates/js/modals.js:927 +#: templates/js/modals.js:947 msgid "You do not have the required permissions to access this function" msgstr "" -#: templates/js/modals.js:931 +#: templates/js/modals.js:951 msgid "Error 404: Resource Not Found" msgstr "" -#: templates/js/modals.js:932 +#: templates/js/modals.js:952 msgid "The requested resource could not be located on the server" msgstr "" -#: templates/js/modals.js:936 +#: templates/js/modals.js:956 msgid "Error 408: Timeout" msgstr "" -#: templates/js/modals.js:937 +#: templates/js/modals.js:957 msgid "Connection timeout while requesting data from server" msgstr "" -#: templates/js/modals.js:940 +#: templates/js/modals.js:960 msgid "Error requesting form data" msgstr "" @@ -6795,6 +6935,10 @@ msgstr "" msgid "No sales orders found" msgstr "" +#: templates/js/order.js:343 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +6967,39 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:323 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:990 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:806 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7097,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:853 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:868 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:882 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:883 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1022 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1069 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1088 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1107 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1125 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1148 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1156 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1188 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1200 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1201 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1325 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1366 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1389 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1417 msgid "Uninstall Stock Item" msgstr "" @@ -7267,56 +7411,56 @@ msgstr "" msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" @@ -7560,35 +7704,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:174 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:182 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:185 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:187 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:189 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:191 msgid "Permission to delete items" msgstr "" From ba1c70e86b93b6695a990e9a5df2333bab3e9efc Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 26 Jun 2021 20:48:09 +1000 Subject: [PATCH 108/445] Intercept is_valid() method to set default values --- InvenTree/InvenTree/serializers.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index fa7674723c..5be6d44c0c 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -7,6 +7,7 @@ Serializers used in various InvenTree apps from __future__ import unicode_literals from rest_framework import serializers +from rest_framework.utils import model_meta import os @@ -39,6 +40,35 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): but also ensures that the underlying model class data are checked on validation. """ + def is_valid(self, raise_exception=False): + """ + Override the 'is_valid' method of the underlying ModelSerializer class. + + - This is so we can intercept the data before save() is called. + - If we are creating a *new* model, replace any "missing" fields with the default values + - Default values are those specified by the database model + """ + + # This serializer is *not* associated with a model instance + # This means that we are trying to *create* a new model + if self.instance is None: + ModelClass = self.Meta.model + + fields = model_meta.get_field_info(ModelClass) + + for field_name, field in fields.fields.items(): + + # Check if the field has a default value + if field.has_default(): + + # Value not specified? + if field_name not in self.initial_data: + + self.initial_data[field_name] = field.default + + + return super().is_valid(raise_exception=raise_exception) + def validate(self, data): """ Perform serializer validation. In addition to running validators on the serializer fields, From b2aa38fefa66922165071690058686cfef7bee93 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 26 Jun 2021 21:14:10 +1000 Subject: [PATCH 109/445] Override get_initial() rather than is_valid() --- InvenTree/InvenTree/serializers.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index f19ef23c00..82584bdbb0 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -45,17 +45,15 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): but also ensures that the underlying model class data are checked on validation. """ - def is_valid(self, raise_exception=False): + def get_initial(self): """ - Override the 'is_valid' method of the underlying ModelSerializer class. - - - This is so we can intercept the data before save() is called. - - If we are creating a *new* model, replace any "missing" fields with the default values - - Default values are those specified by the database model + Construct initial data for the serializer. + Use the 'default' values specified by the django model definition """ - # This serializer is *not* associated with a model instance - # This means that we are trying to *create* a new model + initials = super().get_initial() + + # Are we creating a new instance? if self.instance is None: ModelClass = self.Meta.model @@ -63,16 +61,10 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): for field_name, field in fields.fields.items(): - # Check if the field has a default value if field.has_default(): + initials[field_name] = field.default - # Value not specified? - if field_name not in self.initial_data: - - self.initial_data[field_name] = field.default - - - return super().is_valid(raise_exception=raise_exception) + return initials def run_validation(self, data=empty): """ Perform serializer validation. From a0390f08219b6690bf35eda117c69e8af557108b Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 26 Jun 2021 21:14:47 +1000 Subject: [PATCH 110/445] PEP style fixes --- InvenTree/InvenTree/serializers.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index 82584bdbb0..9e8e811b90 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -2,13 +2,9 @@ Serializers used in various InvenTree apps """ - # -*- coding: utf-8 -*- from __future__ import unicode_literals -from rest_framework import serializers -from rest_framework.utils import model_meta - import os from django.conf import settings @@ -16,6 +12,7 @@ from django.contrib.auth.models import User from django.core.exceptions import ValidationError as DjangoValidationError from rest_framework import serializers +from rest_framework.utils import model_meta from rest_framework.fields import empty from rest_framework.exceptions import ValidationError From ae1a1e139fa9137f2bb5fe11d42f2c3d4f2c4365 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 27 Jun 2021 00:01:40 +1000 Subject: [PATCH 111/445] Further fixes for default API values - Account for callable defaults - Extra check in is_valid() --- InvenTree/InvenTree/api_tester.py | 7 +++++- InvenTree/InvenTree/serializers.py | 39 +++++++++++++++++++++++++++++- InvenTree/part/test_api.py | 34 +++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/InvenTree/InvenTree/api_tester.py b/InvenTree/InvenTree/api_tester.py index a803e6797f..1cbc62ec0a 100644 --- a/InvenTree/InvenTree/api_tester.py +++ b/InvenTree/InvenTree/api_tester.py @@ -18,6 +18,7 @@ class InvenTreeAPITestCase(APITestCase): email = 'test@testing.com' superuser = False + is_staff = True auto_login = True # Set list of roles automatically associated with the user @@ -40,8 +41,12 @@ class InvenTreeAPITestCase(APITestCase): if self.superuser: self.user.is_superuser = True - self.user.save() + if self.is_staff: + self.user.is_staff = True + + self.user.save() + for role in self.roles: self.assignRole(role) diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index 9e8e811b90..c00c9ef690 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -59,10 +59,47 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): for field_name, field in fields.fields.items(): if field.has_default(): - initials[field_name] = field.default + + value = field.default + + # Account for callable functions + if callable(value): + value = value() + + initials[field_name] = value return initials + def is_valid(self, raise_exception=False): + """ + Also override the is_valid() method, as in some cases get_initial() is not actually called. + """ + + # Calling super().is_valid creates self._validated_data + valid = super().is_valid(raise_exception) + + # Are we creating a new instance? + if self.instance is None: + ModelClass = self.Meta.model + + fields = model_meta.get_field_info(ModelClass) + + for field_name, field in fields.fields.items(): + + if field.has_default(): + if field not in self._validated_data: + + value = field.default + + # Account for callable functions + if callable(value): + value = value() + + self._validated_data[field_name] = value + + + return valid + def run_validation(self, data=empty): """ Perform serializer validation. In addition to running validators on the serializer fields, diff --git a/InvenTree/part/test_api.py b/InvenTree/part/test_api.py index 787c5d3f85..29df621914 100644 --- a/InvenTree/part/test_api.py +++ b/InvenTree/part/test_api.py @@ -13,6 +13,7 @@ from InvenTree.status_codes import StockStatus from part.models import Part, PartCategory from stock.models import StockItem from company.models import Company +from common.models import InvenTreeSetting class PartAPITest(InvenTreeAPITestCase): @@ -332,7 +333,38 @@ class PartAPITest(InvenTreeAPITestCase): # Check that the un-specified fields have used correct default values self.assertTrue(data['active']) self.assertFalse(data['virtual']) - self.assertTrue(data['purchaseable']) + + # By default, parts are not purchaseable + self.assertFalse(data['purchaseable']) + + # Set the default 'purchaseable' status to True + InvenTreeSetting.set_setting( + 'PART_PURCHASEABLE', + True, + self.user + ) + + response = self.client.post(url, { + 'name': 'all defaults', + 'description': 'my test part 2', + 'category': 1, + }) + + # Part should now be purchaseable by default + self.assertTrue(response.data['purchaseable']) + + # "default" values should not be used if the value is specified + response = self.client.post(url, { + 'name': 'all defaults', + 'description': 'my test part 2', + 'category': 1, + 'active': False, + 'purchaseable': False, + }) + + self.assertFalse(response.data['active']) + self.assertFalse(response.data['purchaseable']) + class PartDetailTests(InvenTreeAPITestCase): From 8913b74f4183686e2074c16c05e15d5b5522917b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 27 Jun 2021 00:12:10 +1000 Subject: [PATCH 112/445] Typo fixes --- InvenTree/InvenTree/serializers.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index c00c9ef690..6b5bdaef22 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -58,7 +58,7 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): for field_name, field in fields.fields.items(): - if field.has_default(): + if field.has_default() and field_name not in initials: value = field.default @@ -87,7 +87,7 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): for field_name, field in fields.fields.items(): if field.has_default(): - if field not in self._validated_data: + if field_name not in self._validated_data.keys(): value = field.default @@ -97,7 +97,6 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): self._validated_data[field_name] = value - return valid def run_validation(self, data=empty): From 232899e0c43b1448cbcc9ca7b68b464fc9c08b13 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 27 Jun 2021 00:25:23 +1000 Subject: [PATCH 113/445] Simpler implementation --- InvenTree/InvenTree/serializers.py | 65 +++++++++++++++++------------- InvenTree/part/test_api.py | 1 - 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index 6b5bdaef22..9d695ab0de 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -7,6 +7,8 @@ from __future__ import unicode_literals import os +from collections import OrderedDict + from django.conf import settings from django.contrib.auth.models import User from django.core.exceptions import ValidationError as DjangoValidationError @@ -42,6 +44,38 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): but also ensures that the underlying model class data are checked on validation. """ + def __init__(self, instance=None, data=empty, **kwargs): + + self.instance = instance + + # If instance is None, we are creating a new instance + if instance is None: + + if data is empty: + data = OrderedDict() + else: + # Required to side-step immutability of a QueryDict + data = data.copy() + + # Add missing fields which have default values + ModelClass = self.Meta.model + + fields = model_meta.get_field_info(ModelClass) + + for field_name, field in fields.fields.items(): + + if field.has_default() and field_name not in data: + + value = field.default + + # Account for callable functions + if callable(value): + value = value() + + data[field_name] = value + + super().__init__(instance, data, **kwargs) + def get_initial(self): """ Construct initial data for the serializer. @@ -50,6 +84,8 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): initials = super().get_initial() + print("initials:", initials) + # Are we creating a new instance? if self.instance is None: ModelClass = self.Meta.model @@ -70,35 +106,6 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): return initials - def is_valid(self, raise_exception=False): - """ - Also override the is_valid() method, as in some cases get_initial() is not actually called. - """ - - # Calling super().is_valid creates self._validated_data - valid = super().is_valid(raise_exception) - - # Are we creating a new instance? - if self.instance is None: - ModelClass = self.Meta.model - - fields = model_meta.get_field_info(ModelClass) - - for field_name, field in fields.fields.items(): - - if field.has_default(): - if field_name not in self._validated_data.keys(): - - value = field.default - - # Account for callable functions - if callable(value): - value = value() - - self._validated_data[field_name] = value - - return valid - def run_validation(self, data=empty): """ Perform serializer validation. In addition to running validators on the serializer fields, diff --git a/InvenTree/part/test_api.py b/InvenTree/part/test_api.py index 29df621914..3fbf26f8bb 100644 --- a/InvenTree/part/test_api.py +++ b/InvenTree/part/test_api.py @@ -366,7 +366,6 @@ class PartAPITest(InvenTreeAPITestCase): self.assertFalse(response.data['purchaseable']) - class PartDetailTests(InvenTreeAPITestCase): """ Test that we can create / edit / delete Part objects via the API From d3e9803fd48626d30dbddbcc26d9dd0a6ce6eea7 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 27 Jun 2021 00:25:49 +1000 Subject: [PATCH 114/445] Remove debug statement --- InvenTree/InvenTree/serializers.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index 9d695ab0de..1f7b8c0290 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -84,8 +84,6 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): initials = super().get_initial() - print("initials:", initials) - # Are we creating a new instance? if self.instance is None: ModelClass = self.Meta.model From 7505d7b3c57bd92738be6c0f0eadb0087c48072c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 27 Jun 2021 00:47:12 +1000 Subject: [PATCH 115/445] Unit test fixes --- InvenTree/stock/test_api.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index e1fb616335..729bf25a9b 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -354,16 +354,18 @@ class StockItemTest(StockAPITestCase): self.assertContains(response, 'does not exist', status_code=status.HTTP_400_BAD_REQUEST) # POST without quantity - response = self.client.post( + response = self.post( self.list_url, - data={ + { 'part': 1, 'location': 1, - } + }, + expected_code=201, ) - self.assertContains(response, 'This field is required', status_code=status.HTTP_400_BAD_REQUEST) - + # Item should have been created with default quantity + self.assertEqual(response.data['quantity'], 1) + # POST with quantity and part and location response = self.client.post( self.list_url, From 0cc999410b443c1173b46bfb5282dedc79691e36 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 27 Jun 2021 01:03:54 +1000 Subject: [PATCH 116/445] More unit test fixes --- InvenTree/part/test_api.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/test_api.py b/InvenTree/part/test_api.py index 3fbf26f8bb..ee01df89cf 100644 --- a/InvenTree/part/test_api.py +++ b/InvenTree/part/test_api.py @@ -445,7 +445,14 @@ class PartDetailTests(InvenTreeAPITestCase): # Try to remove the part response = self.client.delete(url) - + + # As the part is 'active' we cannot delete it + self.assertEqual(response.status_code, 405) + + # So, let's make it not active + response = self.patch(url, {'active': False}, expected_code=200) + + response = self.client.delete(url) self.assertEqual(response.status_code, 204) # Part count should have reduced From 34a374ce9ac0a212ca05774ffb5f344d601cb92d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 27 Jun 2021 01:18:09 +1000 Subject: [PATCH 117/445] Add try/except around callable default --- InvenTree/InvenTree/serializers.py | 10 ++++++++-- InvenTree/part/test_api.py | 2 -- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index 1f7b8c0290..50a37d8cba 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -70,7 +70,10 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): # Account for callable functions if callable(value): - value = value() + try: + value = value() + except: + continue data[field_name] = value @@ -98,7 +101,10 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): # Account for callable functions if callable(value): - value = value() + try: + value = value() + except: + continue initials[field_name] = value diff --git a/InvenTree/part/test_api.py b/InvenTree/part/test_api.py index ee01df89cf..4922ed4e04 100644 --- a/InvenTree/part/test_api.py +++ b/InvenTree/part/test_api.py @@ -603,8 +603,6 @@ class PartDetailTests(InvenTreeAPITestCase): # And now check that the image has been set p = Part.objects.get(pk=pk) - print("Image:", p.image.file) - class PartAPIAggregationTest(InvenTreeAPITestCase): """ From 67128c308bb8a5985abd233f20f94fc13e4e6401 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Jun 2021 12:26:02 +0200 Subject: [PATCH 118/445] fixing typo --- InvenTree/part/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 2b97fde596..7ed4c99057 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -2503,7 +2503,7 @@ class BomItem(models.Model): # get internal price setting use_internal = common.models.InvenTreeSetting.get_setting('PART_BOM_USE_INTERNAL_PRICE', False) - prange = self.sub_part.get_price_range(self.quantity, intenal=use_internal) + prange = self.sub_part.get_price_range(self.quantity, internal=use_internal) if prange is None: return prange From 786e994e19923a742e40922939dbd6cc91a157e1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 27 Jun 2021 20:58:24 +1000 Subject: [PATCH 119/445] Update version.py 0.2.4 --- InvenTree/InvenTree/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index 08fa5e0ae4..738274b1cd 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -8,7 +8,7 @@ import re import common.models -INVENTREE_SW_VERSION = "0.2.4 pre" +INVENTREE_SW_VERSION = "0.2.4" INVENTREE_API_VERSION = 6 From 604c136b003eed3d82c488eecbeb85cbf0fe2ebf Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 27 Jun 2021 21:00:01 +1000 Subject: [PATCH 120/445] Update version.py --- InvenTree/InvenTree/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index 738274b1cd..6afa5ebadd 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -8,7 +8,7 @@ import re import common.models -INVENTREE_SW_VERSION = "0.2.4" +INVENTREE_SW_VERSION = "0.2.5 pre" INVENTREE_API_VERSION = 6 From d80948369b65ff7594ae5cf8d74aaad1f39cbb68 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 27 Jun 2021 21:44:21 +1000 Subject: [PATCH 121/445] Include 'default' value in OPTIONS request for any fields with specified default values --- InvenTree/InvenTree/metadata.py | 38 +++++++++++++++++-- .../company/templates/company/index.html | 25 ++++++++++-- RELEASE.md | 4 ++ 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/InvenTree/InvenTree/metadata.py b/InvenTree/InvenTree/metadata.py index 611b12101c..85815d2558 100644 --- a/InvenTree/InvenTree/metadata.py +++ b/InvenTree/InvenTree/metadata.py @@ -6,6 +6,7 @@ import logging from rest_framework import serializers from rest_framework.metadata import SimpleMetadata +from rest_framework.utils import model_meta import users.models @@ -41,11 +42,11 @@ class InvenTreeMetadata(SimpleMetadata): try: # Extract the model name associated with the view - model = view.serializer_class.Meta.model + self.model = view.serializer_class.Meta.model # Construct the 'table name' from the model - app_label = model._meta.app_label - tbl_label = model._meta.model_name + app_label = self.model._meta.app_label + tbl_label = self.model._meta.model_name table = f"{app_label}_{tbl_label}" @@ -83,6 +84,37 @@ class InvenTreeMetadata(SimpleMetadata): return metadata + def get_serializer_info(self, serializer): + """ + Override get_serializer_info so that we can add 'default' values + to any fields whose Meta.model specifies a default value + """ + + field_info = super().get_serializer_info(serializer) + + try: + ModelClass = serializer.Meta.model + + model_fields = model_meta.get_field_info(ModelClass) + + for name, field in model_fields.fields.items(): + + if field.has_default() and name in field_info.keys(): + + default = field.default + + if callable(default): + try: + default = default() + except: + continue + + field_info[name]['default'] = default + except AttributeError: + pass + + return field_info + def get_field_info(self, field): """ Given an instance of a serializer field, return a dictionary diff --git a/InvenTree/company/templates/company/index.html b/InvenTree/company/templates/company/index.html index 3a3168f24e..2f7319fb74 100644 --- a/InvenTree/company/templates/company/index.html +++ b/InvenTree/company/templates/company/index.html @@ -15,10 +15,13 @@ {% if pagetype == 'manufacturers' and roles.purchase_order.add or pagetype == 'suppliers' and roles.purchase_order.add or pagetype == 'customers' and roles.sales_order.add %}
          + +
          -
          {% endif %} @@ -35,6 +38,22 @@ }); }); + $('#new-company-2').click(function() { + constructForm( + '{% url "api-company-list" %}', + { + method: 'POST', + fields: [ + 'name', + 'description', + 'is_supplier', + 'is_manufacturer', + 'is_customer', + ] + } + ); + }); + loadCompanyTable("#company-table", "{% url 'api-company-list' %}", { pagetype: '{{ pagetype }}', diff --git a/RELEASE.md b/RELEASE.md index 90fb027a62..7d6d0fba23 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -21,3 +21,7 @@ Create new release for the [inventree documentation](https://github.com/inventre ### Python Library Release Create new release for the [inventree python library](https://github.com/inventree/inventree-python) + +## App Release + +Create new versioned release for the InvenTree mobile app. From a3ec24fbcc4a837a1e795c96dd3510e5cc2ac3d5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Jun 2021 13:48:08 +0200 Subject: [PATCH 122/445] Reenabling prices for BOM items Closes #1721 --- InvenTree/part/serializers.py | 4 ++-- InvenTree/templates/js/bom.js | 11 ++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 6c47f1310f..2da2d05d3b 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -377,7 +377,7 @@ class PartStarSerializer(InvenTreeModelSerializer): class BomItemSerializer(InvenTreeModelSerializer): """ Serializer for BomItem object """ - # price_range = serializers.CharField(read_only=True) + price_range = serializers.CharField(read_only=True) quantity = serializers.FloatField() @@ -492,7 +492,7 @@ class BomItemSerializer(InvenTreeModelSerializer): 'reference', 'sub_part', 'sub_part_detail', - # 'price_range', + 'price_range', 'validated', ] diff --git a/InvenTree/templates/js/bom.js b/InvenTree/templates/js/bom.js index 7328bcb331..665379d8d5 100644 --- a/InvenTree/templates/js/bom.js +++ b/InvenTree/templates/js/bom.js @@ -259,26 +259,19 @@ function loadBomTable(table, options) { sortable: true, }); - /* - - // TODO - Re-introduce the pricing column at a later stage, - // once the pricing has been "fixed" - // O.W. 2020-11-24 - cols.push( { field: 'price_range', - title: '{% trans "Price" %}', + title: '{% trans "Buy Price" %}', sortable: true, formatter: function(value, row, index, field) { if (value) { return value; } else { - return "{% trans "No pricing available" %}"; + return "{% trans 'No pricing available' %}"; } } }); - */ cols.push({ field: 'optional', From 0e9b82c475a28a83399cc41cf517bf2d0a95e00d Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 27 Jun 2021 21:58:22 +1000 Subject: [PATCH 123/445] Load default values into rendered form --- .../company/templates/company/index.html | 5 ++ InvenTree/templates/js/forms.js | 48 ++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/InvenTree/company/templates/company/index.html b/InvenTree/company/templates/company/index.html index 2f7319fb74..28129b1f36 100644 --- a/InvenTree/company/templates/company/index.html +++ b/InvenTree/company/templates/company/index.html @@ -46,6 +46,11 @@ fields: [ 'name', 'description', + 'website', + 'address', + 'phone', + 'email', + 'contact', 'is_supplier', 'is_manufacturer', 'is_customer', diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index b33f5048b3..7d6cc5cd98 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -110,6 +110,16 @@ function getApiEndpointOptions(url, callback, options) { */ function constructCreateForm(fields, options) { + // Check if default values were provided for any fields + for (const name in fields) { + + var field = fields[name]; + + if (field.default != null) { + field.value = field.default; + } + } + // We should have enough information to create the form! constructFormBody(fields, options); } @@ -320,6 +330,8 @@ function constructFormBody(fields, options) { $(modal).modal('show'); + updateFieldValues(fields, options); + // Setup related fields initializeRelatedFields(fields, options) @@ -387,6 +399,41 @@ function submitFormData(fields, options) { } +/* + * Update (set) the field values based on the specified data. + * + * Iterate through each of the displayed fields, + * and set the 'val' attribute of each one. + * + */ +function updateFieldValues(fields, options) { + + for (var idx = 0; idx < options.field_names.length; idx++) { + + var name = options.field_names[idx]; + + var field = fields[name] || null; + + if (field == null) { continue; } + + var value = field.value || field.default || null; + + if (value == null) { continue; } + + var el = $(options.modal).find(`#id_${name}`); + + switch (field.type) { + case 'boolean': + el.prop('checked', value); + break; + default: + el.val(value); + break; + } + } +} + + /* * Extract and field value before sending back to the server * @@ -409,7 +456,6 @@ function getFormFieldValue(name, field, options) { } - /* * Handle successful form posting * From 4f726931a63a3a80b52c171483e12e6bf952f258 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Jun 2021 14:18:37 +0200 Subject: [PATCH 124/445] adds in money-conversion helper --- InvenTree/InvenTree/helpers.py | 19 +++++++++++++++++++ InvenTree/part/models.py | 14 +++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 9d00697230..cc1e60eb8e 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -21,6 +21,9 @@ import InvenTree.version from common.models import InvenTreeSetting from .settings import MEDIA_URL, STATIC_URL +from common.settings import currency_code_default + +from djmoney.money import Money def getSetting(key, backup_value=None): @@ -247,6 +250,22 @@ def decimal2string(d): return s.rstrip("0").rstrip(".") +def decimal2money(d, currency = None): + """ + Format a Decimal number as Money + + Args: + d: A python Decimal object + currency: Currency of the input amount, defaults to default currency in settings + + Returns: + A Money object from the input(s) + """ + if not currency: + currency = currency_code_default() + return Money(d, currency) + + def WrapWithQuotes(text, quote='"'): """ Wrap the supplied text with quotes diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 7ed4c99057..f76ff4c104 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -39,7 +39,7 @@ from InvenTree import helpers from InvenTree import validators from InvenTree.models import InvenTreeTree, InvenTreeAttachment from InvenTree.fields import InvenTreeURLField -from InvenTree.helpers import decimal2string, normalize +from InvenTree.helpers import decimal2string, normalize, decimal2money from InvenTree.status_codes import BuildStatus, PurchaseOrderStatus, SalesOrderStatus @@ -2414,7 +2414,7 @@ class BomItem(models.Model): return "{n} x {child} to make {parent}".format( parent=self.part.full_name, child=self.sub_part.full_name, - n=helpers.decimal2string(self.quantity)) + n=decimal2string(self.quantity)) def available_stock(self): """ @@ -2498,12 +2498,12 @@ class BomItem(models.Model): return required @property - def price_range(self): + def price_range(self, internal = False): """ Return the price-range for this BOM item. """ # get internal price setting use_internal = common.models.InvenTreeSetting.get_setting('PART_BOM_USE_INTERNAL_PRICE', False) - prange = self.sub_part.get_price_range(self.quantity, internal=use_internal) + prange = self.sub_part.get_price_range(self.quantity, internal=use_internal and internal) if prange is None: return prange @@ -2511,11 +2511,11 @@ class BomItem(models.Model): pmin, pmax = prange if pmin == pmax: - return decimal2string(pmin) + return decimal2money(pmin) # Convert to better string representation - pmin = decimal2string(pmin) - pmax = decimal2string(pmax) + pmin = decimal2money(pmin) + pmax = decimal2money(pmax) return "{pmin} to {pmax}".format(pmin=pmin, pmax=pmax) From e4a9d56ba0d7aeebbd2f20fa52035b0c7b086ad3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Jun 2021 14:26:51 +0200 Subject: [PATCH 125/445] style fixes --- InvenTree/InvenTree/helpers.py | 2 +- InvenTree/part/models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index cc1e60eb8e..330bd2bb68 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -250,7 +250,7 @@ def decimal2string(d): return s.rstrip("0").rstrip(".") -def decimal2money(d, currency = None): +def decimal2money(d, currency=None): """ Format a Decimal number as Money diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index f76ff4c104..9f4da436df 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -2498,7 +2498,7 @@ class BomItem(models.Model): return required @property - def price_range(self, internal = False): + def price_range(self, internal=False): """ Return the price-range for this BOM item. """ # get internal price setting From 16f25f54d4797b2cfbd89d79a950fbeb91cf4783 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Jun 2021 17:45:31 +0200 Subject: [PATCH 126/445] sorting price-breaks on start --- InvenTree/part/templates/part/prices.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/InvenTree/part/templates/part/prices.html b/InvenTree/part/templates/part/prices.html index 1214239fe4..31732d3d94 100644 --- a/InvenTree/part/templates/part/prices.html +++ b/InvenTree/part/templates/part/prices.html @@ -189,7 +189,8 @@
          - +
          @@ -240,7 +241,8 @@
          - +
          From 984efd7493cad851e52ad2582cd639ec1d82eb8a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Jun 2021 17:51:49 +0200 Subject: [PATCH 127/445] sort graph-data as well --- InvenTree/templates/js/part.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/InvenTree/templates/js/part.js b/InvenTree/templates/js/part.js index 75e925266a..bab8a914db 100644 --- a/InvenTree/templates/js/part.js +++ b/InvenTree/templates/js/part.js @@ -788,6 +788,10 @@ function loadPriceBreakTable(table, options) { url: options.url, onLoadSuccess: function(tableData) { if (linkedGraph) { + // sort array + tableData = tableData.sort((a,b)=>a.quantity-b.quantity); + + // split up for graph definition var labels = Array.from(tableData, x => x.quantity); var data = Array.from(tableData, x => parseFloat(x.price)); From d71aee00cd34f3bbe059edd2aae154f922b19e03 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Jun 2021 17:54:33 +0200 Subject: [PATCH 128/445] refactor of variable names --- InvenTree/templates/js/part.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/InvenTree/templates/js/part.js b/InvenTree/templates/js/part.js index bab8a914db..888f1d245a 100644 --- a/InvenTree/templates/js/part.js +++ b/InvenTree/templates/js/part.js @@ -792,8 +792,8 @@ function loadPriceBreakTable(table, options) { tableData = tableData.sort((a,b)=>a.quantity-b.quantity); // split up for graph definition - var labels = Array.from(tableData, x => x.quantity); - var data = Array.from(tableData, x => parseFloat(x.price)); + var graphLabels = Array.from(tableData, x => x.quantity); + var graphData = Array.from(tableData, x => parseFloat(x.price)); // destroy chart if exists if (chart){ @@ -801,11 +801,11 @@ function loadPriceBreakTable(table, options) { } chart = loadLineChart(linkedGraph, { - labels: labels, + labels: graphLabels, datasets: [ { label: '{% trans "Unit Price" %}', - data: data, + data: graphData, backgroundColor: 'rgba(255, 206, 86, 0.2)', borderColor: 'rgb(255, 206, 86)', stepped: true, From ef07c93634ce202df4665145e8ce77f19f39cb37 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Jun 2021 18:31:40 +0200 Subject: [PATCH 129/445] section anchors --- InvenTree/InvenTree/static/css/inventree.css | 11 ++++- InvenTree/part/templates/part/prices.html | 45 ++++++++++++++++---- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index a0030ee7e6..41e0937a8b 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -965,9 +965,16 @@ input[type="date"].form-control, input[type="time"].form-control, input[type="da .row.full-height { display: flex; flex-wrap: wrap; - } +} .row.full-height > [class*='col-'] { display: flex; flex-direction: column; - } +} + +a.anchor { + display: block; + position: relative; + top: -60px; + visibility: hidden; +} \ No newline at end of file diff --git a/InvenTree/part/templates/part/prices.html b/InvenTree/part/templates/part/prices.html index 31732d3d94..0d5b3e9d91 100644 --- a/InvenTree/part/templates/part/prices.html +++ b/InvenTree/part/templates/part/prices.html @@ -17,13 +17,17 @@ {% default_currency as currency %}
          +

          {% trans "Pricing ranges" %}

          {% if part.supplier_count > 0 %} {% if min_total_buy_price %} - + @@ -48,7 +52,9 @@ {% if part.bom_count > 0 %} {% if min_total_bom_price %} - + @@ -94,7 +100,10 @@ {% if total_part_price %} - + @@ -132,8 +141,11 @@ {% if part.purchaseable and roles.purchase_order.view %}
          +
          -

          {% trans "Supplier Cost" %}

          +

          {% trans "Supplier Cost" %} + +

          @@ -149,8 +161,11 @@
          +
          -

          {% trans "Purchase Price" %}

          +

          {% trans "Purchase Price" %} + +

          {% if price_history %} @@ -172,8 +187,11 @@ {% if show_internal_price and roles.sales_order.view %}
          +
          -

          {% trans "Internal Cost" %}

          +

          {% trans "Internal Cost" %} + +

          @@ -200,8 +218,11 @@ {% if part.has_bom and roles.sales_order.view %}
          +
          -

          {% trans "BOM Cost" %}

          +

          {% trans "BOM Cost" %} + +

          @@ -224,8 +245,11 @@ {% if part.salable and roles.sales_order.view %}
          +
          -

          {% trans "Sale Cost" %}

          +

          {% trans "Sale Cost" %} + +

          @@ -249,8 +273,11 @@
          +
          -

          {% trans "Sale Price" %}

          +

          {% trans "Sale Price" %} + +

          From f479c0cd27d6589d519d27660786b85b5a1b987c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Jun 2021 20:46:52 +0200 Subject: [PATCH 130/445] naming refactor --- InvenTree/part/templates/part/prices.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/InvenTree/part/templates/part/prices.html b/InvenTree/part/templates/part/prices.html index 0d5b3e9d91..b1403b3157 100644 --- a/InvenTree/part/templates/part/prices.html +++ b/InvenTree/part/templates/part/prices.html @@ -293,6 +293,8 @@ {% block js_ready %} {{ block.super }} + {% default_currency as currency %} + loadSupplierPartTable( "#supplier-table", @@ -321,9 +323,8 @@ // history graphs - {% default_currency as currency %} {% if price_history %} - var pricedata = { + var purchasepricedata = { labels: [ {% for line in price_history %}'{{ line.date }}',{% endfor %} ], @@ -375,7 +376,7 @@ borderWidth: 1 }] } - var StockPriceChart = loadStockPricingChart($('#StockPriceChart'), pricedata) + var StockPriceChart = loadStockPricingChart($('#StockPriceChart'), purchasepricedata) var bom_colors = randomColor({hue: 'green', count: {{ bom_parts|length }} }) var bomdata = { labels: [{% for line in bom_parts %}'{{ line.name }}',{% endfor %}], From e06397adc1da181e3ad281958a4df8411dab503e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Jun 2021 21:31:10 +0200 Subject: [PATCH 131/445] refactor --- InvenTree/part/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 2f129dd30b..cb89f67de3 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -979,6 +979,8 @@ class PartPricingView(PartDetail): """ returns context with pricing information """ ctx = PartPricing.get_pricing(self, quantity, currency) part = self.get_part() + default_currency = inventree_settings.currency_code_default() + # Stock history if part.total_stock > 1: price_history = [] @@ -990,7 +992,7 @@ class PartPricingView(PartDetail): continue # convert purchase price to current currency - only one currency in the graph - price = convert_money(stock_item.purchase_price, inventree_settings.currency_code_default()) + price = convert_money(stock_item.purchase_price, default_currency) line = { 'price': price.amount, 'qty': stock_item.quantity From 4462b1e25064a0bca7ac4c415d57e30f8d3cb023 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Jun 2021 21:31:34 +0200 Subject: [PATCH 132/445] order stock histroy items --- InvenTree/part/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index cb89f67de3..7a683a29b5 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -984,8 +984,8 @@ class PartPricingView(PartDetail): # Stock history if part.total_stock > 1: price_history = [] - stock = part.stock_entries(include_variants=False, in_stock=True) # .order_by('purchase_order__date') - stock = stock.prefetch_related('purchase_order', 'supplier_part') + stock = part.stock_entries(include_variants=False, in_stock=True).\ + order_by('purchase_order__issue_date').prefetch_related('purchase_order', 'supplier_part') for stock_item in stock: if None in [stock_item.purchase_price, stock_item.quantity]: From 5598f7fad15ef481f52de11d9bb2623a3ab8d1e8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Jun 2021 21:32:27 +0200 Subject: [PATCH 133/445] added sale price history --- InvenTree/part/templates/part/prices.html | 41 ++++++++++++++++++++++- InvenTree/part/views.py | 31 +++++++++++++++++ InvenTree/templates/js/part.js | 33 ++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/templates/part/prices.html b/InvenTree/part/templates/part/prices.html index b1403b3157..9c216eb534 100644 --- a/InvenTree/part/templates/part/prices.html +++ b/InvenTree/part/templates/part/prices.html @@ -281,7 +281,15 @@
          - PLACEHOLDER FOR SALE HISTORY + {% if sale_history|length > 0 %} +
          + +
          + {% else %} +
          + {% trans 'No sale pice history available for this part.' %} +
          + {% endif %}
          {% endif %} @@ -444,4 +452,35 @@ ); {% endif %} + // Sale price history + {% if sale_history %} + var salepricedata = { + labels: [ + {% for line in sale_history %}'{{ line.date }}',{% endfor %} + ], + datasets: [{ + label: '{% blocktrans %}Unit Price - {{currency}}{% endblocktrans %}', + backgroundColor: 'rgba(255, 99, 132, 0.2)', + borderColor: 'rgb(255, 99, 132)', + yAxisID: 'y', + data: [ + {% for line in sale_history %}{{ line.price|stringformat:".2f" }},{% endfor %} + ], + borderWidth: 1, + }, + { + label: '{% trans "Quantity" %}', + backgroundColor: 'rgba(255, 206, 86, 0.2)', + borderColor: 'rgb(255, 206, 86)', + yAxisID: 'y1', + data: [ + {% for line in sale_history %}{{ line.qty|stringformat:"f" }},{% endfor %} + ], + borderWidth: 1, + type: 'bar', + }] + } + var SalePriceChart = loadSellPricingChart($('#SalePriceChart'), salepricedata) + {% endif %} + {% endblock %} diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 7a683a29b5..30e95535d6 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -50,6 +50,7 @@ import common.settings as inventree_settings from . import forms as part_forms from .bom import MakeBomTemplate, BomUploadManager, ExportBom, IsValidBOMFormat +from order.models import PurchaseOrderLineItem from .admin import PartResource @@ -1038,6 +1039,36 @@ class PartPricingView(PartDetail): # add to global context ctx['bom_parts'] = ctx_bom_parts + # Sale price history + sale_items = PurchaseOrderLineItem.objects.filter(part__part=part).order_by('order__issue_date').\ + prefetch_related('order', ).all() + + if sale_items: + sale_history = [] + + for sale_item in sale_items: + # check for not fully defined elements + if None in [sale_item.purchase_price, sale_item.quantity]: + continue + + price = convert_money(sale_item.purchase_price, default_currency) + line = { + 'price': price.amount if price else 0, + 'qty': sale_item.quantity, + } + + # set date for graph labels + if sale_item.order.issue_date: + line['date'] = sale_item.order.issue_date.strftime('%d.%m.%Y') + elif sale_item.order.creation_date: + line['date'] = sale_item.order.creation_date.strftime('%d.%m.%Y') + else: + line['date'] = _('None') + + sale_history.append(line) + + ctx['sale_history'] = sale_history + return ctx def get_initials(self): diff --git a/InvenTree/templates/js/part.js b/InvenTree/templates/js/part.js index 888f1d245a..7fa63098e1 100644 --- a/InvenTree/templates/js/part.js +++ b/InvenTree/templates/js/part.js @@ -977,3 +977,36 @@ function loadBomChart(context, data) { } }); } + +function loadSellPricingChart(context, data) { + return new Chart(context, { + type: 'line', + data: data, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: {legend: {position: 'bottom'}}, + scales: { + y: { + type: 'linear', + position: 'left', + grid: {display: false}, + title: { + display: true, + text: '{% trans "Unit Price" %}' + } + }, + y1: { + type: 'linear', + position: 'right', + grid: {display: false}, + titel: { + display: true, + text: '{% trans "Quantity" %}', + position: 'right' + } + }, + }, + } + }); +} From 6335372208078d5c588938bbc9bd34500d08edc1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 28 Jun 2021 09:28:38 +1000 Subject: [PATCH 134/445] Store instance data when performing an "update" --- InvenTree/templates/js/forms.js | 5 ++++- InvenTree/templates/js/model_renderers.js | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 7d6cc5cd98..063f953966 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -155,6 +155,9 @@ function constructChangeForm(fields, options) { } } + // Store the entire data object + options.instance = data; + constructFormBody(fields, options); }, error: function(request, status, error) { @@ -570,7 +573,7 @@ function initializeRelatedFields(fields, options) { * - field: Field definition from the OPTIONS request * - options: Original options object provided by the client */ -function initializeRelatedField(modal, name, field, options) { +function initializeRelatedField(name, field, options) { // Find the select element and attach a select2 to it var select = $(options.modal).find(`#id_${name}`); diff --git a/InvenTree/templates/js/model_renderers.js b/InvenTree/templates/js/model_renderers.js index 924d85d35d..ae32c06eff 100644 --- a/InvenTree/templates/js/model_renderers.js +++ b/InvenTree/templates/js/model_renderers.js @@ -1,3 +1,5 @@ +{% load i18n %} + /* * This file contains functions for rendering various InvenTree database models, * in particular for displaying them in modal forms in a 'select2' context. @@ -69,12 +71,14 @@ function renderPart(name, data, parameters, options) { // Renderer for "PartCategory" model function renderPartCategory(name, data, parameters, options) { - var html = `${data.name}`; + var html = `${data.name}`; if (data.description) { html += ` - ${data.description}`; } + html += `{% trans "Location ID" %}: ${data.pk}`; + if (data.pathstring) { html += `

          ${data.pathstring}

          `; } From ba2537d125061af4f4bceccd1adda30cbaa9e9fd Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 28 Jun 2021 13:03:34 +1000 Subject: [PATCH 135/445] Refactor the way that field options are passed to a form --- InvenTree/templates/js/forms.js | 49 ++++++++++++++------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 063f953966..4e8791f125 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -243,21 +243,20 @@ function constructForm(url, options) { } - +/* + * Construct a modal form based on the provided options + * + * arguments: + * - fields: The endpoint description returned from the OPTIONS request + * - options: form options object provided by the client. + */ function constructFormBody(fields, options) { var html = ''; - var allowed_fields = options.fields || null; - var ignored_fields = options.ignore || []; - - if (!ignored_fields.includes('pk')) { - ignored_fields.push('pk'); - } - - if (!ignored_fields.includes('id')) { - ignored_fields.push('id'); - } + // Client must provide set of fields to be displayed, + // otherwise *all* fields will be displayed + var displayed_fields = options.fields || fields; // Provide each field object with its own name for(field in fields) { @@ -267,25 +266,13 @@ function constructFormBody(fields, options) { // Construct an ordered list of field names var field_names = []; - if (allowed_fields) { - allowed_fields.forEach(function(name) { + for (var name in displayed_fields) { - // Only push names which are actually in the set of fields - if (name in fields) { - - if (!ignored_fields.includes(name) && !field_names.includes(name)) { - field_names.push(name); - } - } else { - console.log(`WARNING: '${name}' does not match a valid field name.`); - } - }); - } else { - for (const name in fields) { - - if (!ignored_fields.includes(name) && !field_names.includes(name)) { - field_names.push(name); - } + // Only push names which are actually in the set of fields + if (name in fields) { + field_names.push(name); + } else { + console.log(`WARNING: '${name}' does not match a valid field name.`); } } @@ -429,6 +416,10 @@ function updateFieldValues(fields, options) { case 'boolean': el.prop('checked', value); break; + case 'related field': + // TODO + console.log(`related field '${name}'`); + break; default: el.val(value); break; From e2942238a9036c10c5a64b6fec371ae31fdff82c Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 28 Jun 2021 13:10:41 +1000 Subject: [PATCH 136/445] Bug fix - check for null rather than just ! --- InvenTree/templates/js/forms.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 4e8791f125..c90569d9c0 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -406,7 +406,11 @@ function updateFieldValues(fields, options) { if (field == null) { continue; } - var value = field.value || field.default || null; + var value = field.value; + + if (value == null) { + value = field.default; + } if (value == null) { continue; } From 41539b75db59c91e0673e49149fa9b0a0cf9808e Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 28 Jun 2021 14:19:05 +1000 Subject: [PATCH 137/445] Adds custom filters for AJAX queries --- InvenTree/templates/js/forms.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index c90569d9c0..6cc665513f 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -261,6 +261,15 @@ function constructFormBody(fields, options) { // Provide each field object with its own name for(field in fields) { fields[field].name = field; + + var field_options = displayed_fields[field]; + + // Copy custom options across to the fields object + if (field_options) { + + // Query filters + fields[field].filters = field_options.filters; + } } // Construct an ordered list of field names @@ -596,12 +605,15 @@ function initializeRelatedField(name, field, options) { offset = (params.page - 1) * pageSize; } - // Re-format search term into InvenTree API style - return { - search: params.term, - offset: offset, - limit: pageSize, - }; + // Custom query filters can be specified against each field + var query = field.filters || {}; + + // Add search and pagination options + query.search = params.term; + query.offset = offset; + query.limit = pageSize; + + return query; }, processResults: function(response) { // Convert the returned InvenTree data into select2-friendly format From fbff9bfb2d25c99b7328c144674026b963fd060b Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 28 Jun 2021 15:10:17 +1000 Subject: [PATCH 138/445] Insert buttons for secondary modals --- InvenTree/templates/js/forms.js | 34 +++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 6cc665513f..833c4eb667 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -269,6 +269,9 @@ function constructFormBody(fields, options) { // Query filters fields[field].filters = field_options.filters; + + // Secondary modal options + fields[field].secondary = field_options.secondary; } } @@ -568,6 +571,29 @@ function initializeRelatedFields(fields, options) { } +/* + * Add a button to launch a secondary modal, to create a new modal instance. + * + * arguments: + * - name: The name of the field + * - field: The field data object + * - options: The options object provided by the client + */ +function addSecondaryModal(name, field, options) { + + var html = ` + +
          + ${field.secondary.label} +
          +
          `; + + $(options.modal).find(`label[for="id_${name}"]`).append(html); + + // TODO: Launch a callback +} + + /* * Initializea single related-field * @@ -582,6 +608,11 @@ function initializeRelatedField(name, field, options) { // Find the select element and attach a select2 to it var select = $(options.modal).find(`#id_${name}`); + // Add a button to launch a 'secondary' modal + if (field.secondary != null) { + addSecondaryModal(name, field, options); + } + // TODO: Add 'placeholder' support for entry select2 fields // limit size for AJAX requests @@ -591,12 +622,11 @@ function initializeRelatedField(name, field, options) { ajax: { url: field.api_url, dataType: 'json', - allowClear: !field.required, // Allow non required fields to be cleared + allowClear: !field.required, dropdownParent: $(options.modal), dropdownAutoWidth: false, delay: 250, cache: true, - // matcher: partialMatcher, data: function(params) { if (!params.page) { From e58507977995fc4f324445ac86c53f9dcb3eacc2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 28 Jun 2021 19:32:48 +1000 Subject: [PATCH 139/445] Callback function for fields after editing --- InvenTree/templates/js/forms.js | 37 ++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 833c4eb667..9c24aa7780 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -272,6 +272,9 @@ function constructFormBody(fields, options) { // Secondary modal options fields[field].secondary = field_options.secondary; + + // Edit callback + fields[field].onEdit = field_options.onEdit; } } @@ -335,7 +338,10 @@ function constructFormBody(fields, options) { updateFieldValues(fields, options); // Setup related fields - initializeRelatedFields(fields, options) + initializeRelatedFields(fields, options); + + // Attach edit callbacks (if required) + addFieldCallbacks(fields, options); attachToggle(modal); @@ -548,6 +554,35 @@ function handleFormErrors(errors, fields, options) { } +/* + * Attach callbacks to specified fields, + * triggered after the field value is edited. + * + * Callback function is called with arguments (name, field, options) + */ +function addFieldCallbacks(fields, options) { + + for (var idx = 0; idx < options.field_names.length; idx++) { + + var name = options.field_names[idx]; + + var field = fields[name]; + + if (!field || !field.onEdit) continue; + + addFieldCallback(name, field, options); + } +} + + +function addFieldCallback(name, field, options) { + + $(options.modal).find(`#id_${name}`).change(function() { + field.onEdit(name, field, options); + }); +} + + function initializeRelatedFields(fields, options) { var field_names = options.field_names; From f3ed05a09e4f5ccf1b65577a0189c80b85c34be6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 28 Jun 2021 20:13:18 +1000 Subject: [PATCH 140/445] Automatically associate ''filters' with relations --- InvenTree/InvenTree/metadata.py | 17 ++++++++++ .../company/templates/company/index.html | 33 ++++++++++++++++--- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/InvenTree/InvenTree/metadata.py b/InvenTree/InvenTree/metadata.py index 85815d2558..89b5b14493 100644 --- a/InvenTree/InvenTree/metadata.py +++ b/InvenTree/InvenTree/metadata.py @@ -97,6 +97,7 @@ class InvenTreeMetadata(SimpleMetadata): model_fields = model_meta.get_field_info(ModelClass) + # Iterate through simple fields for name, field in model_fields.fields.items(): if field.has_default() and name in field_info.keys(): @@ -110,9 +111,25 @@ class InvenTreeMetadata(SimpleMetadata): continue field_info[name]['default'] = default + + # Iterate through relations + for name, relation in model_fields.relations.items(): + + if relation.reverse: + print("skipping reverse relation -", name) + continue + + print('filters:', name, relation.model_field.get_limit_choices_to()) + + continue + # Extract and provide the "limit_choices_to" filters + field_info[name]['filters'] = relation.model_field.get_limit_choices_to() + except AttributeError: pass + print(field_info.keys()) + return field_info def get_field_info(self, field): diff --git a/InvenTree/company/templates/company/index.html b/InvenTree/company/templates/company/index.html index 28129b1f36..f02ae1e6c8 100644 --- a/InvenTree/company/templates/company/index.html +++ b/InvenTree/company/templates/company/index.html @@ -40,12 +40,34 @@ $('#new-company-2').click(function() { constructForm( - '{% url "api-company-list" %}', + '{% url "api-build-list" %}', { method: 'POST', - fields: [ - 'name', - 'description', + title: '{% trans "Edit Part Details" %}', + fields: { + name: { + onEdit: function() { + console.log('Edited name field'); + } + }, + description: {}, + category: { + filters: { + parent: 1, + }, + secondary: { + label: '{% trans "New Category" %}', + }, + }, + active: { + onEdit: function() { + console.log('edited active field'); + } + }, + purchaseable: {}, + salable: {}, + component: {}, + /* 'website', 'address', 'phone', @@ -54,7 +76,8 @@ 'is_supplier', 'is_manufacturer', 'is_customer', - ] + */ + } } ); }); From 3c1f0637dcddfa6f6b4782e64e81883f113c0f30 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 28 Jun 2021 20:42:37 +1000 Subject: [PATCH 141/445] Adds unit tests for HTML API endpoints --- InvenTree/InvenTree/test_api.py | 87 +++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/InvenTree/InvenTree/test_api.py b/InvenTree/InvenTree/test_api.py index f196006df9..bc1157cf45 100644 --- a/InvenTree/InvenTree/test_api.py +++ b/InvenTree/InvenTree/test_api.py @@ -1,7 +1,13 @@ """ Low level tests for the InvenTree API """ +from django.http import response from rest_framework import status +from django.test import TestCase + +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group + from django.urls import reverse from InvenTree.api_tester import InvenTreeAPITestCase @@ -11,6 +17,87 @@ from users.models import RuleSet from base64 import b64encode +class HTMLAPITests(TestCase): + """ + Test that we can access the REST API endpoints via the HTML interface. + + History: Discovered on 2021-06-28 a bug in InvenTreeModelSerializer, + which raised an AssertionError when using the HTML API interface, + while the regular JSON interface continued to work as expected. + """ + + def setUp(self): + super().setUp() + + # Create a user + user = get_user_model() + + self.user = user.objects.create_user( + username='username', + email='user@email.com', + password='password' + ) + + # Put the user into a group with the correct permissions + group = Group.objects.create(name='mygroup') + self.user.groups.add(group) + + # Give the group *all* the permissions! + for rule in group.rule_sets.all(): + rule.can_view = True + rule.can_change = True + rule.can_add = True + rule.can_delete = True + + rule.save() + + self.client.login(username='username', password='password') + + def test_part_api(self): + url = reverse('api-part-list') + + # Check JSON response + response = self.client.get(url, HTTP_ACCEPT='application/json') + self.assertEqual(response.status_code, 200) + + # Check HTTP response + response = self.client.get(url, HTTP_ACCEPT='text/html') + self.assertEqual(response.status_code, 200) + + def test_build_api(self): + url = reverse('api-build-list') + + # Check JSON response + response = self.client.get(url, HTTP_ACCEPT='application/json') + self.assertEqual(response.status_code, 200) + + # Check HTTP response + response = self.client.get(url, HTTP_ACCEPT='text/html') + self.assertEqual(response.status_code, 200) + + def test_stock_api(self): + url = reverse('api-stock-list') + + # Check JSON response + response = self.client.get(url, HTTP_ACCEPT='application/json') + self.assertEqual(response.status_code, 200) + + # Check HTTP response + response = self.client.get(url, HTTP_ACCEPT='text/html') + self.assertEqual(response.status_code, 200) + + def test_company_list(self): + url = reverse('api-company-list') + + # Check JSON response + response = self.client.get(url, HTTP_ACCEPT='application/json') + self.assertEqual(response.status_code, 200) + + # Check HTTP response + response = self.client.get(url, HTTP_ACCEPT='text/html') + self.assertEqual(response.status_code, 200) + + class APITests(InvenTreeAPITestCase): """ Tests for the InvenTree API """ From 4dbd770f2d4f3bf65acef7d43cd048ef2956c482 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 28 Jun 2021 21:08:50 +1000 Subject: [PATCH 142/445] Fixed (I think?) --- InvenTree/InvenTree/serializers.py | 18 +++++++----------- InvenTree/InvenTree/test_api.py | 1 - 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index 50a37d8cba..16db21ca37 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -7,8 +7,6 @@ from __future__ import unicode_literals import os -from collections import OrderedDict - from django.conf import settings from django.contrib.auth.models import User from django.core.exceptions import ValidationError as DjangoValidationError @@ -46,16 +44,13 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): def __init__(self, instance=None, data=empty, **kwargs): - self.instance = instance + # self.instance = instance # If instance is None, we are creating a new instance - if instance is None: + if instance is None and data is not empty: - if data is empty: - data = OrderedDict() - else: - # Required to side-step immutability of a QueryDict - data = data.copy() + # Required to side-step immutability of a QueryDict + data = data.copy() # Add missing fields which have default values ModelClass = self.Meta.model @@ -85,7 +80,7 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): Use the 'default' values specified by the django model definition """ - initials = super().get_initial() + initials = super().get_initial().copy() # Are we creating a new instance? if self.instance is None: @@ -111,7 +106,8 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): return initials def run_validation(self, data=empty): - """ Perform serializer validation. + """ + Perform serializer validation. In addition to running validators on the serializer fields, this class ensures that the underlying model is also validated. """ diff --git a/InvenTree/InvenTree/test_api.py b/InvenTree/InvenTree/test_api.py index bc1157cf45..18f9319624 100644 --- a/InvenTree/InvenTree/test_api.py +++ b/InvenTree/InvenTree/test_api.py @@ -1,6 +1,5 @@ """ Low level tests for the InvenTree API """ -from django.http import response from rest_framework import status from django.test import TestCase From f0f6c7d186f0062f4a3b3d80062dbdf00acde83c Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 28 Jun 2021 21:09:48 +1000 Subject: [PATCH 143/445] Add a comment --- InvenTree/InvenTree/serializers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index 16db21ca37..772daa06ab 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -59,6 +59,11 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): for field_name, field in fields.fields.items(): + """ + Update the field IF (and ONLY IF): + - The field has a specified default value + - The field does not already have a value set + """ if field.has_default() and field_name not in data: value = field.default From ac7564d069bb59834d950fcf788ebd8277a66f82 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 28 Jun 2021 21:29:51 +1000 Subject: [PATCH 144/445] Extract "limit_choices_to" options for relatedfields - Specify as 'filters' for 'related field' type - Extremely handy to be able to filter AJAX requests in a DRY manner! --- InvenTree/InvenTree/metadata.py | 22 +++++++++---------- .../company/templates/company/index.html | 7 +++++- InvenTree/templates/js/forms.js | 4 ++-- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/InvenTree/InvenTree/metadata.py b/InvenTree/InvenTree/metadata.py index 89b5b14493..34490d1079 100644 --- a/InvenTree/InvenTree/metadata.py +++ b/InvenTree/InvenTree/metadata.py @@ -90,7 +90,7 @@ class InvenTreeMetadata(SimpleMetadata): to any fields whose Meta.model specifies a default value """ - field_info = super().get_serializer_info(serializer) + serializer_info = super().get_serializer_info(serializer) try: ModelClass = serializer.Meta.model @@ -100,7 +100,7 @@ class InvenTreeMetadata(SimpleMetadata): # Iterate through simple fields for name, field in model_fields.fields.items(): - if field.has_default() and name in field_info.keys(): + if field.has_default() and name in serializer_info.keys(): default = field.default @@ -110,27 +110,27 @@ class InvenTreeMetadata(SimpleMetadata): except: continue - field_info[name]['default'] = default + serializer_info[name]['default'] = default # Iterate through relations for name, relation in model_fields.relations.items(): - if relation.reverse: - print("skipping reverse relation -", name) + if name not in serializer_info.keys(): + # Skip relation not defined in serializer continue - print('filters:', name, relation.model_field.get_limit_choices_to()) + if relation.reverse: + # Ignore reverse relations + continue - continue # Extract and provide the "limit_choices_to" filters - field_info[name]['filters'] = relation.model_field.get_limit_choices_to() + # This is used to automatically filter AJAX requests + serializer_info[name]['filters'] = relation.model_field.get_limit_choices_to() except AttributeError: pass - print(field_info.keys()) - - return field_info + return serializer_info def get_field_info(self, field): """ diff --git a/InvenTree/company/templates/company/index.html b/InvenTree/company/templates/company/index.html index f02ae1e6c8..fef338078a 100644 --- a/InvenTree/company/templates/company/index.html +++ b/InvenTree/company/templates/company/index.html @@ -45,6 +45,12 @@ method: 'POST', title: '{% trans "Edit Part Details" %}', fields: { + part: { + filters: { + } + }, + quantity: {}, + /* name: { onEdit: function() { console.log('Edited name field'); @@ -67,7 +73,6 @@ purchaseable: {}, salable: {}, component: {}, - /* 'website', 'address', 'phone', diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 9c24aa7780..9343751926 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -267,8 +267,8 @@ function constructFormBody(fields, options) { // Copy custom options across to the fields object if (field_options) { - // Query filters - fields[field].filters = field_options.filters; + // Override existing query filters (if provided!) + fields[field].filters = Object.assign(fields[field].filters || {}, field_options.filters); // Secondary modal options fields[field].secondary = field_options.secondary; From ed2f21f583358c7d6af1d4360ce14ae9d4c48c10 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 28 Jun 2021 21:38:42 +1000 Subject: [PATCH 145/445] Display field prefix element in form --- InvenTree/company/templates/company/index.html | 4 ++++ InvenTree/templates/js/forms.js | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/InvenTree/company/templates/company/index.html b/InvenTree/company/templates/company/index.html index fef338078a..796796528f 100644 --- a/InvenTree/company/templates/company/index.html +++ b/InvenTree/company/templates/company/index.html @@ -45,6 +45,10 @@ method: 'POST', title: '{% trans "Edit Part Details" %}', fields: { + title: { + prefix: `` + }, + reference: {}, part: { filters: { } diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 9343751926..318dfab1b4 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -275,6 +275,9 @@ function constructFormBody(fields, options) { // Edit callback fields[field].onEdit = field_options.onEdit; + + // Field prefix + fields[field].prefix = field_options.prefix; } } @@ -835,14 +838,21 @@ function constructField(name, parameters, options) { html += `
          `; + if (parameters.prefix) { + html += `
          ${parameters.prefix}`; + } + html += constructInput(name, parameters, options); + if (parameters.prefix) { + html += `
          `; // input-group + } + if (parameters.help_text) { html += constructHelpText(name, parameters, options); } html += `
          `; // controls - html += `
          `; // form-group return html; From c3ef8d2dfbfa197a8dafd8f5842d5278ffea5ce6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 09:14:26 +1000 Subject: [PATCH 146/445] Fixes for model renderers --- InvenTree/templates/js/api.js | 8 ++++++++ InvenTree/templates/js/model_renderers.js | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/InvenTree/templates/js/api.js b/InvenTree/templates/js/api.js index aa446028a5..5e8905a1dd 100644 --- a/InvenTree/templates/js/api.js +++ b/InvenTree/templates/js/api.js @@ -18,7 +18,15 @@ function getCookie(name) { } function inventreeGet(url, filters={}, options={}) { + + // Middleware token required for data update + //var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val(); + var csrftoken = getCookie('csrftoken'); + return $.ajax({ + beforeSend: function(xhr, settings) { + xhr.setRequestHeader('X-CSRFToken', csrftoken); + }, url: url, type: 'GET', data: filters, diff --git a/InvenTree/templates/js/model_renderers.js b/InvenTree/templates/js/model_renderers.js index ae32c06eff..24e9c1d328 100644 --- a/InvenTree/templates/js/model_renderers.js +++ b/InvenTree/templates/js/model_renderers.js @@ -18,6 +18,8 @@ function renderCompany(name, data, parameters, options) { var html = `${data.name} - ${data.description}`; + html += `{% trans "Company ID" %}: ${data.pk}`; + return html; } @@ -39,6 +41,8 @@ function renderStockLocation(name, data, parameters, options) { html += ` - ${data.description}`; } + html += `{% trans "Location ID" %}: ${data.pk}`; + if (data.pathstring) { html += `

          ${data.pathstring}

          `; } @@ -64,6 +68,8 @@ function renderPart(name, data, parameters, options) { html += ` - ${data.description}`; } + html += `{% trans "Part ID" %}: ${data.pk}`; + return html; } @@ -77,7 +83,7 @@ function renderPartCategory(name, data, parameters, options) { html += ` - ${data.description}`; } - html += `{% trans "Location ID" %}: ${data.pk}`; + html += `{% trans "Category ID" %}: ${data.pk}`; if (data.pathstring) { html += `

          ${data.pathstring}

          `; From 25a01be995076f66901cf367cef67f094b86f56f Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 09:25:40 +1000 Subject: [PATCH 147/445] Added warning message for missing model information --- InvenTree/templates/js/forms.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 318dfab1b4..7f66a9fd30 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -726,8 +726,9 @@ function initializeRelatedField(name, field, options) { // If the 'model' is specified, hand it off to the custom model render return renderModelData(name, field.model, item, field, options); } else { - // Simply render the 'text' parameter - return item.text; + // Return a simple renderering + console.log(`WARNING: templateResult() missing 'field.model' for '${name}'`); + return `${name} - ${item.id}`; } }, templateSelection: function(item, container) { @@ -736,8 +737,9 @@ function initializeRelatedField(name, field, options) { // If the 'model' is specified, hand it off to the custom model render return renderModelData(name, field.model, item, field, options); } else { - // Simply render the 'text' parameter - return item.text; + // Return a simple renderering + console.log(`WARNING: templateSelection() missing 'field.model' for '${name}'`); + return `${name} - ${item.id}`; } } }); From 0037056ee81058e4941765759103e547656aedb3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 09:26:40 +1000 Subject: [PATCH 148/445] Better default renderer --- InvenTree/templates/js/forms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 7f66a9fd30..e388acf00c 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -801,7 +801,7 @@ function renderModelData(name, model, data, parameters, options) { } else { console.log(`ERROR: Rendering not implemented for model '${model}'`); // Simple text rendering - return data.id; + return `${model} - ID ${data.id}`; } } From 374344d0e2be5064eac9f0025c08a716c9e4aaa5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 09:28:00 +1000 Subject: [PATCH 149/445] Refactor switch statement --- InvenTree/templates/js/forms.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index e388acf00c..b7dc645775 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -913,20 +913,12 @@ function constructInput(name, parameters, options) { func = constructCheckboxInput; break; case 'string': - func = constructTextInput; - break; case 'url': - func = constructTextInput; - break; case 'email': func = constructTextInput; break; case 'integer': - func = constructNumberInput; - break; case 'float': - func = constructNumberInput; - break; case 'decimal': func = constructNumberInput; break; From 9312a5d3b4e104e8dea1c6ddb2c72a00f012c379 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 12:39:39 +1000 Subject: [PATCH 150/445] Correctly render selected value of a related field Ref: https://select2.org/programmatic-control/add-select-clear-items#preselecting-options-in-an-remotely-sourced-ajax-select2 --- InvenTree/templates/js/forms.js | 60 +++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index b7dc645775..fb3963d9e2 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -442,8 +442,7 @@ function updateFieldValues(fields, options) { el.prop('checked', value); break; case 'related field': - // TODO - console.log(`related field '${name}'`); + // TODO? break; default: el.val(value); @@ -721,10 +720,20 @@ function initializeRelatedField(name, field, options) { }, }, templateResult: function(item, container) { + + // Extract 'instance' data passed through from an initial value + // Or, use the raw 'item' data as a backup + var data = item; + + if (item.element && item.element.instance) { + data = item.element.instance; + } + // Custom formatting for the search results if (field.model) { // If the 'model' is specified, hand it off to the custom model render - return renderModelData(name, field.model, item, field, options); + var html = renderModelData(name, field.model, data, field, options); + return $(html); } else { // Return a simple renderering console.log(`WARNING: templateResult() missing 'field.model' for '${name}'`); @@ -732,10 +741,20 @@ function initializeRelatedField(name, field, options) { } }, templateSelection: function(item, container) { + + // Extract 'instance' data passed through from an initial value + // Or, use the raw 'item' data as a backup + var data = item; + + if (item.element && item.element.instance) { + data = item.element.instance; + } + // Custom formatting for selected item if (field.model) { // If the 'model' is specified, hand it off to the custom model render - return renderModelData(name, field.model, item, field, options); + var html = renderModelData(name, field.model, data, field, options); + return $(html); } else { // Return a simple renderering console.log(`WARNING: templateSelection() missing 'field.model' for '${name}'`); @@ -743,6 +762,35 @@ function initializeRelatedField(name, field, options) { } } }); + + // If a 'value' is already defined, grab the model info from the server + if (field.value) { + var pk = field.value; + var url = `${field.api_url}/${pk}/`.replace('//', '/'); + + inventreeGet(url, {}, { + success: function(data) { + + // Create a new option, simply use the model name as the text (for now) + // Note: The correct rendering will be computed later by templateSelection function + var option = new Option(name, data.pk, true, true); + + // Store the returned data as 'instance' parameter of the created option, + // so that it can be retrieved later! + option.instance = data; + + select.append(option).trigger('change'); + + // manually trigger the `select2:select` event + select.trigger({ + type: 'select2:select', + params: { + data: data + } + }); + } + }); + } } @@ -795,9 +843,7 @@ function renderModelData(name, model, data, parameters, options) { } if (html != null) { - // Render HTML to an object - var $state = $(html); - return $state; + return html; } else { console.log(`ERROR: Rendering not implemented for model '${model}'`); // Simple text rendering From f18c2a7a3ddf60ef3c439dbd7657ece60be191a9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 12:48:56 +1000 Subject: [PATCH 151/445] Fix rendering during search --- InvenTree/templates/js/forms.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index fb3963d9e2..dd72031149 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -729,6 +729,10 @@ function initializeRelatedField(name, field, options) { data = item.element.instance; } + if (!data.pk) { + return $(searching()); + } + // Custom formatting for the search results if (field.model) { // If the 'model' is specified, hand it off to the custom model render @@ -750,6 +754,10 @@ function initializeRelatedField(name, field, options) { data = item.element.instance; } + if (!data.pk) { + return $(searching()); + } + // Custom formatting for selected item if (field.model) { // If the 'model' is specified, hand it off to the custom model render @@ -794,6 +802,11 @@ function initializeRelatedField(name, field, options) { } +// Render a 'no results' element +function searching() { + return `{% trans "Searching" %}...`; +} + /* * Render a "foreign key" model reference in a select2 instance. * Allows custom rendering with access to the entire serialized object. From da6d170ce21ddac372777b7c5608f51d8a7edfd4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 19:39:45 +1000 Subject: [PATCH 152/445] Add 'help_text' for related fields --- InvenTree/InvenTree/metadata.py | 3 ++ InvenTree/part/test_api.py | 59 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/InvenTree/InvenTree/metadata.py b/InvenTree/InvenTree/metadata.py index 34490d1079..fa3dee4794 100644 --- a/InvenTree/InvenTree/metadata.py +++ b/InvenTree/InvenTree/metadata.py @@ -127,6 +127,9 @@ class InvenTreeMetadata(SimpleMetadata): # This is used to automatically filter AJAX requests serializer_info[name]['filters'] = relation.model_field.get_limit_choices_to() + if 'help_text' not in serializer_info[name] and hasattr(relation.model_field, 'help_text'): + serializer_info[name]['help_text'] = relation.model_field.help_text + except AttributeError: pass diff --git a/InvenTree/part/test_api.py b/InvenTree/part/test_api.py index 4922ed4e04..3e184c9fe2 100644 --- a/InvenTree/part/test_api.py +++ b/InvenTree/part/test_api.py @@ -16,6 +16,65 @@ from company.models import Company from common.models import InvenTreeSetting +class PartOptionsAPITest(InvenTreeAPITestCase): + """ + Tests for the various OPTIONS endpoints in the /part/ API + + Ensure that the required field details are provided! + """ + + roles = [ + 'part.add', + ] + + def setUp(self): + + super().setUp() + + def test_part(self): + """ + Test the Part API OPTIONS + """ + + actions = self.getActions(reverse('api-part-list'))['POST'] + + # Check that a bunch o' fields are contained + for f in ['assembly', 'component', 'description', 'image', 'IPN']: + self.assertTrue(f in actions.keys()) + + # Active is a 'boolean' field + active = actions['active'] + + self.assertTrue(active['default']) + self.assertEqual(active['help_text'], 'Is this part active?') + self.assertEqual(active['type'], 'boolean') + self.assertEqual(active['read_only'], False) + + # String field + ipn = actions['IPN'] + self.assertEqual(ipn['type'], 'string') + self.assertFalse(ipn['required']) + self.assertEqual(ipn['max_length'], 100) + self.assertEqual(ipn['help_text'], 'Internal Part Number') + + # Related field + category = actions['category'] + + self.assertEqual(category['type'], 'related field') + self.assertTrue(category['required']) + self.assertFalse(category['read_only']) + self.assertEqual(category['label'], 'Category') + self.assertEqual(category['model'], 'partcategory') + self.assertEqual(category['api_url'], reverse('api-part-category-list')) + self.assertEqual(category['help_text'], 'Part category') + + def test_category(self): + pass + + def test_bom_item(self): + pass + + class PartAPITest(InvenTreeAPITestCase): """ Series of tests for the Part DRF API From 4aed6993d4041421bbef047a8db33de784949c9b Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 19:48:49 +1000 Subject: [PATCH 153/445] Add some more unit tests --- InvenTree/part/test_api.py | 45 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/InvenTree/part/test_api.py b/InvenTree/part/test_api.py index 3e184c9fe2..0c1f083383 100644 --- a/InvenTree/part/test_api.py +++ b/InvenTree/part/test_api.py @@ -69,10 +69,51 @@ class PartOptionsAPITest(InvenTreeAPITestCase): self.assertEqual(category['help_text'], 'Part category') def test_category(self): - pass + """ + Test the PartCategory API OPTIONS endpoint + """ + + actions = self.getActions(reverse('api-part-category-list')) + + # actions should *not* contain 'POST' as we do not have the correct role + self.assertFalse('POST' in actions) + + self.assignRole('part_category.add') + + actions = self.getActions(reverse('api-part-category-list'))['POST'] + + name = actions['name'] + + self.assertTrue(name['required']) + self.assertEqual(name['label'], 'Name') + + loc = actions['default_location'] + self.assertEqual(loc['api_url'], reverse('api-location-list')) def test_bom_item(self): - pass + """ + Test the BomItem API OPTIONS endpoint + """ + + actions = self.getActions(reverse('api-bom-list'))['POST'] + + inherited = actions['inherited'] + + self.assertEqual(inherited['type'], 'boolean') + + # 'part' reference + part = actions['part'] + + self.assertTrue(part['required']) + self.assertFalse(part['read_only']) + self.assertTrue(part['filters']['assembly']) + + # 'sub_part' reference + sub_part = actions['sub_part'] + + self.assertTrue(sub_part['required']) + self.assertEqual(sub_part['type'], 'related field') + self.assertTrue(sub_part['filters']['component']) class PartAPITest(InvenTreeAPITestCase): From 981cc2e24e44abd2c7e48512f62936924b98cc81 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 19:51:31 +1000 Subject: [PATCH 154/445] Fix select2 styling --- InvenTree/InvenTree/static/css/inventree.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index 70f4032afe..375e02c8ca 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -979,4 +979,8 @@ input[type="date"].form-control, input[type="time"].form-control, input[type="da max-height: 24px; border-radius: 4px; margin-right: 10px; +} + +.select2-selection { + overflow-y: clip; } \ No newline at end of file From 5230a5a41b5b23306759d7624b4d30b7ce1cd0e9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 19:55:32 +1000 Subject: [PATCH 155/445] Add "success" functionality for form posting --- InvenTree/templates/js/forms.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index dd72031149..8c74def263 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -490,11 +490,21 @@ function handleFormSuccess(response, options) { $(options.modal).modal('hide'); } - if (response.url) { - // GOTO - window.location.href = response.url; + if (options.onSuccess) { + // Callback function + options.onSuccess(response, options); } + if (options.follow && response.url) { + // Follow the returned URL + window.location.href = response.url; + } else if (options.reload) { + // Reload the current page + location.reload(); + } else if (options.redirect) { + // Redirect to a specified URL + window.location.href = options.redirect; + } } From d10169932d635baa5acfb90e3e340ea7108da378 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 29 Jun 2021 12:33:54 +0200 Subject: [PATCH 156/445] option to hide related parts #1733 --- InvenTree/common/models.py | 7 +++++++ InvenTree/part/templates/part/navbar.html | 3 +++ InvenTree/templates/InvenTree/settings/part.html | 1 + 3 files changed, 11 insertions(+) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index ddd27b734e..7e56429c51 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -219,6 +219,13 @@ class InvenTreeSetting(models.Model): 'validator': bool, }, + 'PART_SHOW_RELATED': { + 'name': _('Show related parts'), + 'description': _('Display related parts for a part'), + 'default': True, + 'validator': bool, + }, + 'PART_INTERNAL_PRICE': { 'name': _('Internal Prices'), 'description': _('Enable internal prices for parts'), diff --git a/InvenTree/part/templates/part/navbar.html b/InvenTree/part/templates/part/navbar.html index c0bc4c96a3..1fae6aaec2 100644 --- a/InvenTree/part/templates/part/navbar.html +++ b/InvenTree/part/templates/part/navbar.html @@ -3,6 +3,7 @@ {% load inventree_extras %} {% settings_value "PART_INTERNAL_PRICE" as show_internal_price %} +{% settings_value 'PART_SHOW_RELATED' as show_related %}
          {% include "InvenTree/settings/setting.html" with key="PART_TEMPLATE" icon="fa-clone" %} From cf0feffe26e77d48580e283e2d2e7171c6d6471d Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 20:44:44 +1000 Subject: [PATCH 157/445] Allow override of values from calling function --- InvenTree/company/serializers.py | 1 + .../company/templates/company/index.html | 86 ++++++++----------- InvenTree/company/test_views.py | 15 ---- InvenTree/company/views.py | 4 - InvenTree/templates/js/company.js | 70 +++++++++++++++ InvenTree/templates/js/forms.js | 21 ++++- 6 files changed, 125 insertions(+), 72 deletions(-) diff --git a/InvenTree/company/serializers.py b/InvenTree/company/serializers.py index 1e97756987..3dd4e9334e 100644 --- a/InvenTree/company/serializers.py +++ b/InvenTree/company/serializers.py @@ -70,6 +70,7 @@ class CompanySerializer(InvenTreeModelSerializer): 'phone', 'address', 'email', + 'currency', 'contact', 'link', 'image', diff --git a/InvenTree/company/templates/company/index.html b/InvenTree/company/templates/company/index.html index 796796528f..025251c883 100644 --- a/InvenTree/company/templates/company/index.html +++ b/InvenTree/company/templates/company/index.html @@ -16,10 +16,7 @@ {% if pagetype == 'manufacturers' and roles.purchase_order.add or pagetype == 'suppliers' and roles.purchase_order.add or pagetype == 'customers' and roles.sales_order.add %}
          -
          @@ -32,60 +29,49 @@ {% endblock %} {% block js_ready %} {{ block.super }} - $('#new-company').click(function () { - launchModalForm("{{ create_url }}", { - follow: true - }); - }); - $('#new-company-2').click(function() { + $('#new-company').click(function() { + + createCompany({ + fields: { + is_supplier: { + value: {% if pagetype == 'suppliers' %}true{% else %}false{% endif %}, + }, + is_manufacturer: { + value: {% if pagetype == 'manufacturers' %}true{% else %}false{% endif %}, + }, + is_customer: { + value: {% if pagetype == 'customers' %}true{% else %}false{% endif %}, + }, + } + }); + + return; + constructForm( - '{% url "api-build-list" %}', + '{% url "api-company-list" %}', { method: 'POST', - title: '{% trans "Edit Part Details" %}', + title: '{% trans "Create new Company" %}', + follow: true, fields: { - title: { - prefix: `` - }, - reference: {}, - part: { - filters: { - } - }, - quantity: {}, - /* - name: { - onEdit: function() { - console.log('Edited name field'); - } - }, + name: {}, description: {}, - category: { - filters: { - parent: 1, - }, - secondary: { - label: '{% trans "New Category" %}', - }, + website: {}, + address: {}, + currency: {}, + phone: {}, + email: {}, + contact: {}, + is_supplier: { + value: {% if pagetype == 'suppliers' %}true{% else %}false{% endif %}, }, - active: { - onEdit: function() { - console.log('edited active field'); - } + is_manufacturer: { + value: {% if pagetype == 'manufacturers' %}true{% else %}false{% endif %}, + }, + is_customer: { + value: {% if pagetype == 'customers' %}true{% else %}false{% endif %}, }, - purchaseable: {}, - salable: {}, - component: {}, - 'website', - 'address', - 'phone', - 'email', - 'contact', - 'is_supplier', - 'is_manufacturer', - 'is_customer', - */ } } ); diff --git a/InvenTree/company/test_views.py b/InvenTree/company/test_views.py index cdb2d32af9..a2ef75c688 100644 --- a/InvenTree/company/test_views.py +++ b/InvenTree/company/test_views.py @@ -188,21 +188,6 @@ class CompanyViewTest(CompanyViewTestBase): response = self.client.get(reverse('company-index')) self.assertEqual(response.status_code, 200) - def test_company_create(self): - """ - Test the view for creating a company - """ - - # Check that different company types return different form titles - response = self.client.get(reverse('supplier-create'), HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertContains(response, 'Create new Supplier') - - response = self.client.get(reverse('manufacturer-create'), HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertContains(response, 'Create new Manufacturer') - - response = self.client.get(reverse('customer-create'), HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertContains(response, 'Create new Customer') - class ManufacturerPartViewTests(CompanyViewTestBase): """ diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index 74a583710a..a5cdcd00a0 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -63,21 +63,18 @@ class CompanyIndex(InvenTreeRoleMixin, ListView): 'title': _('Suppliers'), 'button_text': _('New Supplier'), 'filters': {'is_supplier': 'true'}, - 'create_url': reverse('supplier-create'), 'pagetype': 'suppliers', }, reverse('manufacturer-index'): { 'title': _('Manufacturers'), 'button_text': _('New Manufacturer'), 'filters': {'is_manufacturer': 'true'}, - 'create_url': reverse('manufacturer-create'), 'pagetype': 'manufacturers', }, reverse('customer-index'): { 'title': _('Customers'), 'button_text': _('New Customer'), 'filters': {'is_customer': 'true'}, - 'create_url': reverse('customer-create'), 'pagetype': 'customers', } } @@ -86,7 +83,6 @@ class CompanyIndex(InvenTreeRoleMixin, ListView): 'title': _('Companies'), 'button_text': _('New Company'), 'filters': {}, - 'create_url': reverse('company-create'), 'pagetype': 'companies' } diff --git a/InvenTree/templates/js/company.js b/InvenTree/templates/js/company.js index 078b40f4b9..bd9c1cf458 100644 --- a/InvenTree/templates/js/company.js +++ b/InvenTree/templates/js/company.js @@ -1,5 +1,75 @@ {% load i18n %} +/* + * Launches a form to create a new company. + * As this can be called from many different contexts, + * we abstract it here! + */ +function createCompany(options={}) { + + // Default field set + var fields = { + name: {}, + description: {}, + website: {}, + address: {}, + currency: {}, + phone: {}, + email: {}, + contact: {}, + is_supplier: {}, + is_manufacturer: {}, + is_customer: {} + }; + + // Override / update default fields as required + fields = Object.assign(fields, options.fields || {}); + + constructForm( + '{% url "api-company-list" %}', + { + method: 'POST', + fields: fields, + follow: true, + title: '{% trans "Add new Company" %}', + } + ); +} + + +// Launch form to create a new manufacturer part +function createManufacturerPart(options={}) { + + var fields = { + 'part': { + secondary: { + label: '{% trans "New Part" %}', + } + }, + 'manufacturer': { + secondary: { + label: '{% trans "New Manufacturer" %}', + } + }, + 'MPN': {}, + 'description': {}, + 'link': {}, + }; + + fields = Object.assign(fields, options.fields || {}); + + constructForm( + '{% url "api-manufacturer-part-list" %}', + { + fields: fields, + method: 'POST', + follow: true, + title: '{% trans "Add new Manufacturer Part" %}', + } + ); +} + + function loadCompanyTable(table, url, options={}) { /* * Load company listing data into specified table. diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 8c74def263..e2ccb096b3 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -109,14 +109,24 @@ function getApiEndpointOptions(url, callback, options) { * - */ function constructCreateForm(fields, options) { - + // Check if default values were provided for any fields for (const name in fields) { var field = fields[name]; - if (field.default != null) { - field.value = field.default; + var field_options = options.fields[name] || {}; + + // If a 'value' is not provided for the field, + if (field.value == null) { + + if ('value' in field_options) { + // Client has specified the default value for the field + field.value = field_options.value; + } else if (field.default != null) { + // OPTIONS endpoint provided default value for this field + field.value = field.default; + } } } @@ -278,6 +288,11 @@ function constructFormBody(fields, options) { // Field prefix fields[field].prefix = field_options.prefix; + + // // Field value? + // if (fields[field].value == null) { + // fields[field].value = field_options.value; + // } } } From c25967eff678b1082b27883e2e3e6c5fde96eb77 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 21:17:48 +1000 Subject: [PATCH 158/445] Replace CompanyCreate and CompanyEdit forms with AJAX form - Adds the ability to specify an "icon" for each field --- .../templates/company/company_base.html | 6 +- .../company/templates/company/index.html | 49 +++----------- InvenTree/company/views.py | 20 ++---- InvenTree/templates/js/company.js | 64 ++++++++++++++----- InvenTree/templates/js/forms.js | 7 +- 5 files changed, 67 insertions(+), 79 deletions(-) diff --git a/InvenTree/company/templates/company/company_base.html b/InvenTree/company/templates/company/company_base.html index a276f5df4f..197ddbf75e 100644 --- a/InvenTree/company/templates/company/company_base.html +++ b/InvenTree/company/templates/company/company_base.html @@ -111,11 +111,7 @@ }); $('#company-edit').click(function() { - launchModalForm( - "{% url 'company-edit' company.id %}", - { - reload: true - }); + editCompany({{ company.id }}); }); $("#company-order-2").click(function() { diff --git a/InvenTree/company/templates/company/index.html b/InvenTree/company/templates/company/index.html index 025251c883..672d82fdb7 100644 --- a/InvenTree/company/templates/company/index.html +++ b/InvenTree/company/templates/company/index.html @@ -32,49 +32,16 @@ $('#new-company').click(function() { + var fields = companyFormFields(); + + // Field overrides + fields.is_supplier.value = {% if pagetype == 'suppliers' %}true{% else %}false{% endif %}; + fields.is_manufacturer.value = {% if pagetype == 'manufacturers' %}true{% else %}false{% endif %}; + fields.is_customer.value = {% if pagetype == 'customers' %}true{% else %}false{% endif %}; + createCompany({ - fields: { - is_supplier: { - value: {% if pagetype == 'suppliers' %}true{% else %}false{% endif %}, - }, - is_manufacturer: { - value: {% if pagetype == 'manufacturers' %}true{% else %}false{% endif %}, - }, - is_customer: { - value: {% if pagetype == 'customers' %}true{% else %}false{% endif %}, - }, - } + fields: fields, }); - - return; - - constructForm( - '{% url "api-company-list" %}', - { - method: 'POST', - title: '{% trans "Create new Company" %}', - follow: true, - fields: { - name: {}, - description: {}, - website: {}, - address: {}, - currency: {}, - phone: {}, - email: {}, - contact: {}, - is_supplier: { - value: {% if pagetype == 'suppliers' %}true{% else %}false{% endif %}, - }, - is_manufacturer: { - value: {% if pagetype == 'manufacturers' %}true{% else %}false{% endif %}, - }, - is_customer: { - value: {% if pagetype == 'customers' %}true{% else %}false{% endif %}, - }, - } - } - ); }); loadCompanyTable("#company-table", "{% url 'api-company-list' %}", diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index a5cdcd00a0..c42e3e2465 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -246,23 +246,11 @@ class CompanyImage(AjaxUpdateView): } -class CompanyEdit(AjaxUpdateView): - """ View for editing a Company object """ - model = Company - form_class = EditCompanyForm - context_object_name = 'company' - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Edit Company') - permission_required = 'company.change_company' - - def get_data(self): - return { - 'info': _('Edited company information'), - } - - class CompanyCreate(AjaxCreateView): - """ View for creating a new Company object """ + """ + View for creating a new Company object + """ + model = Company context_object_name = 'company' form_class = EditCompanyForm diff --git a/InvenTree/templates/js/company.js b/InvenTree/templates/js/company.js index bd9c1cf458..b069901ce1 100644 --- a/InvenTree/templates/js/company.js +++ b/InvenTree/templates/js/company.js @@ -1,5 +1,52 @@ {% load i18n %} + +// Returns a default form-set for creating / editing a Company object +function companyFormFields(options={}) { + + return { + name: {}, + description: {}, + website: { + icon: 'fa-globe', + }, + address: { + icon: 'fa-envelope', + }, + currency: { + icon: 'fa-dollar-sign', + }, + phone: { + icon: 'fa-phone', + }, + email: { + icon: 'fa-at', + }, + contact: { + icon: 'fa-address-card', + }, + is_supplier: {}, + is_manufacturer: {}, + is_customer: {} + }; +} + + +function editCompany(pk, options={}) { + + var fields = options.fields || companyFormFields(); + + constructForm( + `/api/company/${pk}/`, + { + method: 'PATCH', + fields: fields, + reload: true, + title: '{% trans "Edit Company" %}', + } + ); +}; + /* * Launches a form to create a new company. * As this can be called from many different contexts, @@ -8,22 +55,7 @@ function createCompany(options={}) { // Default field set - var fields = { - name: {}, - description: {}, - website: {}, - address: {}, - currency: {}, - phone: {}, - email: {}, - contact: {}, - is_supplier: {}, - is_manufacturer: {}, - is_customer: {} - }; - - // Override / update default fields as required - fields = Object.assign(fields, options.fields || {}); + var fields = options.fields || companyFormFields(); constructForm( '{% url "api-company-list" %}', diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index e2ccb096b3..e96f9dee2a 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -287,7 +287,12 @@ function constructFormBody(fields, options) { fields[field].onEdit = field_options.onEdit; // Field prefix - fields[field].prefix = field_options.prefix; + if (field_options.prefix) { + fields[field].prefix = field_options.prefix; + } else if (field_options.icon) { + // Specify icon like 'fa-user' + fields[field].prefix = ``; + } // // Field value? // if (fields[field].value == null) { From 170ed37d033bb72b71b045f8e43334a5cd3a7ba1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 21:20:53 +1000 Subject: [PATCH 159/445] Delete CompanyCreate AJAX view --- .../company/detail_manufacturer_part.html | 2 +- .../company/detail_supplier_part.html | 2 +- .../company/manufacturer_part_suppliers.html | 2 +- InvenTree/company/urls.py | 6 -- InvenTree/company/views.py | 55 ------------------- .../templates/order/purchase_orders.html | 2 +- .../order/templates/order/sales_orders.html | 2 +- .../part/templates/part/manufacturer.html | 2 +- InvenTree/part/templates/part/supplier.html | 4 +- 9 files changed, 8 insertions(+), 69 deletions(-) diff --git a/InvenTree/company/templates/company/detail_manufacturer_part.html b/InvenTree/company/templates/company/detail_manufacturer_part.html index 902d456eaf..9916d597ed 100644 --- a/InvenTree/company/templates/company/detail_manufacturer_part.html +++ b/InvenTree/company/templates/company/detail_manufacturer_part.html @@ -71,7 +71,7 @@ field: 'manufacturer', label: '{% trans "New Manufacturer" %}', title: '{% trans "Create new Manufacturer" %}', - url: "{% url 'manufacturer-create' %}", + //url: "{% url 'manufacturer-create' %}", }, ] }); diff --git a/InvenTree/company/templates/company/detail_supplier_part.html b/InvenTree/company/templates/company/detail_supplier_part.html index bf92f96843..d12e53aeca 100644 --- a/InvenTree/company/templates/company/detail_supplier_part.html +++ b/InvenTree/company/templates/company/detail_supplier_part.html @@ -71,7 +71,7 @@ field: 'supplier', label: "{% trans 'New Supplier' %}", title: "{% trans 'Create new Supplier' %}", - url: "{% url 'supplier-create' %}", + // url: "{% url 'supplier-create' %}", }, ] }); diff --git a/InvenTree/company/templates/company/manufacturer_part_suppliers.html b/InvenTree/company/templates/company/manufacturer_part_suppliers.html index 9f445ec215..440d43d646 100644 --- a/InvenTree/company/templates/company/manufacturer_part_suppliers.html +++ b/InvenTree/company/templates/company/manufacturer_part_suppliers.html @@ -81,7 +81,7 @@ $('#supplier-create').click(function () { field: 'supplier', label: '{% trans "New Supplier" %}', title: '{% trans "Create new supplier" %}', - url: "{% url 'supplier-create' %}" + // url: "{% url 'supplier-create' %}" }, ] }); diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index 51aa81f1c7..0aa4d39364 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -8,7 +8,6 @@ from . import views company_detail_urls = [ - url(r'edit/?', views.CompanyEdit.as_view(), name='company-edit'), url(r'delete/?', views.CompanyDelete.as_view(), name='company-delete'), # url(r'orders/?', views.CompanyDetail.as_view(template_name='company/orders.html'), name='company-detail-orders'), @@ -31,11 +30,6 @@ company_detail_urls = [ company_urls = [ - url(r'new/supplier/', views.CompanyCreate.as_view(), name='supplier-create'), - url(r'new/manufacturer/', views.CompanyCreate.as_view(), name='manufacturer-create'), - url(r'new/customer/', views.CompanyCreate.as_view(), name='customer-create'), - url(r'new/?', views.CompanyCreate.as_view(), name='company-create'), - url(r'^(?P\d+)/', include(company_detail_urls)), url(r'suppliers/', views.CompanyIndex.as_view(), name='supplier-index'), diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index c42e3e2465..7d8440f9de 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -246,61 +246,6 @@ class CompanyImage(AjaxUpdateView): } -class CompanyCreate(AjaxCreateView): - """ - View for creating a new Company object - """ - - model = Company - context_object_name = 'company' - form_class = EditCompanyForm - ajax_template_name = 'modal_form.html' - permission_required = 'company.add_company' - - def get_form_title(self): - - url = self.request.path - - if url == reverse('supplier-create'): - return _("Create new Supplier") - - if url == reverse('manufacturer-create'): - return _('Create new Manufacturer') - - if url == reverse('customer-create'): - return _('Create new Customer') - - return _('Create new Company') - - def get_initial(self): - """ Initial values for the form data """ - initials = super().get_initial().copy() - - url = self.request.path - - if url == reverse('supplier-create'): - initials['is_supplier'] = True - initials['is_customer'] = False - initials['is_manufacturer'] = False - - elif url == reverse('manufacturer-create'): - initials['is_manufacturer'] = True - initials['is_supplier'] = True - initials['is_customer'] = False - - elif url == reverse('customer-create'): - initials['is_customer'] = True - initials['is_manufacturer'] = False - initials['is_supplier'] = False - - return initials - - def get_data(self): - return { - 'success': _("Created new company"), - } - - class CompanyDelete(AjaxDeleteView): """ View for deleting a Company object """ diff --git a/InvenTree/order/templates/order/purchase_orders.html b/InvenTree/order/templates/order/purchase_orders.html index a2a5d5d0fa..3eec3d3a2f 100644 --- a/InvenTree/order/templates/order/purchase_orders.html +++ b/InvenTree/order/templates/order/purchase_orders.html @@ -184,7 +184,7 @@ $("#po-create").click(function() { field: 'supplier', label: '{% trans "New Supplier" %}', title: '{% trans "Create new Supplier" %}', - url: '{% url "supplier-create" %}', + // url: '{% url "supplier-create" %}', } ] } diff --git a/InvenTree/order/templates/order/sales_orders.html b/InvenTree/order/templates/order/sales_orders.html index 448ab4b095..2cec25b3d2 100644 --- a/InvenTree/order/templates/order/sales_orders.html +++ b/InvenTree/order/templates/order/sales_orders.html @@ -186,7 +186,7 @@ $("#so-create").click(function() { field: 'customer', label: '{% trans "New Customer" %}', title: '{% trans "Create new Customer" %}', - url: '{% url "customer-create" %}', + // url: '{% url "customer-create" %}', } ] } diff --git a/InvenTree/part/templates/part/manufacturer.html b/InvenTree/part/templates/part/manufacturer.html index 82f02ba85f..4460ad9fe2 100644 --- a/InvenTree/part/templates/part/manufacturer.html +++ b/InvenTree/part/templates/part/manufacturer.html @@ -51,7 +51,7 @@ field: 'manufacturer', label: '{% trans "New Manufacturer" %}', title: '{% trans "Create new manufacturer" %}', - url: "{% url 'manufacturer-create' %}", + // url: "{% url 'manufacturer-create' %}", } ] }); diff --git a/InvenTree/part/templates/part/supplier.html b/InvenTree/part/templates/part/supplier.html index 45d2d1d55c..7959bb79bb 100644 --- a/InvenTree/part/templates/part/supplier.html +++ b/InvenTree/part/templates/part/supplier.html @@ -49,13 +49,13 @@ field: 'supplier', label: '{% trans "New Supplier" %}', title: '{% trans "Create new supplier" %}', - url: "{% url 'supplier-create' %}" + // url: "{% url 'supplier-create' %}" }, { field: 'manufacturer', label: '{% trans "New Manufacturer" %}', title: '{% trans "Create new manufacturer" %}', - url: "{% url 'manufacturer-create' %}", + // url: "{% url 'manufacturer-create' %}", } ] }); From 6156fffd1def322557e125f2371eebacc7eb00e0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 21:25:20 +1000 Subject: [PATCH 160/445] Remove broken URLs --- .../company/templates/company/detail_manufacturer_part.html | 1 - InvenTree/company/templates/company/detail_supplier_part.html | 1 - .../company/templates/company/manufacturer_part_suppliers.html | 1 - InvenTree/order/templates/order/purchase_orders.html | 1 - InvenTree/order/templates/order/sales_orders.html | 1 - InvenTree/part/templates/part/manufacturer.html | 1 - InvenTree/part/templates/part/supplier.html | 2 -- 7 files changed, 8 deletions(-) diff --git a/InvenTree/company/templates/company/detail_manufacturer_part.html b/InvenTree/company/templates/company/detail_manufacturer_part.html index 9916d597ed..a162334040 100644 --- a/InvenTree/company/templates/company/detail_manufacturer_part.html +++ b/InvenTree/company/templates/company/detail_manufacturer_part.html @@ -71,7 +71,6 @@ field: 'manufacturer', label: '{% trans "New Manufacturer" %}', title: '{% trans "Create new Manufacturer" %}', - //url: "{% url 'manufacturer-create' %}", }, ] }); diff --git a/InvenTree/company/templates/company/detail_supplier_part.html b/InvenTree/company/templates/company/detail_supplier_part.html index d12e53aeca..1cb9a2ad38 100644 --- a/InvenTree/company/templates/company/detail_supplier_part.html +++ b/InvenTree/company/templates/company/detail_supplier_part.html @@ -71,7 +71,6 @@ field: 'supplier', label: "{% trans 'New Supplier' %}", title: "{% trans 'Create new Supplier' %}", - // url: "{% url 'supplier-create' %}", }, ] }); diff --git a/InvenTree/company/templates/company/manufacturer_part_suppliers.html b/InvenTree/company/templates/company/manufacturer_part_suppliers.html index 440d43d646..59969d9708 100644 --- a/InvenTree/company/templates/company/manufacturer_part_suppliers.html +++ b/InvenTree/company/templates/company/manufacturer_part_suppliers.html @@ -81,7 +81,6 @@ $('#supplier-create').click(function () { field: 'supplier', label: '{% trans "New Supplier" %}', title: '{% trans "Create new supplier" %}', - // url: "{% url 'supplier-create' %}" }, ] }); diff --git a/InvenTree/order/templates/order/purchase_orders.html b/InvenTree/order/templates/order/purchase_orders.html index 3eec3d3a2f..15d58788bc 100644 --- a/InvenTree/order/templates/order/purchase_orders.html +++ b/InvenTree/order/templates/order/purchase_orders.html @@ -184,7 +184,6 @@ $("#po-create").click(function() { field: 'supplier', label: '{% trans "New Supplier" %}', title: '{% trans "Create new Supplier" %}', - // url: '{% url "supplier-create" %}', } ] } diff --git a/InvenTree/order/templates/order/sales_orders.html b/InvenTree/order/templates/order/sales_orders.html index 2cec25b3d2..bfa6d85a9d 100644 --- a/InvenTree/order/templates/order/sales_orders.html +++ b/InvenTree/order/templates/order/sales_orders.html @@ -186,7 +186,6 @@ $("#so-create").click(function() { field: 'customer', label: '{% trans "New Customer" %}', title: '{% trans "Create new Customer" %}', - // url: '{% url "customer-create" %}', } ] } diff --git a/InvenTree/part/templates/part/manufacturer.html b/InvenTree/part/templates/part/manufacturer.html index 4460ad9fe2..dc04efc503 100644 --- a/InvenTree/part/templates/part/manufacturer.html +++ b/InvenTree/part/templates/part/manufacturer.html @@ -51,7 +51,6 @@ field: 'manufacturer', label: '{% trans "New Manufacturer" %}', title: '{% trans "Create new manufacturer" %}', - // url: "{% url 'manufacturer-create' %}", } ] }); diff --git a/InvenTree/part/templates/part/supplier.html b/InvenTree/part/templates/part/supplier.html index 7959bb79bb..c0486cc42a 100644 --- a/InvenTree/part/templates/part/supplier.html +++ b/InvenTree/part/templates/part/supplier.html @@ -49,13 +49,11 @@ field: 'supplier', label: '{% trans "New Supplier" %}', title: '{% trans "Create new supplier" %}', - // url: "{% url 'supplier-create' %}" }, { field: 'manufacturer', label: '{% trans "New Manufacturer" %}', title: '{% trans "Create new manufacturer" %}', - // url: "{% url 'manufacturer-create' %}", } ] }); From 8b3a49755419e25c10c31e1c03a914bfdddd26f0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 23:05:37 +1000 Subject: [PATCH 161/445] Remove unused Form --- InvenTree/company/forms.py | 36 -------------------------------- InvenTree/company/serializers.py | 2 ++ InvenTree/company/views.py | 2 +- 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/InvenTree/company/forms.py b/InvenTree/company/forms.py index 80673b4fa4..9da15a63e1 100644 --- a/InvenTree/company/forms.py +++ b/InvenTree/company/forms.py @@ -22,42 +22,6 @@ from .models import SupplierPart from .models import SupplierPriceBreak -class EditCompanyForm(HelperForm): - """ Form for editing a Company object """ - - field_prefix = { - 'website': 'fa-globe-asia', - 'email': 'fa-at', - 'address': 'fa-envelope', - 'contact': 'fa-user-tie', - 'phone': 'fa-phone', - } - - currency = django.forms.ChoiceField( - required=False, - label=_('Currency'), - help_text=_('Default currency used for this company'), - choices=[('', '----------')] + djmoney.settings.CURRENCY_CHOICES, - initial=currency_code_default, - ) - - class Meta: - model = Company - fields = [ - 'name', - 'description', - 'website', - 'address', - 'currency', - 'phone', - 'email', - 'contact', - 'is_supplier', - 'is_manufacturer', - 'is_customer', - ] - - class CompanyImageForm(HelperForm): """ Form for uploading a Company image """ diff --git a/InvenTree/company/serializers.py b/InvenTree/company/serializers.py index 3dd4e9334e..dd3175239b 100644 --- a/InvenTree/company/serializers.py +++ b/InvenTree/company/serializers.py @@ -6,6 +6,8 @@ from rest_framework import serializers from sql_util.utils import SubqueryCount +import djmoney.settings + from InvenTree.serializers import InvenTreeModelSerializer from InvenTree.serializers import InvenTreeImageSerializerField diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index 7d8440f9de..5a887d9d38 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -30,7 +30,7 @@ from .models import SupplierPriceBreak from part.models import Part -from .forms import EditCompanyForm, EditManufacturerPartParameterForm +from .forms import EditManufacturerPartParameterForm from .forms import CompanyImageForm from .forms import EditManufacturerPartForm from .forms import EditSupplierPartForm From 33ec91acc7e1b4a757c1da9c19b2d448686e1a6b Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Jun 2021 23:14:39 +1000 Subject: [PATCH 162/445] Add "default" from serializer field (if present) - Overrides model default - Set choices for currency serializer field - Adds some unit testing --- InvenTree/InvenTree/metadata.py | 5 +++ InvenTree/company/forms.py | 1 - InvenTree/company/models.py | 6 ++- InvenTree/company/serializers.py | 7 ++++ InvenTree/company/test_api.py | 69 +++++++++++++++++++++++++++++++- 5 files changed, 85 insertions(+), 3 deletions(-) diff --git a/InvenTree/InvenTree/metadata.py b/InvenTree/InvenTree/metadata.py index fa3dee4794..24e4dab7d7 100644 --- a/InvenTree/InvenTree/metadata.py +++ b/InvenTree/InvenTree/metadata.py @@ -7,6 +7,7 @@ import logging from rest_framework import serializers from rest_framework.metadata import SimpleMetadata from rest_framework.utils import model_meta +from rest_framework.fields import empty import users.models @@ -146,6 +147,10 @@ class InvenTreeMetadata(SimpleMetadata): # Run super method first field_info = super().get_field_info(field) + # If a default value is specified for the serializer field, add it! + if 'default' not in field_info and not field.default == empty: + field_info['default'] = field.get_default() + # Introspect writable related fields if field_info['type'] == 'field' and not field_info['read_only']: diff --git a/InvenTree/company/forms.py b/InvenTree/company/forms.py index 9da15a63e1..68e32628b4 100644 --- a/InvenTree/company/forms.py +++ b/InvenTree/company/forms.py @@ -11,7 +11,6 @@ from InvenTree.fields import RoundingDecimalFormField from django.utils.translation import ugettext_lazy as _ import django.forms -import djmoney.settings from djmoney.forms.fields import MoneyField from common.settings import currency_code_default diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index 1c2306fc6a..58cfbe7011 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -105,7 +105,11 @@ class Company(models.Model): blank=True, ) - website = models.URLField(blank=True, verbose_name=_('Website'), help_text=_('Company website URL')) + website = models.URLField( + blank=True, + verbose_name=_('Website'), + help_text=_('Company website URL') + ) address = models.CharField(max_length=200, verbose_name=_('Address'), diff --git a/InvenTree/company/serializers.py b/InvenTree/company/serializers.py index dd3175239b..9e64fbad0a 100644 --- a/InvenTree/company/serializers.py +++ b/InvenTree/company/serializers.py @@ -17,6 +17,8 @@ from .models import Company from .models import ManufacturerPart, ManufacturerPartParameter from .models import SupplierPart, SupplierPriceBreak +from common.settings import currency_code_default + class CompanyBriefSerializer(InvenTreeModelSerializer): """ Serializer for Company object (limited detail) """ @@ -60,6 +62,11 @@ class CompanySerializer(InvenTreeModelSerializer): parts_supplied = serializers.IntegerField(read_only=True) parts_manufactured = serializers.IntegerField(read_only=True) + currency = serializers.ChoiceField( + choices=djmoney.settings.CURRENCY_CHOICES, + default=currency_code_default, + ) + class Meta: model = Company fields = [ diff --git a/InvenTree/company/test_api.py b/InvenTree/company/test_api.py index dd42b97801..345f4bf1a4 100644 --- a/InvenTree/company/test_api.py +++ b/InvenTree/company/test_api.py @@ -62,12 +62,79 @@ class CompanyTest(InvenTreeAPITestCase): self.assertEqual(response.data['name'], 'ACMOO') def test_company_search(self): - # Test search functionality in company list + """ + Test search functionality in company list + """ + url = reverse('api-company-list') data = {'search': 'cup'} response = self.get(url, data) self.assertEqual(len(response.data), 2) + def test_company_create(self): + """ + Test that we can create a company via the API! + """ + + url = reverse('api-company-list') + + # Name is required + response = self.post( + url, + { + 'description': 'A description!', + }, + expected_code=400 + ) + + # Minimal example, checking default values + response = self.post( + url, + { + 'name': 'My API Company', + 'description': 'A company created via the API', + }, + expected_code=201 + ) + + self.assertTrue(response.data['is_supplier']) + self.assertFalse(response.data['is_customer']) + self.assertFalse(response.data['is_manufacturer']) + + self.assertEqual(response.data['currency'], 'USD') + + # Maximal example, specify values + response = self.post( + url, + { + 'name': "Another Company", + 'description': "Also created via the API!", + 'currency': 'AUD', + 'is_supplier': False, + 'is_manufacturer': True, + 'is_customer': True, + }, + expected_code=201 + ) + + self.assertEqual(response.data['currency'], 'AUD') + self.assertFalse(response.data['is_supplier']) + self.assertTrue(response.data['is_customer']) + self.assertTrue(response.data['is_manufacturer']) + + # Attempt to create with invalid currency + response = self.post( + url, + { + 'name': "A name", + 'description': 'A description', + 'currency': 'POQD', + }, + expected_code=400 + ) + + self.assertTrue('currency' in response.data) + class ManufacturerTest(InvenTreeAPITestCase): """ From 293b5d4c071041dd849691fd2203e88af548584f Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 00:13:53 +1000 Subject: [PATCH 163/445] Allow file and image fields - Use FormData class - Replace existing Company image upload form --- .../templates/company/company_base.html | 18 +++++- InvenTree/company/urls.py | 1 - InvenTree/company/views.py | 14 ----- InvenTree/templates/js/company.js | 33 ----------- InvenTree/templates/js/forms.js | 58 ++++++++++++++++--- 5 files changed, 65 insertions(+), 59 deletions(-) diff --git a/InvenTree/company/templates/company/company_base.html b/InvenTree/company/templates/company/company_base.html index 197ddbf75e..52d5abf3e6 100644 --- a/InvenTree/company/templates/company/company_base.html +++ b/InvenTree/company/templates/company/company_base.html @@ -157,10 +157,22 @@ {% endif %} $("#company-image-upload").click(function() { - launchModalForm( - "{% url 'company-image' company.id %}", + + constructForm( + '{% url "api-company-detail" company.pk %}', { - reload: true + method: 'PATCH', + fields: { + image: {}, + }, + title: '{% trans "Upload Image" %}', + onSuccess: function(data) { + if (data.image) { + $('#company-image').attr('src', data.image); + } else { + location.reload(); + } + } } ); }); diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index 0aa4d39364..51685215b6 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -20,7 +20,6 @@ company_detail_urls = [ url(r'^sales-orders/', views.CompanyDetail.as_view(template_name='company/sales_orders.html'), name='company-detail-sales-orders'), url(r'^notes/', views.CompanyNotes.as_view(), name='company-notes'), - url(r'^thumbnail/', views.CompanyImage.as_view(), name='company-image'), url(r'^thumb-download/', views.CompanyImageDownloadFromURL.as_view(), name='company-image-download'), # Any other URL diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index 5a887d9d38..8416ce2e3f 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -232,20 +232,6 @@ class CompanyImageDownloadFromURL(AjaxUpdateView): ) -class CompanyImage(AjaxUpdateView): - """ View for uploading an image for the Company """ - model = Company - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Update Company Image') - form_class = CompanyImageForm - permission_required = 'company.change_company' - - def get_data(self): - return { - 'success': _('Updated company image'), - } - - class CompanyDelete(AjaxDeleteView): """ View for deleting a Company object """ diff --git a/InvenTree/templates/js/company.js b/InvenTree/templates/js/company.js index b069901ce1..96beb0a041 100644 --- a/InvenTree/templates/js/company.js +++ b/InvenTree/templates/js/company.js @@ -69,39 +69,6 @@ function createCompany(options={}) { } -// Launch form to create a new manufacturer part -function createManufacturerPart(options={}) { - - var fields = { - 'part': { - secondary: { - label: '{% trans "New Part" %}', - } - }, - 'manufacturer': { - secondary: { - label: '{% trans "New Manufacturer" %}', - } - }, - 'MPN': {}, - 'description': {}, - 'link': {}, - }; - - fields = Object.assign(fields, options.fields || {}); - - constructForm( - '{% url "api-manufacturer-part-list" %}', - { - fields: fields, - method: 'POST', - follow: true, - title: '{% trans "Add new Manufacturer Part" %}', - } - ); -} - - function loadCompanyTable(table, url, options={}) { /* * Load company listing data into specified table. diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index e96f9dee2a..535391d2e1 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -350,8 +350,8 @@ function constructFormBody(fields, options) { // Set the form title and button labels modalSetTitle(modal, options.title || '{% trans "Form Title" %}'); - modalSetSubmitText(options.submitText || '{% trans "Submit" %}'); - modalSetCloseText(options.cancelText || '{% trans "Cancel" %}'); + modalSetSubmitText(modal, options.submitText || '{% trans "Submit" %}'); + modalSetCloseText(modal, options.cancelText || '{% trans "Cancel" %}'); // Insert generated form content $(modal).find('.modal-form-content').html(html); @@ -387,8 +387,8 @@ function constructFormBody(fields, options) { */ function submitFormData(fields, options) { - // Data to be sent to the server - var data = {}; + // Form data to be uploaded to the server + var form_data = new FormData(); // Extract values for each field options.field_names.forEach(function(name) { @@ -399,16 +399,32 @@ function submitFormData(fields, options) { var value = getFormFieldValue(name, field, options); - data[name] = value; + // Handle file inputs + if (field.type == 'image upload' || field.type == 'file upload') { + + var field_el = $(options.modal).find(`#id_${name}`)[0]; + + var field_files = field_el.files; + + if (field_files.length > 0) { + // One file per field, please! + var file = field_files[0]; + + form_data.append(name, file); + } + } else { + // Normal field (not a file or image) + form_data.append(name, value); + } } else { console.log(`WARNING: Could not find field matching '${name}'`); } }); // Submit data - inventreePut( + inventreeFormDataUpload( options.url, - data, + form_data, { method: options.method, success: function(response, status) { @@ -464,6 +480,9 @@ function updateFieldValues(fields, options) { case 'related field': // TODO? break; + case 'file upload': + case 'image upload': + break; default: el.val(value); break; @@ -1017,6 +1036,10 @@ function constructInput(name, parameters, options) { case 'related field': func = constructRelatedFieldInput; break; + case 'image upload': + case 'file upload': + func = constructFileUploadInput; + break; default: // Unsupported field type! break; @@ -1101,7 +1124,6 @@ function constructCheckboxInput(name, parameters, options) { 'checkbox', parameters ); - } @@ -1193,6 +1215,26 @@ function constructRelatedFieldInput(name, parameters, options) { } +/* + * Construct a field for file upload + */ +function constructFileUploadInput(name, parameters, options) { + + var cls = 'clearablefileinput'; + + if (parameters.required) { + cls = 'fileinput'; + } + + return constructInputOptions( + name, + cls, + 'file', + parameters + ); +} + + /* * Construct a 'help text' div based on the field parameters * From 26eafe242c18eca230cf4d2d5a3e9a54610f9fe9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 00:18:25 +1000 Subject: [PATCH 164/445] Replace PartImageUpload form --- .../templates/company/company_base.html | 21 ++++++------ InvenTree/part/templates/part/part_base.html | 34 +++++++++++++------ InvenTree/part/urls.py | 1 - InvenTree/part/views.py | 15 -------- 4 files changed, 33 insertions(+), 38 deletions(-) diff --git a/InvenTree/company/templates/company/company_base.html b/InvenTree/company/templates/company/company_base.html index 52d5abf3e6..88b9f2958d 100644 --- a/InvenTree/company/templates/company/company_base.html +++ b/InvenTree/company/templates/company/company_base.html @@ -133,6 +133,14 @@ }); }); + function reloadImage(data) { + if (data.image) { + $('#company-image').attr('src', data.image); + } else { + location.reload(); + } + } + enableDragAndDrop( "#company-thumb", "{% url 'api-company-detail' company.id %}", @@ -140,12 +148,7 @@ label: 'image', method: 'PATCH', success: function(data, status, xhr) { - - if (data.image) { - $('#company-image').attr('src', data.image); - } else { - location.reload(); - } + reloadImage(data); } } ); @@ -167,11 +170,7 @@ }, title: '{% trans "Upload Image" %}', onSuccess: function(data) { - if (data.image) { - $('#company-image').attr('src', data.image); - } else { - location.reload(); - } + reloadImage(data); } } ); diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index b486e2c589..922ff01912 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -237,6 +237,16 @@ }); {% endif %} + function reloadImage(data) { + // If image / thumbnail data present, live update + if (data.image) { + $('#part-image').attr('src', data.image); + } else { + // Otherwise, reload the page + location.reload(); + } + } + enableDragAndDrop( '#part-thumb', "{% url 'api-part-detail' part.id %}", @@ -244,14 +254,7 @@ label: 'image', method: 'PATCH', success: function(data, status, xhr) { - - // If image / thumbnail data present, live update - if (data.image) { - $('#part-image').attr('src', data.image); - } else { - // Otherwise, reload the page - location.reload(); - } + reloadImage(data); } } ); @@ -293,11 +296,20 @@ }); $("#part-image-upload").click(function() { - launchModalForm("{% url 'part-image-upload' part.id %}", + + constructForm( + '{% url "api-part-detail" part.pk %}', { - reload: true + method: 'PATCH', + fields: { + image: {}, + }, + title: '{% trans "Upload Image" %}', + onSuccess: function(data) { + reloadImage(data); + } } - ); + ) }); diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index c35786e5d3..fb4a1ab9eb 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -81,7 +81,6 @@ part_detail_urls = [ url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'), # Normal thumbnail with form - url(r'^thumbnail/?', views.PartImageUpload.as_view(), name='part-image-upload'), url(r'^thumb-select/?', views.PartImageSelect.as_view(), name='part-image-select'), url(r'^thumb-download/', views.PartImageDownloadFromURL.as_view(), name='part-image-download'), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 2f129dd30b..9998a12783 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -1186,21 +1186,6 @@ class PartImageDownloadFromURL(AjaxUpdateView): ) -class PartImageUpload(AjaxUpdateView): - """ View for uploading a new Part image """ - - model = Part - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Upload Part Image') - - form_class = part_forms.PartImageForm - - def get_data(self): - return { - 'success': _('Updated part image'), - } - - class PartImageSelect(AjaxUpdateView): """ View for selecting Part image from existing images. """ From c425f36a355e336110fd3e1ea12b3675574f5ee4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 00:24:27 +1000 Subject: [PATCH 165/445] Remove dead class --- InvenTree/company/forms.py | 10 ---------- InvenTree/company/views.py | 1 - 2 files changed, 11 deletions(-) diff --git a/InvenTree/company/forms.py b/InvenTree/company/forms.py index 68e32628b4..3b54f3dc61 100644 --- a/InvenTree/company/forms.py +++ b/InvenTree/company/forms.py @@ -21,16 +21,6 @@ from .models import SupplierPart from .models import SupplierPriceBreak -class CompanyImageForm(HelperForm): - """ Form for uploading a Company image """ - - class Meta: - model = Company - fields = [ - 'image' - ] - - class CompanyImageDownloadForm(HelperForm): """ Form for downloading an image from a URL diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index 8416ce2e3f..1b817fe66d 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -31,7 +31,6 @@ from .models import SupplierPriceBreak from part.models import Part from .forms import EditManufacturerPartParameterForm -from .forms import CompanyImageForm from .forms import EditManufacturerPartForm from .forms import EditSupplierPartForm from .forms import EditPriceBreakForm From 621f47e46c1e7ba14f44e0134881fbbd35e2a671 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 01:04:39 +1000 Subject: [PATCH 166/445] Replace "edit part category" form --- InvenTree/InvenTree/models.py | 11 +++++++++++ InvenTree/InvenTree/serializers.py | 13 +++++++++++++ InvenTree/part/api.py | 5 ++++- InvenTree/part/serializers.py | 1 + InvenTree/part/templates/part/category.html | 18 ++++++++++++++---- InvenTree/part/test_views.py | 5 ----- InvenTree/part/urls.py | 1 - InvenTree/templates/js/forms.js | 21 +++++++++++++++++++-- 8 files changed, 62 insertions(+), 13 deletions(-) diff --git a/InvenTree/InvenTree/models.py b/InvenTree/InvenTree/models.py index 5822f8a19f..2831a23151 100644 --- a/InvenTree/InvenTree/models.py +++ b/InvenTree/InvenTree/models.py @@ -10,11 +10,13 @@ from django.db import models from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType from django.utils.translation import gettext_lazy as _ +from django.core.exceptions import ValidationError from django.db.models.signals import pre_delete from django.dispatch import receiver from mptt.models import MPTTModel, TreeForeignKey +from mptt.exceptions import InvalidMove from .validators import validate_tree_name @@ -91,6 +93,15 @@ class InvenTreeTree(MPTTModel): parent: The item immediately above this one. An item with a null parent is a top-level item """ + def save(self, *args, **kwargs): + + try: + super().save(*args, **kwargs) + except InvalidMove: + raise ValidationError({ + 'parent': _("Invalid choice"), + }) + class Meta: abstract = True diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index 772daa06ab..19c70fa29a 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -110,6 +110,19 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): return initials + def save(self, **kwargs): + """ + Catch any django ValidationError thrown at the moment save() is called, + and re-throw as a DRF ValidationError + """ + + try: + super().save(**kwargs) + except (ValidationError, DjangoValidationError) as exc: + raise ValidationError(detail=serializers.as_serializer_error(exc)) + + return self.instance + def run_validation(self, data=empty): """ Perform serializer validation. diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 8ef6902600..2212743c2b 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -127,7 +127,10 @@ class CategoryList(generics.ListCreateAPIView): class CategoryDetail(generics.RetrieveUpdateDestroyAPIView): - """ API endpoint for detail view of a single PartCategory object """ + """ + API endpoint for detail view of a single PartCategory object + """ + serializer_class = part_serializers.CategorySerializer queryset = PartCategory.objects.all() diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index ff178c5941..fb5480f668 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -39,6 +39,7 @@ class CategorySerializer(InvenTreeModelSerializer): 'name', 'description', 'default_location', + 'default_keywords', 'pathstring', 'url', 'parent', diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html index ef250d4c89..125e089721 100644 --- a/InvenTree/part/templates/part/category.html +++ b/InvenTree/part/templates/part/category.html @@ -268,13 +268,23 @@ {% if category %} $("#cat-edit").click(function () { - launchModalForm( - "{% url 'category-edit' category.id %}", + + constructForm( + '{% url "api-part-category-detail" category.pk %}', { + fields: { + name: {}, + description: {}, + parent: {}, + default_location: {}, + default_keywords: { + icon: 'fa-key', + } + }, + title: '{% trans "Edit Part Category" %}', reload: true - }, + } ); - return false; }); {% if category.parent %} diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index c32753cbbb..231eed7896 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -294,11 +294,6 @@ class CategoryTest(PartViewTestCase): # Form should still return OK self.assertEqual(response.status_code, 200) - def test_edit(self): - """ Retrieve the part category editing form """ - response = self.client.get(reverse('category-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - def test_set_category(self): """ Test that the "SetCategory" view works """ diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index fb4a1ab9eb..80351b8dba 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -104,7 +104,6 @@ category_urls = [ # Category detail views url(r'(?P\d+)/', include([ - url(r'^edit/', views.CategoryEdit.as_view(), name='category-edit'), url(r'^delete/', views.CategoryDelete.as_view(), name='category-delete'), url(r'^parameters/', include(category_parameter_urls)), diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 535391d2e1..c472a83ffd 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -388,8 +388,13 @@ function constructFormBody(fields, options) { function submitFormData(fields, options) { // Form data to be uploaded to the server + // Only used if file / image upload is required var form_data = new FormData(); + var data = {}; + + var has_files = false; + // Extract values for each field options.field_names.forEach(function(name) { @@ -411,20 +416,31 @@ function submitFormData(fields, options) { var file = field_files[0]; form_data.append(name, file); + + has_files = true; } } else { // Normal field (not a file or image) form_data.append(name, value); + + data[name] = value; } } else { console.log(`WARNING: Could not find field matching '${name}'`); } }); + var upload_func = inventreePut; + + if (has_files) { + upload_func = inventreeFormDataUpload; + data = form_data; + } + // Submit data - inventreeFormDataUpload( + upload_func( options.url, - form_data, + data, { method: options.method, success: function(response, status) { @@ -708,6 +724,7 @@ function initializeRelatedField(name, field, options) { ajax: { url: field.api_url, dataType: 'json', + placeholder: '', allowClear: !field.required, dropdownParent: $(options.modal), dropdownAutoWidth: false, From 1f75530910d3ae336aaf1f18c364250553ad71fc Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 01:07:36 +1000 Subject: [PATCH 167/445] Specify custom help text for fields on the client side --- InvenTree/part/templates/part/category.html | 4 +++- InvenTree/templates/js/forms.js | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html index 125e089721..cf7348be76 100644 --- a/InvenTree/part/templates/part/category.html +++ b/InvenTree/part/templates/part/category.html @@ -275,7 +275,9 @@ fields: { name: {}, description: {}, - parent: {}, + parent: { + help_text: '{% trans "Select parent category" %}', + }, default_location: {}, default_keywords: { icon: 'fa-key', diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index c472a83ffd..fec168e923 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -286,6 +286,11 @@ function constructFormBody(fields, options) { // Edit callback fields[field].onEdit = field_options.onEdit; + // Custom help_text + if (field_options.help_text) { + fields[field].help_text = field_options.help_text; + } + // Field prefix if (field_options.prefix) { fields[field].prefix = field_options.prefix; From 43f26f2c659f30041465b102bca219d4a42d4fb9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 01:07:57 +1000 Subject: [PATCH 168/445] Allow custom labels --- InvenTree/templates/js/forms.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index fec168e923..54f0ae2f16 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -291,6 +291,11 @@ function constructFormBody(fields, options) { fields[field].help_text = field_options.help_text; } + // Custom label + if (field_options.label) { + fields[field].label = field_options.label; + } + // Field prefix if (field_options.prefix) { fields[field].prefix = field_options.prefix; From 7d53bcb27cada9cc9cd8d61fecb0c74e72b3735d Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 08:52:53 +1000 Subject: [PATCH 169/445] Convert StockItemEditStatus to use API forms --- .../stock/templates/stock/item_base.html | 15 ++++++------- InvenTree/stock/urls.py | 1 - InvenTree/stock/views.py | 21 ------------------- 3 files changed, 8 insertions(+), 29 deletions(-) diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index bf9d10590f..b674c5c7fc 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -490,13 +490,14 @@ $("#stock-edit").click(function () { }); $('#stock-edit-status').click(function () { - launchModalForm( - "{% url 'stock-item-edit-status' item.id %}", - { - reload: true, - submit_text: '{% trans "Save" %}', - } - ); + + constructForm('{% url "api-stock-detail" item.pk %}', { + fields: { + status: {}, + }, + reload: true, + title: '{% trans "Edit Stock Status" %}', + }); }); {% endif %} diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index dbdbdda317..c0b6341744 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -24,7 +24,6 @@ location_urls = [ ] stock_item_detail_urls = [ - url(r'^edit_status/', views.StockItemEditStatus.as_view(), name='stock-item-edit-status'), url(r'^edit/', views.StockItemEdit.as_view(), name='stock-item-edit'), url(r'^convert/', views.StockItemConvert.as_view(), name='stock-item-convert'), url(r'^serialize/', views.StockItemSerialize.as_view(), name='stock-item-serialize'), diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 9a47576442..bc3e8cb462 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -1212,27 +1212,6 @@ class StockAdjust(AjaxView, FormMixin): return _("Deleted {n} stock items").format(n=count) -class StockItemEditStatus(AjaxUpdateView): - """ - View for editing stock item status field - """ - - model = StockItem - form_class = StockForms.EditStockItemStatusForm - ajax_form_title = _('Edit Stock Item Status') - - def save(self, object, form, **kwargs): - """ - Override the save method, to track the user who updated the model - """ - - item = form.save(commit=False) - - item.save(user=self.request.user) - - return item - - class StockItemEdit(AjaxUpdateView): """ View for editing details of a single StockItem From 87235b7e6f6679b611353f645fc63cc7dd5d0cd7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 09:17:28 +1000 Subject: [PATCH 170/445] Replace StockItemAttachmentCreate form - Also replace drag-and-drop - Add 'hidden' option for form fields - Adds renderer for StockItem model --- InvenTree/stock/serializers.py | 2 + .../templates/stock/item_attachments.html | 26 +++++++++-- InvenTree/stock/urls.py | 1 - InvenTree/stock/views.py | 46 ------------------- InvenTree/templates/js/forms.js | 24 ++++++++-- InvenTree/templates/js/model_renderers.js | 25 ++++++++-- 6 files changed, 66 insertions(+), 58 deletions(-) diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index a0b7e3403a..38301bdd1f 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -288,6 +288,8 @@ class StockItemAttachmentSerializer(InvenTreeModelSerializer): attachment = InvenTreeAttachmentSerializerField(required=True) + # TODO: Record the uploading user when creating or updating an attachment! + class Meta: model = StockItemAttachment diff --git a/InvenTree/stock/templates/stock/item_attachments.html b/InvenTree/stock/templates/stock/item_attachments.html index a022403d02..abd89c57c3 100644 --- a/InvenTree/stock/templates/stock/item_attachments.html +++ b/InvenTree/stock/templates/stock/item_attachments.html @@ -21,10 +21,11 @@ enableDragAndDrop( '#attachment-dropzone', - "{% url 'stock-item-attachment-create' %}", + "{% url 'api-stock-attachment-list' %}", { data: { stock_item: {{ item.id }}, + user: {{ user.pk }}, }, label: 'attachment', success: function(data, status, xhr) { @@ -34,10 +35,27 @@ enableDragAndDrop( ); $("#new-attachment").click(function() { - launchModalForm("{% url 'stock-item-attachment-create' %}?item={{ item.id }}", + + constructForm( + '{% url "api-stock-attachment-list" %}', { - reload: true, - }); + method: 'POST', + fields: { + attachment: {}, + comment: {}, + stock_item: { + value: {{ item.pk }}, + hidden: true, + }, + user: { + value: {{ user.pk }}, + hidden: true, + } + }, + reload: true, + title: '{% trans "Add Attachment" %}', + } + ); }); $("#attachment-table").on('click', '.attachment-edit-button', function() { diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index c0b6341744..01eb6f4704 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -64,7 +64,6 @@ stock_urls = [ # URLs for StockItem attachments url(r'^item/attachment/', include([ - url(r'^new/', views.StockItemAttachmentCreate.as_view(), name='stock-item-attachment-create'), url(r'^(?P\d+)/edit/', views.StockItemAttachmentEdit.as_view(), name='stock-item-attachment-edit'), url(r'^(?P\d+)/delete/', views.StockItemAttachmentDelete.as_view(), name='stock-item-attachment-delete'), ])), diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index bc3e8cb462..3608d5d553 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -255,52 +255,6 @@ class StockLocationQRCode(QRCodeView): return None -class StockItemAttachmentCreate(AjaxCreateView): - """ - View for adding a new attachment for a StockItem - """ - - model = StockItemAttachment - form_class = StockForms.EditStockItemAttachmentForm - ajax_form_title = _("Add Stock Item Attachment") - ajax_template_name = "modal_form.html" - - def save(self, form, **kwargs): - """ Record the user that uploaded the attachment """ - - attachment = form.save(commit=False) - attachment.user = self.request.user - attachment.save() - - def get_data(self): - return { - 'success': _("Added attachment") - } - - def get_initial(self): - """ - Get initial data for the new StockItem attachment object. - - - Client must provide a valid StockItem ID - """ - - initials = super().get_initial() - - try: - initials['stock_item'] = StockItem.objects.get(id=self.request.GET.get('item', None)) - except (ValueError, StockItem.DoesNotExist): - pass - - return initials - - def get_form(self): - - form = super().get_form() - form.fields['stock_item'].widget = HiddenInput() - - return form - - class StockItemAttachmentEdit(AjaxUpdateView): """ View for editing a StockItemAttachment object. diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 54f0ae2f16..10d07d07e2 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -304,10 +304,7 @@ function constructFormBody(fields, options) { fields[field].prefix = ``; } - // // Field value? - // if (fields[field].value == null) { - // fields[field].value = field_options.value; - // } + fields[field].hidden = field_options.hidden; } } @@ -672,6 +669,8 @@ function initializeRelatedFields(fields, options) { if (!field || field.type != 'related field') continue; + if (field.hidden) continue; + if (!field.api_url) { // TODO: Provide manual api_url option? console.log(`Related field '${name}' missing 'api_url' parameter.`); @@ -962,6 +961,11 @@ function constructField(name, parameters, options) { var field_name = `id_${name}`; + // Hidden inputs are rendered without label / help text / etc + if (parameters.hidden) { + return constructHiddenInput(name, parameters, options); + } + var form_classes = 'form-group'; if (parameters.errors) { @@ -1142,6 +1146,18 @@ function constructInputOptions(name, classes, type, parameters) { } +// Construct a "hidden" input +function constructHiddenInput(name, parameters, options) { + + return constructInputOptions( + name, + 'hiddeninput', + 'hidden', + parameters + ); +} + + // Construct a "checkbox" input function constructCheckboxInput(name, parameters, options) { diff --git a/InvenTree/templates/js/model_renderers.js b/InvenTree/templates/js/model_renderers.js index 24e9c1d328..c9cf654d12 100644 --- a/InvenTree/templates/js/model_renderers.js +++ b/InvenTree/templates/js/model_renderers.js @@ -27,8 +27,27 @@ function renderCompany(name, data, parameters, options) { // Renderer for "StockItem" model function renderStockItem(name, data, parameters, options) { - // TODO - Include part detail, location, quantity - // TODO - Include part image + var image = data.part_detail.thumbnail || data.part_detail.image; + + if (!image) { + image = `/static/img/blank_image.png`; + } + + var html = ``; + + html += ` ${data.part_detail.full_name || data.part_detail.name}`; + + if (data.serial && data.quantity == 1) { + html += ` - {% trans "Serial Number" %}: ${data.serial}`; + } else { + html += ` - {% trans "Quantity" %}: ${data.quantity}`; + } + + if (data.part_detail.description) { + html += `

          ${data.part_detail.description}

          `; + } + + return html; } @@ -62,7 +81,7 @@ function renderPart(name, data, parameters, options) { var html = ``; - html += ` ${data.full_name ?? data.name}`; + html += ` ${data.full_name || data.name}`; if (data.description) { html += ` - ${data.description}`; From 54c9bd25a5de7e28cc635ecc9996b0a7282ec7a6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 09:40:54 +1000 Subject: [PATCH 171/445] Add detail endpoint for StockItemAttachment --- InvenTree/stock/api.py | 12 ++++++++++++ .../stock/templates/stock/item_attachments.html | 16 +++++++++++----- InvenTree/stock/urls.py | 1 - InvenTree/stock/views.py | 17 ----------------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index d1add67d9d..26dd97b848 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -2,6 +2,7 @@ JSON API for the Stock app """ +from django.db.models.query import QuerySet from django_filters.rest_framework import FilterSet, DjangoFilterBackend from django_filters import NumberFilter @@ -931,6 +932,15 @@ class StockAttachmentList(generics.ListCreateAPIView, AttachmentMixin): ] +class StockAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin): + """ + Detail endpoint for StockItemAttachment + """ + + queryset = StockItemAttachment.objects.all() + serializer_class = StockItemAttachmentSerializer + + class StockItemTestResultList(generics.ListCreateAPIView): """ API endpoint for listing (and creating) a StockItemTestResult object. @@ -1133,6 +1143,7 @@ stock_api_urls = [ url(r'location/', include(location_endpoints)), # These JSON endpoints have been replaced (for now) with server-side form rendering - 02/06/2019 + # TODO: Remove server-side forms for stock adjustment!!! url(r'count/?', StockCount.as_view(), name='api-stock-count'), url(r'add/?', StockAdd.as_view(), name='api-stock-add'), url(r'remove/?', StockRemove.as_view(), name='api-stock-remove'), @@ -1140,6 +1151,7 @@ stock_api_urls = [ # Base URL for StockItemAttachment API endpoints url(r'^attachment/', include([ + url(r'^(?P\d+)/', StockAttachmentDetail.as_view(), name='api-stock-attachment-detail'), url(r'^$', StockAttachmentList.as_view(), name='api-stock-attachment-list'), ])), diff --git a/InvenTree/stock/templates/stock/item_attachments.html b/InvenTree/stock/templates/stock/item_attachments.html index abd89c57c3..f5e9f8c4fc 100644 --- a/InvenTree/stock/templates/stock/item_attachments.html +++ b/InvenTree/stock/templates/stock/item_attachments.html @@ -61,12 +61,18 @@ $("#new-attachment").click(function() { $("#attachment-table").on('click', '.attachment-edit-button', function() { var button = $(this); - var url = `/stock/item/attachment/${button.attr('pk')}/edit/`; + var pk = button.attr('pk'); - launchModalForm(url, - { - reload: true, - }); + var url = `/api/stock/attachment/${pk}/`; + + constructForm(url, { + fields: { + attachment: {}, + comment: {}, + }, + title: '{% trans "Edit Attachment" %}', + reload: true + }); }); $("#attachment-table").on('click', '.attachment-delete-button', function() { diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index 01eb6f4704..eb0acbbef2 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -64,7 +64,6 @@ stock_urls = [ # URLs for StockItem attachments url(r'^item/attachment/', include([ - url(r'^(?P\d+)/edit/', views.StockItemAttachmentEdit.as_view(), name='stock-item-attachment-edit'), url(r'^(?P\d+)/delete/', views.StockItemAttachmentDelete.as_view(), name='stock-item-attachment-delete'), ])), diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 3608d5d553..5b41bfe1b2 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -255,23 +255,6 @@ class StockLocationQRCode(QRCodeView): return None -class StockItemAttachmentEdit(AjaxUpdateView): - """ - View for editing a StockItemAttachment object. - """ - - model = StockItemAttachment - form_class = StockForms.EditStockItemAttachmentForm - ajax_form_title = _("Edit Stock Item Attachment") - - def get_form(self): - - form = super().get_form() - form.fields['stock_item'].widget = HiddenInput() - - return form - - class StockItemAttachmentDelete(AjaxDeleteView): """ View for deleting a StockItemAttachment object. From 8c439e52fdea54f65f428ba9805c40fe34a7ffe2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 09:41:13 +1000 Subject: [PATCH 172/445] PEP fix --- InvenTree/stock/api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 26dd97b848..534d27a8f4 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -2,7 +2,6 @@ JSON API for the Stock app """ -from django.db.models.query import QuerySet from django_filters.rest_framework import FilterSet, DjangoFilterBackend from django_filters import NumberFilter From 238dccc071ed69aa5479d9afab806fd370413d03 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 09:45:36 +1000 Subject: [PATCH 173/445] Replace PartAttachmentCreate form --- .../part/templates/part/attachments.html | 21 ++++++-- InvenTree/part/test_views.py | 23 -------- InvenTree/part/urls.py | 1 - InvenTree/part/views.py | 54 ------------------- 4 files changed, 17 insertions(+), 82 deletions(-) diff --git a/InvenTree/part/templates/part/attachments.html b/InvenTree/part/templates/part/attachments.html index 93440e13ed..78bd621254 100644 --- a/InvenTree/part/templates/part/attachments.html +++ b/InvenTree/part/templates/part/attachments.html @@ -21,7 +21,7 @@ enableDragAndDrop( '#attachment-dropzone', - "{% url 'part-attachment-create' %}", + '{% url "api-part-attachment-list" %}', { data: { part: {{ part.id }}, @@ -34,10 +34,23 @@ ); $("#new-attachment").click(function() { - launchModalForm("{% url 'part-attachment-create' %}?part={{ part.id }}", + + constructForm( + '{% url "api-part-attachment-list" %}', { - reload: true, - }); + method: 'POST', + fields: { + attachment: {}, + comment: {}, + part: { + value: {{ part.pk }}, + hidden: true, + } + }, + reload: true, + title: '{% trans "Add Attachment" %}', + } + ) }); $("#attachment-table").on('click', '.attachment-edit-button', function() { diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 231eed7896..3b6b245231 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -232,29 +232,6 @@ class PartRelatedTests(PartViewTestCase): self.assertEqual(n, 1) -class PartAttachmentTests(PartViewTestCase): - - def test_valid_create(self): - """ test creation of an attachment for a valid part """ - - response = self.client.get(reverse('part-attachment-create'), {'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # TODO - Create a new attachment using this view - - def test_invalid_create(self): - """ test creation of an attachment for an invalid part """ - - # TODO - pass - - def test_edit(self): - """ test editing an attachment """ - - # TODO - pass - - class PartQRTest(PartViewTestCase): """ Tests for the Part QR Code AJAX view """ diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 80351b8dba..cd18fc0f7e 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -18,7 +18,6 @@ part_related_urls = [ ] part_attachment_urls = [ - url(r'^new/?', views.PartAttachmentCreate.as_view(), name='part-attachment-create'), url(r'^(?P\d+)/edit/?', views.PartAttachmentEdit.as_view(), name='part-attachment-edit'), url(r'^(?P\d+)/delete/?', views.PartAttachmentDelete.as_view(), name='part-attachment-delete'), ] diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 9998a12783..c9d767d835 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -154,60 +154,6 @@ class PartRelatedDelete(AjaxDeleteView): role_required = 'part.change' -class PartAttachmentCreate(AjaxCreateView): - """ View for creating a new PartAttachment object - - - The view only makes sense if a Part object is passed to it - """ - model = PartAttachment - form_class = part_forms.EditPartAttachmentForm - ajax_form_title = _("Add part attachment") - ajax_template_name = "modal_form.html" - - def save(self, form, **kwargs): - """ - Record the user that uploaded this attachment - """ - - attachment = form.save(commit=False) - attachment.user = self.request.user - attachment.save() - - def get_data(self): - return { - 'success': _('Added attachment') - } - - def get_initial(self): - """ Get initial data for new PartAttachment object. - - - Client should have requested this form with a parent part in mind - - e.g. ?part= - """ - - initials = super(AjaxCreateView, self).get_initial() - - # TODO - If the proper part was not sent, return an error message - try: - initials['part'] = Part.objects.get(id=self.request.GET.get('part', None)) - except (ValueError, Part.DoesNotExist): - pass - - return initials - - def get_form(self): - """ Create a form to upload a new PartAttachment - - - Hide the 'part' field - """ - - form = super(AjaxCreateView, self).get_form() - - form.fields['part'].widget = HiddenInput() - - return form - - class PartAttachmentEdit(AjaxUpdateView): """ View for editing a PartAttachment object """ From b946aedb5c3eb76b3cc1e10bb5f81daaa45bcd54 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 09:49:30 +1000 Subject: [PATCH 174/445] Replace PartAttachmentEdit view --- InvenTree/part/api.py | 10 +++++++++ .../part/templates/part/attachments.html | 16 +++++++++----- InvenTree/part/urls.py | 1 - InvenTree/part/views.py | 21 ------------------- .../templates/stock/item_attachments.html | 5 ----- 5 files changed, 21 insertions(+), 32 deletions(-) diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 2212743c2b..d9fa77afd4 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -232,6 +232,15 @@ class PartAttachmentList(generics.ListCreateAPIView, AttachmentMixin): ] +class PartAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin): + """ + Detail endpoint for PartAttachment model + """ + + queryset = PartAttachment.objects.all() + serializer_class = part_serializers.PartAttachmentSerializer + + class PartTestTemplateList(generics.ListCreateAPIView): """ API endpoint for listing (and creating) a PartTestTemplate. @@ -1032,6 +1041,7 @@ part_api_urls = [ # Base URL for PartAttachment API endpoints url(r'^attachment/', include([ + url(r'^(?P\d+)/', PartAttachmentDetail.as_view(), name='api-part-attachment-detail'), url(r'^$', PartAttachmentList.as_view(), name='api-part-attachment-list'), ])), diff --git a/InvenTree/part/templates/part/attachments.html b/InvenTree/part/templates/part/attachments.html index 78bd621254..cff6f25892 100644 --- a/InvenTree/part/templates/part/attachments.html +++ b/InvenTree/part/templates/part/attachments.html @@ -56,12 +56,18 @@ $("#attachment-table").on('click', '.attachment-edit-button', function() { var button = $(this); - var url = `/part/attachment/${button.attr('pk')}/edit/`; + var pk = button.attr('pk'); - launchModalForm(url, - { - reload: true, - }); + var url = `/api/part/attachment/${pk}/`; + + constructForm(url, { + fields: { + attachment: {}, + comment: {}, + }, + title: '{% trans "Edit Attachment" %}', + reload: true, + }); }); $("#attachment-table").on('click', '.attachment-delete-button', function() { diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index cd18fc0f7e..eeb1a08be4 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -18,7 +18,6 @@ part_related_urls = [ ] part_attachment_urls = [ - url(r'^(?P\d+)/edit/?', views.PartAttachmentEdit.as_view(), name='part-attachment-edit'), url(r'^(?P\d+)/delete/?', views.PartAttachmentDelete.as_view(), name='part-attachment-delete'), ] diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index c9d767d835..b2d12a72ab 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -154,27 +154,6 @@ class PartRelatedDelete(AjaxDeleteView): role_required = 'part.change' -class PartAttachmentEdit(AjaxUpdateView): - """ View for editing a PartAttachment object """ - - model = PartAttachment - form_class = part_forms.EditPartAttachmentForm - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Edit attachment') - - def get_data(self): - return { - 'success': _('Part attachment updated') - } - - def get_form(self): - form = super(AjaxUpdateView, self).get_form() - - form.fields['part'].widget = HiddenInput() - - return form - - class PartAttachmentDelete(AjaxDeleteView): """ View for deleting a PartAttachment """ diff --git a/InvenTree/stock/templates/stock/item_attachments.html b/InvenTree/stock/templates/stock/item_attachments.html index f5e9f8c4fc..13e886d8a5 100644 --- a/InvenTree/stock/templates/stock/item_attachments.html +++ b/InvenTree/stock/templates/stock/item_attachments.html @@ -25,7 +25,6 @@ enableDragAndDrop( { data: { stock_item: {{ item.id }}, - user: {{ user.pk }}, }, label: 'attachment', success: function(data, status, xhr) { @@ -47,10 +46,6 @@ $("#new-attachment").click(function() { value: {{ item.pk }}, hidden: true, }, - user: { - value: {{ user.pk }}, - hidden: true, - } }, reload: true, title: '{% trans "Add Attachment" %}', From 60d599b4762fd595192c1f9e96a4f04813fa5cf0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 10:03:54 +1000 Subject: [PATCH 175/445] Refactor PurchaseOrderAttachment views --- InvenTree/order/api.py | 15 +++- .../order/templates/order/po_attachments.html | 32 ++++++-- InvenTree/order/urls.py | 2 - InvenTree/order/views.py | 73 ------------------- 4 files changed, 36 insertions(+), 86 deletions(-) diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py index c22d76a52e..74d94b12f4 100644 --- a/InvenTree/order/api.py +++ b/InvenTree/order/api.py @@ -554,12 +554,22 @@ class POAttachmentList(generics.ListCreateAPIView, AttachmentMixin): serializer_class = POAttachmentSerializer +class POAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin): + """ + Detail endpoint for a PurchaseOrderAttachment + """ + + queryset = PurchaseOrderAttachment.objects.all() + serializer_class = POAttachmentSerializer + + order_api_urls = [ # API endpoints for purchase orders - url(r'^po/(?P\d+)/$', PODetail.as_view(), name='api-po-detail'), url(r'po/attachment/', include([ + url(r'^(?P\d+)/$', POAttachmentDetail.as_view(), name='api-po-attachment-detail'), url(r'^.*$', POAttachmentList.as_view(), name='api-po-attachment-list'), ])), + url(r'^po/(?P\d+)/$', PODetail.as_view(), name='api-po-detail'), url(r'^po/.*$', POList.as_view(), name='api-po-list'), # API endpoints for purchase order line items @@ -568,12 +578,11 @@ order_api_urls = [ # API endpoints for sales ordesr url(r'^so/', include([ - url(r'^(?P\d+)/$', SODetail.as_view(), name='api-so-detail'), url(r'attachment/', include([ url(r'^.*$', SOAttachmentList.as_view(), name='api-so-attachment-list'), ])), - # List all sales orders + url(r'^(?P\d+)/$', SODetail.as_view(), name='api-so-detail'), url(r'^.*$', SOList.as_view(), name='api-so-list'), ])), diff --git a/InvenTree/order/templates/order/po_attachments.html b/InvenTree/order/templates/order/po_attachments.html index 40052c1ec6..20d15ea90f 100644 --- a/InvenTree/order/templates/order/po_attachments.html +++ b/InvenTree/order/templates/order/po_attachments.html @@ -22,7 +22,7 @@ enableDragAndDrop( '#attachment-dropzone', - "{% url 'po-attachment-create' %}", + '{% url "api-po-attachment-list" %}', { data: { order: {{ order.id }}, @@ -35,20 +35,36 @@ enableDragAndDrop( ); $("#new-attachment").click(function() { - launchModalForm("{% url 'po-attachment-create' %}?order={{ order.id }}", - { - reload: true, - } - ); + + constructForm('{% url "api-po-attachment-list" %}', { + method: 'POST', + fields: { + attachment: {}, + comment: {}, + order: { + value: {{ order.pk }}, + hidden: true, + }, + }, + reload: true, + title: '{% trans "Add Attachment" %}', + }); }); $("#attachment-table").on('click', '.attachment-edit-button', function() { var button = $(this); - var url = `/order/purchase-order/attachment/${button.attr('pk')}/edit/`; + var pk = button.attr('pk'); - launchModalForm(url, { + var url = `/api/order/po/attachment/${pk}/`; + + constructForm(url, { + fields: { + attachment: {}, + comment: {}, + }, reload: true, + title: '{% trans "Edit Attachment" %}', }); }); diff --git a/InvenTree/order/urls.py b/InvenTree/order/urls.py index 112a8cf297..692f12f298 100644 --- a/InvenTree/order/urls.py +++ b/InvenTree/order/urls.py @@ -46,8 +46,6 @@ purchase_order_urls = [ ])), url(r'^attachment/', include([ - url(r'^new/', views.PurchaseOrderAttachmentCreate.as_view(), name='po-attachment-create'), - url(r'^(?P\d+)/edit/', views.PurchaseOrderAttachmentEdit.as_view(), name='po-attachment-edit'), url(r'^(?P\d+)/delete/', views.PurchaseOrderAttachmentDelete.as_view(), name='po-attachment-delete'), ])), diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 98f3384ca9..8df386e8b8 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -96,58 +96,6 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView): template_name = 'order/sales_order_detail.html' -class PurchaseOrderAttachmentCreate(AjaxCreateView): - """ - View for creating a new PurchaseOrderAttachment - """ - - model = PurchaseOrderAttachment - form_class = order_forms.EditPurchaseOrderAttachmentForm - ajax_form_title = _("Add Purchase Order Attachment") - ajax_template_name = "modal_form.html" - - def save(self, form, **kwargs): - - attachment = form.save(commit=False) - attachment.user = self.request.user - attachment.save() - - def get_data(self): - return { - "success": _("Added attachment") - } - - def get_initial(self): - """ - Get initial data for creating a new PurchaseOrderAttachment object. - - - Client must request this form with a parent PurchaseOrder in midn. - - e.g. ?order= - """ - - initials = super(AjaxCreateView, self).get_initial() - - try: - initials["order"] = PurchaseOrder.objects.get(id=self.request.GET.get('order', -1)) - except (ValueError, PurchaseOrder.DoesNotExist): - pass - - return initials - - def get_form(self): - """ - Create a form to upload a new PurchaseOrderAttachment - - - Hide the 'order' field - """ - - form = super(AjaxCreateView, self).get_form() - - form.fields['order'].widget = HiddenInput() - - return form - - class SalesOrderAttachmentCreate(AjaxCreateView): """ View for creating a new SalesOrderAttachment """ @@ -188,27 +136,6 @@ class SalesOrderAttachmentCreate(AjaxCreateView): return form -class PurchaseOrderAttachmentEdit(AjaxUpdateView): - """ View for editing a PurchaseOrderAttachment object """ - - model = PurchaseOrderAttachment - form_class = order_forms.EditPurchaseOrderAttachmentForm - ajax_form_title = _("Edit Attachment") - - def get_data(self): - return { - 'success': _('Attachment updated') - } - - def get_form(self): - form = super(AjaxUpdateView, self).get_form() - - # Hide the 'order' field - form.fields['order'].widget = HiddenInput() - - return form - - class SalesOrderAttachmentEdit(AjaxUpdateView): """ View for editing a SalesOrderAttachment object """ From 712c9598d1d3586f38f38ba30d62dfc0ecd6d5a5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 10:09:05 +1000 Subject: [PATCH 176/445] Refactor SalesOrderAttachment forms --- InvenTree/order/api.py | 10 ++++ .../order/templates/order/so_attachments.html | 32 +++++++--- InvenTree/order/urls.py | 2 - InvenTree/order/views.py | 60 ------------------- 4 files changed, 34 insertions(+), 70 deletions(-) diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py index 74d94b12f4..a128130f39 100644 --- a/InvenTree/order/api.py +++ b/InvenTree/order/api.py @@ -259,6 +259,15 @@ class SOAttachmentList(generics.ListCreateAPIView, AttachmentMixin): ] +class SOAttachmentDetail(generics.RetrieveUpdateAPIView, AttachmentMixin): + """ + Detail endpoint for SalesOrderAttachment + """ + + queryset = SalesOrderAttachment.objects.all() + serializer_class = SOAttachmentSerializer + + class SOList(generics.ListCreateAPIView): """ API endpoint for accessing a list of SalesOrder objects. @@ -579,6 +588,7 @@ order_api_urls = [ # API endpoints for sales ordesr url(r'^so/', include([ url(r'attachment/', include([ + url(r'^(?P\d+)/$', SOAttachmentDetail.as_view(), name='api-so-attachment-detail'), url(r'^.*$', SOAttachmentList.as_view(), name='api-so-attachment-list'), ])), diff --git a/InvenTree/order/templates/order/so_attachments.html b/InvenTree/order/templates/order/so_attachments.html index b868aea48e..90ba49a0ea 100644 --- a/InvenTree/order/templates/order/so_attachments.html +++ b/InvenTree/order/templates/order/so_attachments.html @@ -23,7 +23,7 @@ enableDragAndDrop( '#attachment-dropzone', - "{% url 'so-attachment-create' %}", + '{% url "api-so-attachment-list" %}', { data: { order: {{ order.id }}, @@ -36,20 +36,36 @@ enableDragAndDrop( ); $("#new-attachment").click(function() { - launchModalForm("{% url 'so-attachment-create' %}?order={{ order.id }}", - { - reload: true, - } - ); + + constructForm('{% url "api-so-attachment-list" %}', { + method: 'POST', + fields: { + attachment: {}, + comment: {}, + order: { + value: {{ order.pk }}, + hidden: true + } + }, + reload: true, + title: '{% trans "Add Attachment" %}' + }); }); $("#attachment-table").on('click', '.attachment-edit-button', function() { var button = $(this); - var url = `/order/sales-order/attachment/${button.attr('pk')}/edit/`; + var pk = button.attr('pk'); - launchModalForm(url, { + var url = `/api/order/so/attachment/${pk}/`; + + constructForm(url, { + fields: { + attachment: {}, + comment: {}, + }, reload: true, + title: '{% trans "Edit Attachment" %}', }); }); diff --git a/InvenTree/order/urls.py b/InvenTree/order/urls.py index 692f12f298..db76306b3c 100644 --- a/InvenTree/order/urls.py +++ b/InvenTree/order/urls.py @@ -89,8 +89,6 @@ sales_order_urls = [ ])), url(r'^attachment/', include([ - url(r'^new/', views.SalesOrderAttachmentCreate.as_view(), name='so-attachment-create'), - url(r'^(?P\d+)/edit/', views.SalesOrderAttachmentEdit.as_view(), name='so-attachment-edit'), url(r'^(?P\d+)/delete/', views.SalesOrderAttachmentDelete.as_view(), name='so-attachment-delete'), ])), diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 8df386e8b8..9cf53ec51c 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -96,66 +96,6 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView): template_name = 'order/sales_order_detail.html' -class SalesOrderAttachmentCreate(AjaxCreateView): - """ View for creating a new SalesOrderAttachment """ - - model = SalesOrderAttachment - form_class = order_forms.EditSalesOrderAttachmentForm - ajax_form_title = _('Add Sales Order Attachment') - - def save(self, form, **kwargs): - """ - Save the user that uploaded the attachment - """ - - attachment = form.save(commit=False) - attachment.user = self.request.user - attachment.save() - - def get_data(self): - return { - 'success': _('Added attachment') - } - - def get_initial(self): - initials = super().get_initial().copy() - - try: - initials['order'] = SalesOrder.objects.get(id=self.request.GET.get('order', None)) - except (ValueError, SalesOrder.DoesNotExist): - pass - - return initials - - def get_form(self): - """ Hide the 'order' field """ - - form = super().get_form() - form.fields['order'].widget = HiddenInput() - - return form - - -class SalesOrderAttachmentEdit(AjaxUpdateView): - """ View for editing a SalesOrderAttachment object """ - - model = SalesOrderAttachment - form_class = order_forms.EditSalesOrderAttachmentForm - ajax_form_title = _("Edit Attachment") - - def get_data(self): - return { - 'success': _('Attachment updated') - } - - def get_form(self): - form = super().get_form() - - form.fields['order'].widget = HiddenInput() - - return form - - class PurchaseOrderAttachmentDelete(AjaxDeleteView): """ View for deleting a PurchaseOrderAttachment """ From f67779c816d59f21b5a41fdeecf244037b608ae6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 10:37:38 +1000 Subject: [PATCH 177/445] Unit test fixes --- InvenTree/InvenTree/tests.py | 6 ++---- InvenTree/company/test_api.py | 13 ++++++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index b7e5b98c1b..cb570d0176 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -15,8 +15,6 @@ from .validators import validate_overage, validate_part_name from . import helpers from . import version -from mptt.exceptions import InvalidMove - from decimal import Decimal import InvenTree.tasks @@ -203,7 +201,7 @@ class TestMPTT(TestCase): loc = StockLocation.objects.get(pk=4) loc.parent = loc - with self.assertRaises(InvalidMove): + with self.assertRaises(ValidationError): loc.save() def test_child_as_parent(self): @@ -214,7 +212,7 @@ class TestMPTT(TestCase): parent.parent = child - with self.assertRaises(InvalidMove): + with self.assertRaises(ValidationError): parent.save() def test_move(self): diff --git a/InvenTree/company/test_api.py b/InvenTree/company/test_api.py index 345f4bf1a4..6cd7ac7e3a 100644 --- a/InvenTree/company/test_api.py +++ b/InvenTree/company/test_api.py @@ -44,6 +44,10 @@ class CompanyTest(InvenTreeAPITestCase): self.assertEqual(len(response.data), 2) def test_company_detail(self): + """ + Tests for the Company detail endpoint + """ + url = reverse('api-company-detail', kwargs={'pk': 1}) response = self.get(url) @@ -52,14 +56,18 @@ class CompanyTest(InvenTreeAPITestCase): # Change the name of the company # Note we should not have the correct permissions (yet) data = response.data - data['name'] = 'ACMOO' response = self.client.patch(url, data, format='json', expected_code=400) self.assignRole('company.change') + # Update the name and set the currency to a valid value + data['name'] = 'ACMOO' + data['currency'] = 'NZD' + response = self.client.patch(url, data, format='json', expected_code=200) self.assertEqual(response.data['name'], 'ACMOO') + self.assertEqual(response.data['currency'], 'NZD') def test_company_search(self): """ @@ -182,6 +190,9 @@ class ManufacturerTest(InvenTreeAPITestCase): self.assertEqual(len(response.data), 2) def test_manufacturer_part_detail(self): + """ + Tests for the ManufacturerPart detail endpoint + """ url = reverse('api-manufacturer-part-detail', kwargs={'pk': 1}) response = self.get(url) From a7d60cf5ad4f63202ccc08a8a0f9101b65d156bd Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 10:49:33 +1000 Subject: [PATCH 178/445] Exposes BuildOrderAttachment objects to the REST API --- InvenTree/build/api.py | 39 ++++++++++++++++++++++++++++------ InvenTree/build/serializers.py | 22 +++++++++++++++++-- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/InvenTree/build/api.py b/InvenTree/build/api.py index 1cb973fe05..779c248fe5 100644 --- a/InvenTree/build/api.py +++ b/InvenTree/build/api.py @@ -11,11 +11,12 @@ from rest_framework import generics from django.conf.urls import url, include +from InvenTree.api import AttachmentMixin from InvenTree.helpers import str2bool, isNull from InvenTree.status_codes import BuildStatus -from .models import Build, BuildItem -from .serializers import BuildSerializer, BuildItemSerializer +from .models import Build, BuildItem, BuildOrderAttachment +from .serializers import BuildAttachmentSerializer, BuildSerializer, BuildItemSerializer class BuildList(generics.ListCreateAPIView): @@ -226,14 +227,40 @@ class BuildItemList(generics.ListCreateAPIView): ] -build_item_api_urls = [ - url('^.*$', BuildItemList.as_view(), name='api-build-item-list'), -] +class BuildAttachmentList(generics.ListCreateAPIView, AttachmentMixin): + """ + API endpoint for listing (and creating) BuildOrderAttachment objects + """ + + queryset = BuildOrderAttachment.objects.all() + serializer_class = BuildAttachmentSerializer + + +class BuildAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin): + """ + Detail endpoint for a BuildOrderAttachment object + """ + + queryset = BuildOrderAttachment.objects.all() + serializer_class = BuildAttachmentSerializer + build_api_urls = [ - url(r'^item/', include(build_item_api_urls)), + # Attachments + url(r'^attachment/', include([ + url(r'^(?P\d+)/', BuildAttachmentDetail.as_view(), name='api-build-attachment-detail'), + url('^.*$', BuildAttachmentList.as_view(), name='api-build-attachment-list'), + ])), + + # Build Items + url(r'^item/', include([ + url('^.*$', BuildItemList.as_view(), name='api-build-item-list') + ])), + + # Build Detail url(r'^(?P\d+)/', BuildDetail.as_view(), name='api-build-detail'), + # Build List url(r'^.*$', BuildList.as_view(), name='api-build-list'), ] diff --git a/InvenTree/build/serializers.py b/InvenTree/build/serializers.py index d8573cfa70..06c4f36ebb 100644 --- a/InvenTree/build/serializers.py +++ b/InvenTree/build/serializers.py @@ -10,13 +10,13 @@ from django.db.models import BooleanField from rest_framework import serializers -from InvenTree.serializers import InvenTreeModelSerializer +from InvenTree.serializers import InvenTreeModelSerializer, InvenTreeAttachmentSerializerField from stock.serializers import StockItemSerializerBrief from stock.serializers import LocationSerializer from part.serializers import PartSerializer, PartBriefSerializer -from .models import Build, BuildItem +from .models import Build, BuildItem, BuildOrderAttachment class BuildSerializer(InvenTreeModelSerializer): @@ -143,3 +143,21 @@ class BuildItemSerializer(InvenTreeModelSerializer): 'stock_item_detail', 'quantity' ] + + +class BuildAttachmentSerializer(InvenTreeModelSerializer): + """ + Serializer for a BuildAttachment + """ + + attachment = InvenTreeAttachmentSerializerField(required=True) + + class Meta: + model = BuildOrderAttachment + + fields = [ + 'pk', + 'build', + 'attachment', + 'comment' + ] From 9ea3e511b9ccb18a436a7fed89e9054ec25c0afe Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 11:05:35 +1000 Subject: [PATCH 179/445] Refactor BuildAttachment views --- .../build/templates/build/attachments.html | 39 ++++++----- InvenTree/build/urls.py | 2 - InvenTree/build/views.py | 70 ------------------- 3 files changed, 22 insertions(+), 89 deletions(-) diff --git a/InvenTree/build/templates/build/attachments.html b/InvenTree/build/templates/build/attachments.html index 8546ab42f5..9cd7761357 100644 --- a/InvenTree/build/templates/build/attachments.html +++ b/InvenTree/build/templates/build/attachments.html @@ -22,7 +22,7 @@ enableDragAndDrop( '#attachment-dropzone', - '{% url "build-attachment-create" %}', + '{% url "api-build-attachment-list" %}', { data: { build: {{ build.id }}, @@ -36,29 +36,34 @@ enableDragAndDrop( // Callback for creating a new attachment $('#new-attachment').click(function() { - launchModalForm( - '{% url "build-attachment-create" %}', - { - reload: true, - data: { - build: {{ build.pk }}, + + constructForm('{% url "api-build-attachment-list" %}', { + fields: { + attachment: {}, + comment: {}, + build: { + value: {{ build.pk }}, + hidden: true, } - } - ); + }, + method: 'POST', + reload: true, + title: '{% trans "Add Attachment" %}', + }); }); // Callback for editing an attachment $("#attachment-table").on('click', '.attachment-edit-button', function() { var pk = $(this).attr('pk'); - var url = `/build/attachment/${pk}/edit/`; - - launchModalForm( - url, - { - reload: true, - } - ); + constructForm(`/api/build/attachment/${pk}/`, { + fields: { + attachment: {}, + comment: {}, + }, + reload: true, + title: '{% trans "Edit Attachment" %}', + }); }); // Callback for deleting an attachment diff --git a/InvenTree/build/urls.py b/InvenTree/build/urls.py index 99b6b72818..ae9ce1bf87 100644 --- a/InvenTree/build/urls.py +++ b/InvenTree/build/urls.py @@ -37,8 +37,6 @@ build_urls = [ ])), url('^attachment/', include([ - url('^new/', views.BuildAttachmentCreate.as_view(), name='build-attachment-create'), - url(r'^(?P\d+)/edit/', views.BuildAttachmentEdit.as_view(), name='build-attachment-edit'), url(r'^(?P\d+)/delete/', views.BuildAttachmentDelete.as_view(), name='build-attachment-delete'), ])), diff --git a/InvenTree/build/views.py b/InvenTree/build/views.py index 6e72f7f3e6..8cdaede60b 100644 --- a/InvenTree/build/views.py +++ b/InvenTree/build/views.py @@ -1060,76 +1060,6 @@ class BuildItemEdit(AjaxUpdateView): return form -class BuildAttachmentCreate(AjaxCreateView): - """ - View for creating a BuildAttachment - """ - - model = BuildOrderAttachment - form_class = forms.EditBuildAttachmentForm - ajax_form_title = _('Add Build Order Attachment') - - def save(self, form, **kwargs): - """ - Add information on the user that uploaded the attachment - """ - - attachment = form.save(commit=False) - attachment.user = self.request.user - attachment.save() - - def get_data(self): - return { - 'success': _('Added attachment') - } - - def get_initial(self): - """ - Get initial data for creating an attachment - """ - - initials = super().get_initial() - - try: - initials['build'] = Build.objects.get(pk=self.request.GET.get('build', -1)) - except (ValueError, Build.DoesNotExist): - pass - - return initials - - def get_form(self): - """ - Hide the 'build' field if specified - """ - - form = super().get_form() - - form.fields['build'].widget = HiddenInput() - - return form - - -class BuildAttachmentEdit(AjaxUpdateView): - """ - View for editing a BuildAttachment object - """ - - model = BuildOrderAttachment - form_class = forms.EditBuildAttachmentForm - ajax_form_title = _('Edit Attachment') - - def get_form(self): - form = super().get_form() - form.fields['build'].widget = HiddenInput() - - return form - - def get_data(self): - return { - 'success': _('Attachment updated') - } - - class BuildAttachmentDelete(AjaxDeleteView): """ View for deleting a BuildAttachment From 537c15081b2ac018f9ffa07fa1645f99328d6371 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 11:12:16 +1000 Subject: [PATCH 180/445] Fix for PK lookup in API test --- InvenTree/company/test_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/company/test_api.py b/InvenTree/company/test_api.py index 6cd7ac7e3a..40176c7634 100644 --- a/InvenTree/company/test_api.py +++ b/InvenTree/company/test_api.py @@ -20,7 +20,7 @@ class CompanyTest(InvenTreeAPITestCase): super().setUp() - Company.objects.create(name='ACME', description='Supplier', is_customer=False, is_supplier=True) + self.acme = Company.objects.create(name='ACME', description='Supplier', is_customer=False, is_supplier=True) Company.objects.create(name='Drippy Cup Co.', description='Customer', is_customer=True, is_supplier=False) Company.objects.create(name='Sippy Cup Emporium', description='Another supplier') @@ -48,7 +48,7 @@ class CompanyTest(InvenTreeAPITestCase): Tests for the Company detail endpoint """ - url = reverse('api-company-detail', kwargs={'pk': 1}) + url = reverse('api-company-detail', kwargs={'pk': self.acme.pk}) response = self.get(url) self.assertEqual(response.data['name'], 'ACME') From 653e3cd135469291b920001076788af72c5e62b9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 12:03:32 +1000 Subject: [PATCH 181/445] Starting work on a DELETE form --- InvenTree/InvenTree/static/css/inventree.css | 8 +++ InvenTree/templates/js/forms.js | 66 +++++++++++++++++++- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index 375e02c8ca..11c0c95561 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -640,6 +640,14 @@ z-index: 9999; } +.modal-header { + border-bottom: 1px solid #ddd; +} + +.modal-footer { + border-top: 1px solid #ddd; +} + .modal-primary { z-index: 10000; } diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 10d07d07e2..89b4608c8d 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -172,10 +172,48 @@ function constructChangeForm(fields, options) { }, error: function(request, status, error) { // TODO: Handle error here - console.log(`ERROR in constructChangeForm at '${url}'`); + console.log(`ERROR in constructChangeForm at '${options.url}'`); } - }) + }); +} + +/* + * Construct a 'delete' form, to remove a model instance from the database. + * + * arguments: + * - fields: The 'actions' object provided by the OPTIONS request + * - options: The 'options' object provided by the client + */ +function constructDeleteForm(fields, options) { + + // Force the "confirm" property if not set + if (!('confirm' in options)) { + options.confirm = true; + } + + // Request existing data from the API endpoint + // This data can be used to render some information on the form + $.ajax({ + url: options.url, + type: 'GET', + contentType: 'application/json', + dataType: 'json', + accepts: { + json: 'application/json', + }, + success: function(data) { + + // Store the instance data + options.instance = data; + + constructFormBody(fields, options); + }, + error: function(request, status, error) { + // TODO: Handle error here + console.log(`ERROR in constructDeleteForm at '${options.url}`); + } + }); } @@ -229,7 +267,7 @@ function constructForm(url, options) { break; case 'DELETE': if (canDelete(OPTIONS)) { - console.log('delete'); + constructDeleteForm(OPTIONS.actions.DELETE, options); } else { // User does not have permission to DELETE to the endpoint // TODO @@ -363,6 +401,14 @@ function constructFormBody(fields, options) { // Insert generated form content $(modal).find('.modal-form-content').html(html); + // Clear any existing buttons from the modal + $(modal).find('#modal-footer-buttons').html(''); + + // Insert "confirm" button (if required) + if (options.confirm) { + insertConfirmButton(options); + } + $(modal).modal('show'); updateFieldValues(fields, options); @@ -388,6 +434,20 @@ function constructFormBody(fields, options) { } +// Add a "confirm" checkbox to the modal +// The "submit" button will be disabled unless "confirm" is checked +function insertConfirmButton(options) { + + var confirm = ` + + Confirm + + `; + + $(options.modal).find('#modal-footer-buttons').append(confirm); +} + + /* * Submit form data to the server. * From 4d8e88c77936bb8b98a34aece48dc2a2223b9d20 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 12:48:14 +1000 Subject: [PATCH 182/445] BuildAttachmentDelete form --- InvenTree/build/templates/build/attachments.html | 9 +++++++++ InvenTree/build/urls.py | 4 ---- InvenTree/build/views.py | 15 --------------- InvenTree/templates/js/forms.js | 16 ++++++++++++++-- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/InvenTree/build/templates/build/attachments.html b/InvenTree/build/templates/build/attachments.html index 9cd7761357..839c275a9b 100644 --- a/InvenTree/build/templates/build/attachments.html +++ b/InvenTree/build/templates/build/attachments.html @@ -70,6 +70,15 @@ $("#attachment-table").on('click', '.attachment-edit-button', function() { $("#attachment-table").on('click', '.attachment-delete-button', function() { var pk = $(this).attr('pk'); + constructForm(`/api/build/attachment/${pk}/`, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + reload: true, + }); + + return; + var url = `/build/attachment/${pk}/delete/`; launchModalForm( diff --git a/InvenTree/build/urls.py b/InvenTree/build/urls.py index ae9ce1bf87..549a20ee7e 100644 --- a/InvenTree/build/urls.py +++ b/InvenTree/build/urls.py @@ -36,10 +36,6 @@ build_urls = [ url('^new/', views.BuildItemCreate.as_view(), name='build-item-create'), ])), - url('^attachment/', include([ - url(r'^(?P\d+)/delete/', views.BuildAttachmentDelete.as_view(), name='build-attachment-delete'), - ])), - url(r'new/', views.BuildCreate.as_view(), name='build-create'), url(r'^(?P\d+)/', include(build_detail_urls)), diff --git a/InvenTree/build/views.py b/InvenTree/build/views.py index 8cdaede60b..a3fd4fbd34 100644 --- a/InvenTree/build/views.py +++ b/InvenTree/build/views.py @@ -1058,18 +1058,3 @@ class BuildItemEdit(AjaxUpdateView): form.fields['install_into'].widget = HiddenInput() return form - - -class BuildAttachmentDelete(AjaxDeleteView): - """ - View for deleting a BuildAttachment - """ - - model = BuildOrderAttachment - ajax_form_title = _('Delete Attachment') - context_object_name = 'attachment' - - def get_data(self): - return { - 'danger': _('Deleted attachment') - } diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 89b4608c8d..d568e40fe7 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -438,13 +438,25 @@ function constructFormBody(fields, options) { // The "submit" button will be disabled unless "confirm" is checked function insertConfirmButton(options) { + var message = options.confirmMessage || '{% trans "Confirm" %}'; + var confirm = ` - Confirm - + ${message} + `; $(options.modal).find('#modal-footer-buttons').append(confirm); + + // Disable the 'submit' button + $(options.modal).find('#modal-form-submit').prop('disabled', true); + + // Trigger event + $(options.modal).find('#modal-confirm').change(function() { + var enabled = this.checked; + + $(options.modal).find('#modal-form-submit').prop('disabled', !enabled); + }); } From 4e23dbd0af20d350b9b48864901cc06ee0e53378 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 12:54:38 +1000 Subject: [PATCH 183/445] Refactor delete views for SalesOrderAttachment and PurchaseOrderAttachment --- .../build/templates/build/attachments.html | 11 ------- InvenTree/build/views.py | 2 +- InvenTree/order/api.py | 2 +- .../order/templates/order/po_attachments.html | 7 ++-- .../order/templates/order/so_attachments.html | 7 ++-- InvenTree/order/urls.py | 8 ----- InvenTree/order/views.py | 32 ++----------------- 7 files changed, 14 insertions(+), 55 deletions(-) diff --git a/InvenTree/build/templates/build/attachments.html b/InvenTree/build/templates/build/attachments.html index 839c275a9b..728c02fca7 100644 --- a/InvenTree/build/templates/build/attachments.html +++ b/InvenTree/build/templates/build/attachments.html @@ -76,17 +76,6 @@ $("#attachment-table").on('click', '.attachment-delete-button', function() { title: '{% trans "Delete Attachment" %}', reload: true, }); - - return; - - var url = `/build/attachment/${pk}/delete/`; - - launchModalForm( - url, - { - reload: true, - } - ); }); $("#attachment-table").inventreeTable({}); diff --git a/InvenTree/build/views.py b/InvenTree/build/views.py index a3fd4fbd34..16004dacc1 100644 --- a/InvenTree/build/views.py +++ b/InvenTree/build/views.py @@ -12,7 +12,7 @@ from django.forms import HiddenInput from django.urls import reverse from part.models import Part -from .models import Build, BuildItem, BuildOrderAttachment +from .models import Build, BuildItem from . import forms from stock.models import StockLocation, StockItem diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py index a128130f39..748cd360d8 100644 --- a/InvenTree/order/api.py +++ b/InvenTree/order/api.py @@ -259,7 +259,7 @@ class SOAttachmentList(generics.ListCreateAPIView, AttachmentMixin): ] -class SOAttachmentDetail(generics.RetrieveUpdateAPIView, AttachmentMixin): +class SOAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin): """ Detail endpoint for SalesOrderAttachment """ diff --git a/InvenTree/order/templates/order/po_attachments.html b/InvenTree/order/templates/order/po_attachments.html index 20d15ea90f..a6ea769aee 100644 --- a/InvenTree/order/templates/order/po_attachments.html +++ b/InvenTree/order/templates/order/po_attachments.html @@ -71,9 +71,12 @@ $("#attachment-table").on('click', '.attachment-edit-button', function() { $("#attachment-table").on('click', '.attachment-delete-button', function() { var button = $(this); - var url = `/order/purchase-order/attachment/${button.attr('pk')}/delete/`; + var pk = button.attr('pk'); - launchModalForm(url, { + constructForm(`/api/order/po/attachment/${pk}/`, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', reload: true, }); }); diff --git a/InvenTree/order/templates/order/so_attachments.html b/InvenTree/order/templates/order/so_attachments.html index 90ba49a0ea..6df93bbe45 100644 --- a/InvenTree/order/templates/order/so_attachments.html +++ b/InvenTree/order/templates/order/so_attachments.html @@ -72,9 +72,12 @@ $("#attachment-table").on('click', '.attachment-edit-button', function() { $("#attachment-table").on('click', '.attachment-delete-button', function() { var button = $(this); - var url = `/order/sales-order/attachment/${button.attr('pk')}/delete/`; + var pk = button.attr('pk'); - launchModalForm(url, { + constructForm(`/api/order/so/attachment/${pk}/`, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', reload: true, }); }); diff --git a/InvenTree/order/urls.py b/InvenTree/order/urls.py index db76306b3c..3863d895c8 100644 --- a/InvenTree/order/urls.py +++ b/InvenTree/order/urls.py @@ -45,10 +45,6 @@ purchase_order_urls = [ ])), ])), - url(r'^attachment/', include([ - url(r'^(?P\d+)/delete/', views.PurchaseOrderAttachmentDelete.as_view(), name='po-attachment-delete'), - ])), - # Display complete list of purchase orders url(r'^.*$', views.PurchaseOrderIndex.as_view(), name='po-index'), ] @@ -88,10 +84,6 @@ sales_order_urls = [ ])), ])), - url(r'^attachment/', include([ - url(r'^(?P\d+)/delete/', views.SalesOrderAttachmentDelete.as_view(), name='so-attachment-delete'), - ])), - # Display detail view for a single SalesOrder url(r'^(?P\d+)/', include(sales_order_detail_urls)), diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 9cf53ec51c..04bd0d3828 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -20,8 +20,8 @@ from django.forms import HiddenInput, IntegerField import logging from decimal import Decimal, InvalidOperation -from .models import PurchaseOrder, PurchaseOrderLineItem, PurchaseOrderAttachment -from .models import SalesOrder, SalesOrderLineItem, SalesOrderAttachment +from .models import PurchaseOrder, PurchaseOrderLineItem +from .models import SalesOrder, SalesOrderLineItem from .models import SalesOrderAllocation from .admin import POLineItemResource from build.models import Build @@ -96,34 +96,6 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView): template_name = 'order/sales_order_detail.html' -class PurchaseOrderAttachmentDelete(AjaxDeleteView): - """ View for deleting a PurchaseOrderAttachment """ - - model = PurchaseOrderAttachment - ajax_form_title = _("Delete Attachment") - ajax_template_name = "order/delete_attachment.html" - context_object_name = "attachment" - - def get_data(self): - return { - "danger": _("Deleted attachment") - } - - -class SalesOrderAttachmentDelete(AjaxDeleteView): - """ View for deleting a SalesOrderAttachment """ - - model = SalesOrderAttachment - ajax_form_title = _("Delete Attachment") - ajax_template_name = "order/delete_attachment.html" - context_object_name = "attachment" - - def get_data(self): - return { - "danger": _("Deleted attachment") - } - - class PurchaseOrderNotes(InvenTreeRoleMixin, UpdateView): """ View for updating the 'notes' field of a PurchaseOrder """ From 8f47035a7b62b27cd5baf881a29b2a0acc3f3601 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 12:58:41 +1000 Subject: [PATCH 184/445] Refactor delete view for PartAttachment and StockItemAttachment --- InvenTree/part/templates/part/attachments.html | 13 +++++++------ InvenTree/part/urls.py | 7 ------- InvenTree/part/views.py | 18 +----------------- .../templates/stock/item_attachments.html | 13 ++++++++----- InvenTree/stock/urls.py | 5 ----- InvenTree/stock/views.py | 18 +----------------- 6 files changed, 17 insertions(+), 57 deletions(-) diff --git a/InvenTree/part/templates/part/attachments.html b/InvenTree/part/templates/part/attachments.html index cff6f25892..5fca535098 100644 --- a/InvenTree/part/templates/part/attachments.html +++ b/InvenTree/part/templates/part/attachments.html @@ -72,13 +72,14 @@ $("#attachment-table").on('click', '.attachment-delete-button', function() { var button = $(this); + var pk = button.attr('pk'); + var url = `/api/part/attachment/${pk}/`; - var url = `/part/attachment/${button.attr('pk')}/delete/`; - - launchModalForm(url, { - success: function() { - location.reload(); - } + constructForm(url, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + reload: true, }); }); diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index eeb1a08be4..489df6c116 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -17,10 +17,6 @@ part_related_urls = [ url(r'^(?P\d+)/delete/?', views.PartRelatedDelete.as_view(), name='part-related-delete'), ] -part_attachment_urls = [ - url(r'^(?P\d+)/delete/?', views.PartAttachmentDelete.as_view(), name='part-attachment-delete'), -] - sale_price_break_urls = [ url(r'^new/', views.PartSalePriceBreakCreate.as_view(), name='sale-price-break-create'), url(r'^(?P\d+)/edit/', views.PartSalePriceBreakEdit.as_view(), name='sale-price-break-edit'), @@ -146,9 +142,6 @@ part_urls = [ # Part related url(r'^related-parts/', include(part_related_urls)), - # Part attachments - url(r'^attachment/', include(part_attachment_urls)), - # Part price breaks url(r'^sale-price/', include(sale_price_break_urls)), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index b2d12a72ab..0f0ccd8ba0 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -31,7 +31,7 @@ import io from rapidfuzz import fuzz from decimal import Decimal, InvalidOperation -from .models import PartCategory, Part, PartAttachment, PartRelated +from .models import PartCategory, Part, PartRelated from .models import PartParameterTemplate, PartParameter from .models import PartCategoryParameterTemplate from .models import BomItem @@ -154,22 +154,6 @@ class PartRelatedDelete(AjaxDeleteView): role_required = 'part.change' -class PartAttachmentDelete(AjaxDeleteView): - """ View for deleting a PartAttachment """ - - model = PartAttachment - ajax_form_title = _("Delete Part Attachment") - ajax_template_name = "attachment_delete.html" - context_object_name = "attachment" - - role_required = 'part.change' - - def get_data(self): - return { - 'danger': _('Deleted part attachment') - } - - class PartTestTemplateCreate(AjaxCreateView): """ View for creating a PartTestTemplate """ diff --git a/InvenTree/stock/templates/stock/item_attachments.html b/InvenTree/stock/templates/stock/item_attachments.html index 13e886d8a5..f58d5db063 100644 --- a/InvenTree/stock/templates/stock/item_attachments.html +++ b/InvenTree/stock/templates/stock/item_attachments.html @@ -73,12 +73,15 @@ $("#attachment-table").on('click', '.attachment-edit-button', function() { $("#attachment-table").on('click', '.attachment-delete-button', function() { var button = $(this); - var url = `/stock/item/attachment/${button.attr('pk')}/delete/`; + var pk = button.attr('pk'); - launchModalForm(url, { - success: function() { - location.reload(); - } + var url = `/api/stock/attachment/${pk}/`; + + constructForm(url, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + reload: true, }); }); diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index eb0acbbef2..3e38d48f0e 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -62,11 +62,6 @@ stock_urls = [ url(r'^item/uninstall/', views.StockItemUninstall.as_view(), name='stock-item-uninstall'), - # URLs for StockItem attachments - url(r'^item/attachment/', include([ - url(r'^(?P\d+)/delete/', views.StockItemAttachmentDelete.as_view(), name='stock-item-attachment-delete'), - ])), - # URLs for StockItem tests url(r'^item/test/', include([ url(r'^new/', views.StockItemTestResultCreate.as_view(), name='stock-item-test-create'), diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 5b41bfe1b2..e8a3b8614c 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -32,7 +32,7 @@ from datetime import datetime, timedelta from company.models import Company, SupplierPart from part.models import Part -from .models import StockItem, StockLocation, StockItemTracking, StockItemAttachment, StockItemTestResult +from .models import StockItem, StockLocation, StockItemTracking, StockItemTestResult import common.settings from common.models import InvenTreeSetting @@ -255,22 +255,6 @@ class StockLocationQRCode(QRCodeView): return None -class StockItemAttachmentDelete(AjaxDeleteView): - """ - View for deleting a StockItemAttachment object. - """ - - model = StockItemAttachment - ajax_form_title = _("Delete Stock Item Attachment") - ajax_template_name = "attachment_delete.html" - context_object_name = "attachment" - - def get_data(self): - return { - 'danger': _("Deleted attachment"), - } - - class StockItemAssignToCustomer(AjaxUpdateView): """ View for manually assigning a StockItem to a Customer From 09fff5b64403812e69b35658e3bb0eb88856d7f2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 14:07:15 +1000 Subject: [PATCH 185/445] Refactor PriceBreakCreate form - Handle non_field_errors --- InvenTree/company/serializers.py | 9 +++ .../company/supplier_part_pricing.html | 21 +++++-- InvenTree/company/urls.py | 1 - InvenTree/company/views.py | 61 ------------------- InvenTree/templates/js/forms.js | 30 +++++++++ 5 files changed, 55 insertions(+), 67 deletions(-) diff --git a/InvenTree/company/serializers.py b/InvenTree/company/serializers.py index 9e64fbad0a..9f40365757 100644 --- a/InvenTree/company/serializers.py +++ b/InvenTree/company/serializers.py @@ -2,6 +2,8 @@ JSON serializers for Company app """ +from django.utils.translation import ugettext_lazy as _ + from rest_framework import serializers from sql_util.utils import SubqueryCount @@ -249,6 +251,12 @@ class SupplierPriceBreakSerializer(InvenTreeModelSerializer): price = serializers.CharField() + price_currency = serializers.ChoiceField( + choices=djmoney.settings.CURRENCY_CHOICES, + default=currency_code_default, + label=_('Currency'), + ) + class Meta: model = SupplierPriceBreak fields = [ @@ -256,4 +264,5 @@ class SupplierPriceBreakSerializer(InvenTreeModelSerializer): 'part', 'quantity', 'price', + 'price_currency', ] diff --git a/InvenTree/company/templates/company/supplier_part_pricing.html b/InvenTree/company/templates/company/supplier_part_pricing.html index 89b33049c6..5d2d0c5e31 100644 --- a/InvenTree/company/templates/company/supplier_part_pricing.html +++ b/InvenTree/company/templates/company/supplier_part_pricing.html @@ -98,12 +98,23 @@ $('#price-break-table').inventreeTable({ }); $('#new-price-break').click(function() { - launchModalForm("{% url 'price-break-create' %}", + + constructForm( + '{% url "api-part-supplier-price-list" %}', { - reload: true, - data: { - part: {{ part.id }}, - } + method: 'POST', + fields: { + quantity: {}, + part: { + value: {{ part.pk }}, + hidden: true, + }, + price: {}, + price_currency: { + }, + }, + title: '{% trans "Add Price Break" %}', + reload: true } ); }); diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index 51685215b6..840f95b771 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -40,7 +40,6 @@ company_urls = [ ] price_break_urls = [ - url('^new/', views.PriceBreakCreate.as_view(), name='price-break-create'), url(r'^(?P\d+)/edit/', views.PriceBreakEdit.as_view(), name='price-break-edit'), url(r'^(?P\d+)/delete/', views.PriceBreakDelete.as_view(), name='price-break-delete'), diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index 1b817fe66d..cc046173f9 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -761,67 +761,6 @@ class SupplierPartDelete(AjaxDeleteView): return self.renderJsonResponse(self.request, data=data, form=self.get_form()) -class PriceBreakCreate(AjaxCreateView): - """ View for creating a supplier price break """ - - model = SupplierPriceBreak - form_class = EditPriceBreakForm - ajax_form_title = _('Add Price Break') - ajax_template_name = 'modal_form.html' - - def get_data(self): - return { - 'success': _('Added new price break') - } - - def get_part(self): - """ - Attempt to extract SupplierPart object from the supplied data. - """ - - try: - supplier_part = SupplierPart.objects.get(pk=self.request.GET.get('part')) - return supplier_part - except (ValueError, SupplierPart.DoesNotExist): - pass - - try: - supplier_part = SupplierPart.objects.get(pk=self.request.POST.get('part')) - return supplier_part - except (ValueError, SupplierPart.DoesNotExist): - pass - - return None - - def get_form(self): - - form = super(AjaxCreateView, self).get_form() - form.fields['part'].widget = HiddenInput() - - return form - - def get_initial(self): - - initials = super(AjaxCreateView, self).get_initial() - - supplier_part = self.get_part() - - initials['part'] = self.get_part() - - if supplier_part is not None: - currency_code = supplier_part.supplier.currency_code - else: - currency_code = common.settings.currency_code_default() - - # Extract the currency object associated with the code - currency = CURRENCIES.get(currency_code, None) - - if currency: - initials['price'] = [1.0, currency] - - return initials - - class PriceBreakEdit(AjaxUpdateView): """ View for editing a supplier price break """ diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index d568e40fe7..a4baa8707f 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -302,6 +302,8 @@ function constructFormBody(fields, options) { var html = ''; + html += `
          `; + // Client must provide set of fields to be displayed, // otherwise *all* fields will be displayed var displayed_fields = options.fields || fields; @@ -653,6 +655,9 @@ function clearFormErrors(options) { // Remove the "has error" class $(options.modal).find('.has-error').removeClass('has-error'); + + // Clear the 'non field errors' + $(options.modal).find('#non-field-errors').html(''); } @@ -669,6 +674,31 @@ function handleFormErrors(errors, fields, options) { // Remove any existing error messages from the form clearFormErrors(options); + var non_field_errors = $(options.modal).find('#non-field-errors'); + + non_field_errors.append( + `
          + {% trans "Form errors exist" %} +
          ` + ); + + // Non-field errors? + if ('non_field_errors' in errors) { + + var nfe = errors.non_field_errors; + + for (var idx = 0; idx < nfe.length; idx++) { + var err = nfe[idx]; + + var html = ` +
          + ${err} +
          `; + + non_field_errors.append(html); + } + } + for (field_name in errors) { if (field_name in fields) { From 2b394174bc65a7fa1d9ebf00ccb89e6382252fde Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 14:14:31 +1000 Subject: [PATCH 186/445] Refactor update and delete forms for SupplierPriceBreak --- InvenTree/InvenTree/urls.py | 2 -- InvenTree/company/api.py | 16 ++++++++++- .../company/supplier_part_pricing.html | 28 ++++++++++--------- InvenTree/company/urls.py | 6 ---- InvenTree/company/views.py | 24 ---------------- 5 files changed, 30 insertions(+), 46 deletions(-) diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index 6a7ae7bdfd..8c0cf494be 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -13,7 +13,6 @@ from django.contrib.auth import views as auth_views from company.urls import company_urls from company.urls import manufacturer_part_urls from company.urls import supplier_part_urls -from company.urls import price_break_urls from common.urls import common_urls from part.urls import part_urls @@ -126,7 +125,6 @@ urlpatterns = [ url(r'^part/', include(part_urls)), url(r'^manufacturer-part/', include(manufacturer_part_urls)), url(r'^supplier-part/', include(supplier_part_urls)), - url(r'^price-break/', include(price_break_urls)), # "Dynamic" javascript files which are rendered using InvenTree templating. url(r'^dynamic/', include(dynamic_javascript_urls)), diff --git a/InvenTree/company/api.py b/InvenTree/company/api.py index 16887414de..6eac0339fa 100644 --- a/InvenTree/company/api.py +++ b/InvenTree/company/api.py @@ -394,6 +394,15 @@ class SupplierPriceBreakList(generics.ListCreateAPIView): ] +class SupplierPriceBreakDetail(generics.RetrieveUpdateDestroyAPIView): + """ + Detail endpoint for SupplierPriceBreak object + """ + + queryset = SupplierPriceBreak.objects.all() + serializer_class = SupplierPriceBreakSerializer + + manufacturer_part_api_urls = [ url(r'^parameter/', include([ @@ -424,7 +433,12 @@ company_api_urls = [ url(r'^part/', include(supplier_part_api_urls)), - url(r'^price-break/', SupplierPriceBreakList.as_view(), name='api-part-supplier-price-list'), + # Supplier price breaks + url(r'^price-break/', include([ + + url(r'^(?P\d+)/?', SupplierPriceBreakDetail.as_view(), name='api-part-supplier-price-detail'), + url(r'^.*$', SupplierPriceBreakList.as_view(), name='api-part-supplier-price-list'), + ])), url(r'^(?P\d+)/?', CompanyDetail.as_view(), name='api-company-detail'), diff --git a/InvenTree/company/templates/company/supplier_part_pricing.html b/InvenTree/company/templates/company/supplier_part_pricing.html index 5d2d0c5e31..a476b53a13 100644 --- a/InvenTree/company/templates/company/supplier_part_pricing.html +++ b/InvenTree/company/templates/company/supplier_part_pricing.html @@ -46,23 +46,25 @@ $('#price-break-table').inventreeTable({ table.find('.button-price-break-delete').click(function() { var pk = $(this).attr('pk'); - launchModalForm( - `/price-break/${pk}/delete/`, - { - success: reloadPriceBreaks - } - ); + constructForm(`/api/company/price-break/${pk}/`, { + method: 'DELETE', + onSuccess: reloadPriceBreaks, + title: '{% trans "Delete Price Break" %}', + }); }); table.find('.button-price-break-edit').click(function() { var pk = $(this).attr('pk'); - launchModalForm( - `/price-break/${pk}/edit/`, - { - success: reloadPriceBreaks - } - ); + constructForm(`/api/company/price-break/${pk}/`, { + fields: { + quantity: {}, + price: {}, + price_currency: {}, + }, + onSuccess: reloadPriceBreaks, + title: '{% trans "Edit Price Break" %}', + }); }); }, columns: [ @@ -114,7 +116,7 @@ $('#new-price-break').click(function() { }, }, title: '{% trans "Add Price Break" %}', - reload: true + onSuccess: reloadPriceBreaks, } ); }); diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index 840f95b771..47a57d1df0 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -39,12 +39,6 @@ company_urls = [ url(r'^.*$', views.CompanyIndex.as_view(), name='company-index'), ] -price_break_urls = [ - - url(r'^(?P\d+)/edit/', views.PriceBreakEdit.as_view(), name='price-break-edit'), - url(r'^(?P\d+)/delete/', views.PriceBreakDelete.as_view(), name='price-break-delete'), -] - manufacturer_part_urls = [ url(r'^new/?', views.ManufacturerPartCreate.as_view(), name='manufacturer-part-create'), diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index cc046173f9..67c4e45a2e 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -759,27 +759,3 @@ class SupplierPartDelete(AjaxDeleteView): part.delete() return self.renderJsonResponse(self.request, data=data, form=self.get_form()) - - -class PriceBreakEdit(AjaxUpdateView): - """ View for editing a supplier price break """ - - model = SupplierPriceBreak - form_class = EditPriceBreakForm - ajax_form_title = _('Edit Price Break') - ajax_template_name = 'modal_form.html' - - def get_form(self): - - form = super(AjaxUpdateView, self).get_form() - form.fields['part'].widget = HiddenInput() - - return form - - -class PriceBreakDelete(AjaxDeleteView): - """ View for deleting a supplier price break """ - - model = SupplierPriceBreak - ajax_form_title = _("Delete Price Break") - ajax_template_name = 'modal_delete_form.html' From a92fc7cf2c12ac93e8fdbf618196c4792c89c6f5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 14:15:18 +1000 Subject: [PATCH 187/445] PEP fixes --- InvenTree/company/api.py | 2 +- InvenTree/company/views.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/InvenTree/company/api.py b/InvenTree/company/api.py index 6eac0339fa..999e4e4039 100644 --- a/InvenTree/company/api.py +++ b/InvenTree/company/api.py @@ -438,7 +438,7 @@ company_api_urls = [ url(r'^(?P\d+)/?', SupplierPriceBreakDetail.as_view(), name='api-part-supplier-price-detail'), url(r'^.*$', SupplierPriceBreakList.as_view(), name='api-part-supplier-price-list'), - ])), + ])), url(r'^(?P\d+)/?', CompanyDetail.as_view(), name='api-company-detail'), diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index 67c4e45a2e..01b602d20a 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -26,14 +26,12 @@ from InvenTree.views import InvenTreeRoleMixin from .models import Company, ManufacturerPartParameter from .models import ManufacturerPart from .models import SupplierPart -from .models import SupplierPriceBreak from part.models import Part from .forms import EditManufacturerPartParameterForm from .forms import EditManufacturerPartForm from .forms import EditSupplierPartForm -from .forms import EditPriceBreakForm from .forms import CompanyImageDownloadForm import common.models From 682b2b4b2fa6bf3bd4f75ae9445e01b1c44b1304 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 17:04:21 +1000 Subject: [PATCH 188/445] Support rendering / updating of date inputs --- .../order/purchase_order_detail.html | 3 +- InvenTree/templates/js/forms.js | 44 +++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index 0ad73923a2..e5542f5816 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -21,7 +21,8 @@
          {% if order.status == PurchaseOrderStatus.PENDING and roles.purchase_order.change %} + {% trans "Add Line Item" %} + {% endif %}
          diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index a4baa8707f..de25b80146 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -501,6 +501,7 @@ function submitFormData(fields, options) { has_files = true; } } else { + // Normal field (not a file or image) form_data.append(name, value); @@ -601,12 +602,27 @@ function getFormFieldValue(name, field, options) { // Find the HTML element var el = $(options.modal).find(`#id_${name}`); + var value = null; + switch (field.type) { case 'boolean': - return el.is(":checked"); + value = el.is(":checked"); + break; + case 'date': + case 'datetime': + value = el.val(); + + // Ensure empty values are sent as nulls + if (!value || value.length == 0) { + value = null; + } + break; default: - return el.val(); + value = el.val(); + break; } + + return value; } @@ -705,7 +721,7 @@ function handleFormErrors(errors, fields, options) { // Add the 'has-error' class $(options.modal).find(`#div_id_${field_name}`).addClass('has-error'); - var field_dom = $(options.modal).find(`#id_${field_name}`); + var field_dom = $(options.modal).find(`#errors-${field_name}`); // $(options.modal).find(`#id_${field_name}`); var field_errors = errors[field_name]; @@ -719,7 +735,7 @@ function handleFormErrors(errors, fields, options) { ${error_text} `; - $(html).insertAfter(field_dom); + field_dom.append(html); } } else { @@ -1091,6 +1107,9 @@ function constructField(name, parameters, options) { html += `
          `; // input-group } + // Div for error messages + html += `
          `; + if (parameters.help_text) { html += constructHelpText(name, parameters, options); } @@ -1173,6 +1192,9 @@ function constructInput(name, parameters, options) { case 'file upload': func = constructFileUploadInput; break; + case 'date': + func = constructDateInput; + break; default: // Unsupported field type! break; @@ -1380,6 +1402,20 @@ function constructFileUploadInput(name, parameters, options) { } +/* + * Construct a field for a date input + */ +function constructDateInput(name, parameters, options) { + + return constructInputOptions( + name, + 'dateinput form-control', + 'date', + parameters + ); +} + + /* * Construct a 'help text' div based on the field parameters * From 9b4db43232542f26e7d46766aad50d9fa49d5bf4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 17:40:44 +1000 Subject: [PATCH 189/445] Refactoring "attachment" tables to use the API - Part attachments - StockItem attachments - PurchaseOrder attachments - SalesOrder attachments - BuildOrder attachments --- InvenTree/InvenTree/urls.py | 1 + .../build/templates/build/attachments.html | 51 ++++++------ .../order/templates/order/po_attachments.html | 62 +++++++------- .../order/templates/order/so_attachments.html | 65 +++++++-------- .../part/templates/part/attachments.html | 67 ++++++++------- .../templates/stock/item_attachments.html | 67 +++++++-------- InvenTree/templates/attachment_table.html | 31 +------ InvenTree/templates/base.html | 1 + InvenTree/templates/js/attachment.js | 82 +++++++++++++++++++ 9 files changed, 234 insertions(+), 193 deletions(-) create mode 100644 InvenTree/templates/js/attachment.js diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index 8c0cf494be..6a0d02263d 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -103,6 +103,7 @@ settings_urls = [ # Some javascript files are served 'dynamically', allowing them to pass through the Django translation layer dynamic_javascript_urls = [ url(r'^api.js', DynamicJsView.as_view(template_name='js/api.js'), name='api.js'), + url(r'^attachment.js', DynamicJsView.as_view(template_name='js/attachment.js'), name='attachment.js'), url(r'^forms.js', DynamicJsView.as_view(template_name='js/forms.js'), name='forms.js'), url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/model_renderers.js'), name='model_renderers.js'), url(r'^modals.js', DynamicJsView.as_view(template_name='js/modals.js'), name='modals.js'), diff --git a/InvenTree/build/templates/build/attachments.html b/InvenTree/build/templates/build/attachments.html index 728c02fca7..e969756b81 100644 --- a/InvenTree/build/templates/build/attachments.html +++ b/InvenTree/build/templates/build/attachments.html @@ -47,37 +47,38 @@ $('#new-attachment').click(function() { } }, method: 'POST', - reload: true, + onSuccess: reloadAttachmentTable, title: '{% trans "Add Attachment" %}', }); }); -// Callback for editing an attachment -$("#attachment-table").on('click', '.attachment-edit-button', function() { - var pk = $(this).attr('pk'); - - constructForm(`/api/build/attachment/${pk}/`, { - fields: { - attachment: {}, - comment: {}, +loadAttachmentTable( + '{% url "api-build-attachment-list" %}', + { + filters: { + build: {{ build.pk }}, }, - reload: true, - title: '{% trans "Edit Attachment" %}', - }); -}); + onEdit: function(pk) { + var url = `/api/build/attachment/${pk}/`; -// Callback for deleting an attachment -$("#attachment-table").on('click', '.attachment-delete-button', function() { - var pk = $(this).attr('pk'); + constructForm(url, { + fields: { + comment: {}, + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Edit Attachment" %}', + }); + }, + onDelete: function(pk) { - constructForm(`/api/build/attachment/${pk}/`, { - method: 'DELETE', - confirmMessage: '{% trans "Confirm Delete Operation" %}', - title: '{% trans "Delete Attachment" %}', - reload: true, - }); -}); - -$("#attachment-table").inventreeTable({}); + constructForm(`/api/build/attachment/${pk}/`, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } +); {% endblock %} diff --git a/InvenTree/order/templates/order/po_attachments.html b/InvenTree/order/templates/order/po_attachments.html index a6ea769aee..07e425016b 100644 --- a/InvenTree/order/templates/order/po_attachments.html +++ b/InvenTree/order/templates/order/po_attachments.html @@ -34,6 +34,35 @@ enableDragAndDrop( } ); +loadAttachmentTable( + '{% url "api-po-attachment-list" %}', + { + filters: { + order: {{ order.pk }}, + }, + onEdit: function(pk) { + var url = `/api/order/po/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Edit Attachment" %}', + }); + }, + onDelete: function(pk) { + + constructForm(`/api/order/po/attachment/${pk}/`, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } +); + $("#new-attachment").click(function() { constructForm('{% url "api-po-attachment-list" %}', { @@ -51,37 +80,4 @@ $("#new-attachment").click(function() { }); }); -$("#attachment-table").on('click', '.attachment-edit-button', function() { - var button = $(this); - - var pk = button.attr('pk'); - - var url = `/api/order/po/attachment/${pk}/`; - - constructForm(url, { - fields: { - attachment: {}, - comment: {}, - }, - reload: true, - title: '{% trans "Edit Attachment" %}', - }); -}); - -$("#attachment-table").on('click', '.attachment-delete-button', function() { - var button = $(this); - - var pk = button.attr('pk'); - - constructForm(`/api/order/po/attachment/${pk}/`, { - method: 'DELETE', - confirmMessage: '{% trans "Confirm Delete Operation" %}', - title: '{% trans "Delete Attachment" %}', - reload: true, - }); -}); - -$("#attachment-table").inventreeTable({ -}); - {% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/so_attachments.html b/InvenTree/order/templates/order/so_attachments.html index 6df93bbe45..89f09541d1 100644 --- a/InvenTree/order/templates/order/so_attachments.html +++ b/InvenTree/order/templates/order/so_attachments.html @@ -35,6 +35,36 @@ enableDragAndDrop( } ); +loadAttachmentTable( + '{% url "api-so-attachment-list" %}', + { + filters: { + order: {{ order.pk }}, + }, + onEdit: function(pk) { + var url = `/api/order/so/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Edit Attachment" %}', + }); + }, + onDelete: function(pk) { + var pk = button.attr('pk'); + + constructForm(`/api/order/so/attachment/${pk}/`, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } +); + $("#new-attachment").click(function() { constructForm('{% url "api-so-attachment-list" %}', { @@ -47,42 +77,9 @@ $("#new-attachment").click(function() { hidden: true } }, - reload: true, + onSuccess: reloadAttachmentTable, title: '{% trans "Add Attachment" %}' }); }); -$("#attachment-table").on('click', '.attachment-edit-button', function() { - var button = $(this); - - var pk = button.attr('pk'); - - var url = `/api/order/so/attachment/${pk}/`; - - constructForm(url, { - fields: { - attachment: {}, - comment: {}, - }, - reload: true, - title: '{% trans "Edit Attachment" %}', - }); -}); - -$("#attachment-table").on('click', '.attachment-delete-button', function() { - var button = $(this); - - var pk = button.attr('pk'); - - constructForm(`/api/order/so/attachment/${pk}/`, { - method: 'DELETE', - confirmMessage: '{% trans "Confirm Delete Operation" %}', - title: '{% trans "Delete Attachment" %}', - reload: true, - }); -}); - -$("#attachment-table").inventreeTable({ -}); - {% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/attachments.html b/InvenTree/part/templates/part/attachments.html index 5fca535098..7128980472 100644 --- a/InvenTree/part/templates/part/attachments.html +++ b/InvenTree/part/templates/part/attachments.html @@ -19,6 +19,36 @@ {% block js_ready %} {{ block.super }} + loadAttachmentTable( + '{% url "api-part-attachment-list" %}', + { + filters: { + part: {{ part.pk }}, + }, + onEdit: function(pk) { + var url = `/api/part/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + title: '{% trans "Edit Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + }, + onDelete: function(pk) { + var url = `/api/part/attachment/${pk}/`; + + constructForm(url, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } + ); + enableDragAndDrop( '#attachment-dropzone', '{% url "api-part-attachment-list" %}', @@ -28,7 +58,7 @@ }, label: 'attachment', success: function(data, status, xhr) { - location.reload(); + reloadAttachmentTable(); } } ); @@ -47,43 +77,10 @@ hidden: true, } }, - reload: true, + onSuccess: reloadAttachmentTable, title: '{% trans "Add Attachment" %}', } ) }); - $("#attachment-table").on('click', '.attachment-edit-button', function() { - var button = $(this); - - var pk = button.attr('pk'); - - var url = `/api/part/attachment/${pk}/`; - - constructForm(url, { - fields: { - attachment: {}, - comment: {}, - }, - title: '{% trans "Edit Attachment" %}', - reload: true, - }); - }); - - $("#attachment-table").on('click', '.attachment-delete-button', function() { - var button = $(this); - var pk = button.attr('pk'); - var url = `/api/part/attachment/${pk}/`; - - constructForm(url, { - method: 'DELETE', - confirmMessage: '{% trans "Confirm Delete Operation" %}', - title: '{% trans "Delete Attachment" %}', - reload: true, - }); - }); - - $("#attachment-table").inventreeTable({ - }); - {% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/item_attachments.html b/InvenTree/stock/templates/stock/item_attachments.html index f58d5db063..34ceecc550 100644 --- a/InvenTree/stock/templates/stock/item_attachments.html +++ b/InvenTree/stock/templates/stock/item_attachments.html @@ -28,11 +28,41 @@ enableDragAndDrop( }, label: 'attachment', success: function(data, status, xhr) { - location.reload(); + reloadAttachmentTable(); } } ); +loadAttachmentTable( + '{% url "api-stock-attachment-list" %}', + { + filters: { + item: {{ item.pk }}, + }, + onEdit: function(pk) { + var url = `/api/stock/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + title: '{% trans "Edit Attachment" %}', + onSuccess: reloadAttachmentTable + }); + }, + onDelete: function(pk) { + var url = `/api/stock/attachment/${pk}/`; + + constructForm(url, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } +); + $("#new-attachment").click(function() { constructForm( @@ -53,39 +83,4 @@ $("#new-attachment").click(function() { ); }); -$("#attachment-table").on('click', '.attachment-edit-button', function() { - var button = $(this); - - var pk = button.attr('pk'); - - var url = `/api/stock/attachment/${pk}/`; - - constructForm(url, { - fields: { - attachment: {}, - comment: {}, - }, - title: '{% trans "Edit Attachment" %}', - reload: true - }); -}); - -$("#attachment-table").on('click', '.attachment-delete-button', function() { - var button = $(this); - - var pk = button.attr('pk'); - - var url = `/api/stock/attachment/${pk}/`; - - constructForm(url, { - method: 'DELETE', - confirmMessage: '{% trans "Confirm Delete Operation" %}', - title: '{% trans "Delete Attachment" %}', - reload: true, - }); -}); - -$("#attachment-table").inventreeTable({ -}); - {% endblock %} \ No newline at end of file diff --git a/InvenTree/templates/attachment_table.html b/InvenTree/templates/attachment_table.html index 35b114cc05..18a4da9acc 100644 --- a/InvenTree/templates/attachment_table.html +++ b/InvenTree/templates/attachment_table.html @@ -10,35 +10,6 @@
          {% trans 'Supplier Pricing' %}{% trans 'Supplier Pricing' %} + + + {% trans 'Unit Cost' %} Min: {% include "price.html" with price=min_unit_buy_price %} Max: {% include "price.html" with price=max_unit_buy_price %}
          {% trans 'BOM Pricing' %}{% trans 'BOM Pricing' %} + + {% trans 'Unit Cost' %} Min: {% include "price.html" with price=min_unit_bom_price %} Max: {% include "price.html" with price=max_unit_bom_price %}
          {% trans 'Sale Price' %}{% trans 'Sale Price' %} + + + {% trans 'Unit Cost' %} {% include "price.html" with price=unit_part_price %}
          - - - - - - - - - - {% for attachment in attachments %} - - - - - - - {% endfor %} - +
          {% trans "File" %}{% trans "Comment" %}{% trans "Uploaded" %}
          {{ attachment.basename }}{{ attachment.comment }} - {% if attachment.upload_date %}{{ attachment.upload_date }}{% endif %} - {% if attachment.user %}{{ attachment.user.username }}{% endif %} - -
          - - -
          -
          \ No newline at end of file diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html index ec7e31a7f0..76104d8fe2 100644 --- a/InvenTree/templates/base.html +++ b/InvenTree/templates/base.html @@ -149,6 +149,7 @@ + diff --git a/InvenTree/templates/js/attachment.js b/InvenTree/templates/js/attachment.js new file mode 100644 index 0000000000..4fce7e06fe --- /dev/null +++ b/InvenTree/templates/js/attachment.js @@ -0,0 +1,82 @@ +{% load i18n %} + +function reloadAttachmentTable() { + + $('#attachment-table').bootstrapTable("refresh"); +} + + +function loadAttachmentTable(url, options) { + + var table = options.table || '#attachment-table'; + + $(table).inventreeTable({ + url: url, + name: options.name || 'attachments', + formatNoMatches: function() { return '{% trans "No attachments found" %}'}, + sortable: true, + search: false, + queryParams: options.filters || {}, + onPostBody: function() { + // Add callback for 'edit' button + $(table).find('.button-attachment-edit').click(function() { + var pk = $(this).attr('pk'); + + if (options.onEdit) { + options.onEdit(pk); + } + }); + + // Add callback for 'delete' button + $(table).find('.button-attachment-delete').click(function() { + var pk = $(this).attr('pk'); + + if (options.onDelete) { + options.onDelete(pk); + } + }); + }, + columns: [ + { + field: 'attachment', + title: '{% trans "File" %}', + formatter: function(value, row) { + + var split = value.split('/'); + + return renderLink(split[split.length - 1], value); + } + }, + { + field: 'comment', + title: '{% trans "Comment" %}', + }, + { + field: 'actions', + formatter: function(value, row) { + var html = ''; + + html = `
          `; + + html += makeIconButton( + 'fa-edit icon-blue', + 'button-attachment-edit', + row.pk, + '{% trans "Edit attachment" %}', + ); + + html += makeIconButton( + 'fa-trash-alt icon-red', + 'button-attachment-delete', + row.pk, + '{% trans "Delete attachment" %}', + ); + + html += `
          `; + + return html; + } + } + ] + }); +} \ No newline at end of file From 30ac5dba5550bd9dbad77d8dde97b66256371877 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 17:44:23 +1000 Subject: [PATCH 190/445] Display attachment upload date --- InvenTree/build/serializers.py | 7 ++++++- InvenTree/order/serializers.py | 10 ++++++++++ InvenTree/part/serializers.py | 7 ++++++- InvenTree/stock/serializers.py | 5 +++++ InvenTree/templates/js/attachment.js | 4 ++++ 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/InvenTree/build/serializers.py b/InvenTree/build/serializers.py index 06c4f36ebb..e33fcb6c7f 100644 --- a/InvenTree/build/serializers.py +++ b/InvenTree/build/serializers.py @@ -159,5 +159,10 @@ class BuildAttachmentSerializer(InvenTreeModelSerializer): 'pk', 'build', 'attachment', - 'comment' + 'comment', + 'upload_date', + ] + + read_only_fields = [ + 'upload_date', ] diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py index e527b3cec9..f1eac82530 100644 --- a/InvenTree/order/serializers.py +++ b/InvenTree/order/serializers.py @@ -157,6 +157,11 @@ class POAttachmentSerializer(InvenTreeModelSerializer): 'order', 'attachment', 'comment', + 'upload_date', + ] + + read_only_fields = [ + 'upload_date', ] @@ -359,4 +364,9 @@ class SOAttachmentSerializer(InvenTreeModelSerializer): 'order', 'attachment', 'comment', + 'upload_date', + ] + + read_only_fields = [ + 'upload_date', ] diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index fb5480f668..b8b9b92d5e 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -61,7 +61,12 @@ class PartAttachmentSerializer(InvenTreeModelSerializer): 'pk', 'part', 'attachment', - 'comment' + 'comment', + 'upload_date', + ] + + read_only_fields = [ + 'upload_date', ] diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index 38301bdd1f..c4ac404591 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -270,6 +270,11 @@ class LocationSerializer(InvenTreeModelSerializer): 'parent', 'pathstring', 'items', + 'upload_date', + ] + + read_only_fields = [ + 'upload_date', ] diff --git a/InvenTree/templates/js/attachment.js b/InvenTree/templates/js/attachment.js index 4fce7e06fe..4b9d522a59 100644 --- a/InvenTree/templates/js/attachment.js +++ b/InvenTree/templates/js/attachment.js @@ -51,6 +51,10 @@ function loadAttachmentTable(url, options) { field: 'comment', title: '{% trans "Comment" %}', }, + { + field: 'upload_date', + title: '{% trans "Upload Date" %}', + }, { field: 'actions', formatter: function(value, row) { From 770cd9a12d250787716d761b0f3005832df9f771 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 22:10:15 +1000 Subject: [PATCH 191/445] Fix for LocationSerializer --- InvenTree/stock/serializers.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index c4ac404591..38301bdd1f 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -270,11 +270,6 @@ class LocationSerializer(InvenTreeModelSerializer): 'parent', 'pathstring', 'items', - 'upload_date', - ] - - read_only_fields = [ - 'upload_date', ] From 54731746d814025ccdac214117baa36a045f9cb2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 30 Jun 2021 23:18:50 +1000 Subject: [PATCH 192/445] Render simple choice fields with select2 --- InvenTree/templates/js/forms.js | 46 ++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index de25b80146..76f0dba2dd 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -2,21 +2,23 @@ {% load inventree_extras %} /** + * * This file contains code for rendering (and managing) HTML forms * which are served via the django-drf API. - * + * * The django DRF library provides an OPTIONS method for each API endpoint, * which allows us to introspect the available fields at any given endpoint. - * + * * The OPTIONS method provides the following information for each available field: - * + * * - Field name * - Field label (translated) * - Field help text (translated) * - Field type * - Read / write status * - Field required status - * - min_value / max_value + * - min_value / max_value + * */ /* @@ -785,17 +787,16 @@ function initializeRelatedFields(fields, options) { var field = fields[name] || null; - if (!field || field.type != 'related field') continue; + if (!field || field.hidden) continue; - if (field.hidden) continue; - - if (!field.api_url) { - // TODO: Provide manual api_url option? - console.log(`Related field '${name}' missing 'api_url' parameter.`); - continue; + switch (field.type) { + case 'related field': + initializeRelatedField(name, field, options); + break; + case 'choice': + initializeChoiceField(name, field, options); + break; } - - initializeRelatedField(name, field, options); } } @@ -834,6 +835,12 @@ function addSecondaryModal(name, field, options) { */ function initializeRelatedField(name, field, options) { + if (!field.api_url) { + // TODO: Provide manual api_url option? + console.log(`Related field '${name}' missing 'api_url' parameter.`); + return; + } + // Find the select element and attach a select2 to it var select = $(options.modal).find(`#id_${name}`); @@ -995,6 +1002,17 @@ function initializeRelatedField(name, field, options) { } +function initializeChoiceField(name, field, options) { + + var select = $(options.modal).find(`#id_${name}`); + + select.select2({ + dropdownAutoWidth: false, + dropdownParent: $(options.modal), + }); +} + + // Render a 'no results' element function searching() { return `{% trans "Searching" %}...`; @@ -1343,8 +1361,6 @@ function constructChoiceInput(name, parameters, options) { var choices = parameters.choices || []; - // TODO: Select the selected value! - for (var idx = 0; idx < choices.length; idx++) { var choice = choices[idx]; From 88f57a211f06865a028e25e20f3d75cae49047dc Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 30 Jun 2021 23:35:57 +0200 Subject: [PATCH 193/445] setting for default currency --- InvenTree/common/models.py | 1 + InvenTree/templates/InvenTree/settings/currencies.html | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 7e56429c51..9bd3612e55 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -14,6 +14,7 @@ from django.db import models, transaction from django.db.utils import IntegrityError, OperationalError from django.conf import settings +from djmoney.settings import CURRENCY_CHOICES from djmoney.models.fields import MoneyField from djmoney.contrib.exchange.models import convert_money from djmoney.contrib.exchange.exceptions import MissingRate diff --git a/InvenTree/templates/InvenTree/settings/currencies.html b/InvenTree/templates/InvenTree/settings/currencies.html index 78598236f9..6e61533e6b 100644 --- a/InvenTree/templates/InvenTree/settings/currencies.html +++ b/InvenTree/templates/InvenTree/settings/currencies.html @@ -12,6 +12,13 @@ {% block settings %} + + {% include "InvenTree/settings/header.html" %} + + {% include "InvenTree/settings/setting.html" with key="INVENTREE_DEFAULT_CURRENCY" icon="fa-globe" %} + +
          + From 92645d790bfdfc600adeac2200a25329a8034641 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 30 Jun 2021 23:36:46 +0200 Subject: [PATCH 194/445] use setting for currency_code_default --- InvenTree/common/settings.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/InvenTree/common/settings.py b/InvenTree/common/settings.py index 60265f4cb9..299d142ea9 100644 --- a/InvenTree/common/settings.py +++ b/InvenTree/common/settings.py @@ -8,7 +8,6 @@ from __future__ import unicode_literals from moneyed import CURRENCIES import common.models -from django.conf import settings def currency_code_default(): @@ -16,7 +15,7 @@ def currency_code_default(): Returns the default currency code (or USD if not specified) """ - code = settings.BASE_CURRENCY + code = common.models.InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY') if code not in CURRENCIES: code = 'USD' From 2c7a4a124659824a607b6e2b62c1b8f371738111 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 30 Jun 2021 23:38:48 +0200 Subject: [PATCH 195/445] switching out BASE_CURRENCY --- InvenTree/InvenTree/apps.py | 3 ++- InvenTree/InvenTree/exchange.py | 3 ++- InvenTree/InvenTree/settings.py | 4 ---- InvenTree/InvenTree/tasks.py | 3 ++- InvenTree/InvenTree/views.py | 3 ++- InvenTree/part/views.py | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/InvenTree/InvenTree/apps.py b/InvenTree/InvenTree/apps.py index aeddb714a0..79269d7b74 100644 --- a/InvenTree/InvenTree/apps.py +++ b/InvenTree/InvenTree/apps.py @@ -66,10 +66,11 @@ class InvenTreeConfig(AppConfig): from djmoney.contrib.exchange.models import ExchangeBackend from datetime import datetime, timedelta from InvenTree.tasks import update_exchange_rates + from common.settings import currency_code_default except AppRegistryNotReady: pass - base_currency = settings.BASE_CURRENCY + base_currency = currency_code_default() update = False diff --git a/InvenTree/InvenTree/exchange.py b/InvenTree/InvenTree/exchange.py index 0695e69f48..f5c1ad4d48 100644 --- a/InvenTree/InvenTree/exchange.py +++ b/InvenTree/InvenTree/exchange.py @@ -1,4 +1,5 @@ from django.conf import settings as inventree_settings +from common.settings import currency_code_default from djmoney.contrib.exchange.backends.base import SimpleExchangeBackend @@ -22,7 +23,7 @@ class InvenTreeExchange(SimpleExchangeBackend): return { } - def update_rates(self, base_currency=inventree_settings.BASE_CURRENCY): + def update_rates(self, base_currency=currency_code_default()): symbols = ','.join(inventree_settings.CURRENCIES) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index e0bc1ccb95..6c1d52487d 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -522,10 +522,6 @@ for currency in CURRENCIES: print(f"Currency code '{currency}' is not supported") sys.exit(1) -BASE_CURRENCY = get_setting( - 'INVENTREE_BASE_CURRENCY', - CONFIG.get('base_currency', 'USD') -) # Custom currency exchange backend EXCHANGE_BACKEND = 'InvenTree.exchange.InvenTreeExchange' diff --git a/InvenTree/InvenTree/tasks.py b/InvenTree/InvenTree/tasks.py index f0fe504072..6397ea72e7 100644 --- a/InvenTree/InvenTree/tasks.py +++ b/InvenTree/InvenTree/tasks.py @@ -171,6 +171,7 @@ def update_exchange_rates(): from InvenTree.exchange import InvenTreeExchange from djmoney.contrib.exchange.models import ExchangeBackend, Rate from django.conf import settings + from common.settings import currency_code_default except AppRegistryNotReady: # Apps not yet loaded! logger.info("Could not perform 'update_exchange_rates' - App registry not ready") @@ -192,7 +193,7 @@ def update_exchange_rates(): backend = InvenTreeExchange() print(f"Updating exchange rates from {backend.url}") - base = settings.BASE_CURRENCY + base = currency_code_default() print(f"Using base currency '{base}'") diff --git a/InvenTree/InvenTree/views.py b/InvenTree/InvenTree/views.py index 17caeb872d..9a5e7176a1 100644 --- a/InvenTree/InvenTree/views.py +++ b/InvenTree/InvenTree/views.py @@ -21,6 +21,7 @@ from django.views.generic import ListView, DetailView, CreateView, FormView, Del from django.views.generic.base import RedirectView, TemplateView from djmoney.contrib.exchange.models import ExchangeBackend, Rate +from common.settings import currency_code_default from part.models import Part, PartCategory from stock.models import StockLocation, StockItem @@ -820,7 +821,7 @@ class CurrencySettingsView(TemplateView): ctx = super().get_context_data(**kwargs).copy() ctx['settings'] = InvenTreeSetting.objects.all().order_by('key') - ctx["base_currency"] = settings.BASE_CURRENCY + ctx["base_currency"] = currency_code_default() ctx["currencies"] = settings.CURRENCIES ctx["rates"] = Rate.objects.filter(backend="InvenTreeExchange") diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 2f129dd30b..294f89223e 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -2949,7 +2949,7 @@ class PartSalePriceBreakCreate(AjaxCreateView): initials['part'] = self.get_part() - default_currency = settings.BASE_CURRENCY + default_currency = inventree_settings.currency_code_default() currency = CURRENCIES.get(default_currency, None) if currency is not None: From 4fa57aee16ba46880de16a8019e0c040bb9c7b7d Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 30 Jun 2021 23:48:43 +0200 Subject: [PATCH 196/445] changing method call to avoid circle ref --- InvenTree/common/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 9bd3612e55..ca60c1bf9a 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -19,7 +19,7 @@ from djmoney.models.fields import MoneyField from djmoney.contrib.exchange.models import convert_money from djmoney.contrib.exchange.exceptions import MissingRate -from common.settings import currency_code_default +import common.settings from django.utils.translation import ugettext_lazy as _ from django.core.validators import MinValueValidator, URLValidator @@ -739,7 +739,7 @@ class PriceBreak(models.Model): price = MoneyField( max_digits=19, decimal_places=4, - default_currency=currency_code_default(), + default_currency=lambda: common.settings.currency_code_default(), null=True, verbose_name=_('Price'), help_text=_('Unit price at specified quantity'), @@ -792,7 +792,7 @@ def get_price(instance, quantity, moq=True, multiples=True, currency=None, break if currency is None: # Default currency selection - currency = currency_code_default() + currency = common.settings.currency_code_default() pb_min = None for pb in price_breaks: From 56b23389d3a3188315b119b7dbac971f40419780 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 30 Jun 2021 23:54:56 +0200 Subject: [PATCH 197/445] missed the settings definition --- InvenTree/common/models.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index ca60c1bf9a..55dc760d55 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -82,6 +82,13 @@ class InvenTreeSetting(models.Model): 'default': '', }, + 'INVENTREE_DEFAULT_CURRENCY': { + 'name': _('Default Currency'), + 'description': _('Default currency'), + 'default': 'USD', + 'choices': CURRENCY_CHOICES, + }, + 'INVENTREE_DOWNLOAD_FROM_URL': { 'name': _('Download from URL'), 'description': _('Allow download of remote images and files from external URL'), From 3a57093b4ede3eb0f46f5f9a11a88e486af4308d Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 00:13:38 +0200 Subject: [PATCH 198/445] replace MoneyFields with inherited classes --- InvenTree/InvenTree/fields.py | 10 ++++++++++ InvenTree/common/models.py | 3 +-- InvenTree/company/forms.py | 5 ++--- InvenTree/order/forms.py | 6 ++---- InvenTree/order/models.py | 8 +++----- InvenTree/stock/models.py | 6 ++---- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/InvenTree/InvenTree/fields.py b/InvenTree/InvenTree/fields.py index c496c1bb22..25fbf77c90 100644 --- a/InvenTree/InvenTree/fields.py +++ b/InvenTree/InvenTree/fields.py @@ -13,6 +13,8 @@ from django.core import validators from django import forms from decimal import Decimal +from djmoney.models.fields import MoneyField as ModelMoneyField +from djmoney.forms.fields import MoneyField import InvenTree.helpers @@ -34,6 +36,14 @@ class InvenTreeURLField(models.URLField): }) +class InvenTreeModelMoneyField(ModelMoneyField): + pass + + +class InvenTreeMoneyField(MoneyField): + pass + + class DatePickerFormField(forms.DateField): """ Custom date-picker field diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 55dc760d55..cb6329bb39 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -15,7 +15,6 @@ from django.db.utils import IntegrityError, OperationalError from django.conf import settings from djmoney.settings import CURRENCY_CHOICES -from djmoney.models.fields import MoneyField from djmoney.contrib.exchange.models import convert_money from djmoney.contrib.exchange.exceptions import MissingRate @@ -743,7 +742,7 @@ class PriceBreak(models.Model): help_text=_('Price break quantity'), ) - price = MoneyField( + price = InvenTree.fields.InvenTreeModelMoneyField( max_digits=19, decimal_places=4, default_currency=lambda: common.settings.currency_code_default(), diff --git a/InvenTree/company/forms.py b/InvenTree/company/forms.py index 80673b4fa4..c9497ab89f 100644 --- a/InvenTree/company/forms.py +++ b/InvenTree/company/forms.py @@ -6,13 +6,12 @@ Django Forms for interacting with Company app from __future__ import unicode_literals from InvenTree.forms import HelperForm -from InvenTree.fields import RoundingDecimalFormField +from InvenTree.fields import InvenTreeMoneyField, RoundingDecimalFormField from django.utils.translation import ugettext_lazy as _ import django.forms import djmoney.settings -from djmoney.forms.fields import MoneyField from common.settings import currency_code_default @@ -129,7 +128,7 @@ class EditSupplierPartForm(HelperForm): 'note': 'fa-pencil-alt', } - single_pricing = MoneyField( + single_pricing = InvenTreeMoneyField( label=_('Single Price'), default_currency=currency_code_default(), help_text=_('Single quantity price'), diff --git a/InvenTree/order/forms.py b/InvenTree/order/forms.py index 48b5245a5f..3dd687c685 100644 --- a/InvenTree/order/forms.py +++ b/InvenTree/order/forms.py @@ -10,10 +10,8 @@ from django.utils.translation import ugettext_lazy as _ from mptt.fields import TreeNodeChoiceField -from djmoney.forms.fields import MoneyField - from InvenTree.forms import HelperForm -from InvenTree.fields import RoundingDecimalFormField +from InvenTree.fields import InvenTreeMoneyField, RoundingDecimalFormField from InvenTree.fields import DatePickerFormField from InvenTree.helpers import clean_decimal @@ -321,7 +319,7 @@ class OrderMatchItemForm(MatchItemForm): ) # set price field elif 'price' in col_guess.lower(): - return MoneyField( + return InvenTreeMoneyField( label=_(col_guess), default_currency=InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY'), decimal_places=5, diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index c150331f94..8e5c881ebd 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -22,14 +22,12 @@ from common.settings import currency_code_default from markdownx.models import MarkdownxField from mptt.models import TreeForeignKey -from djmoney.models.fields import MoneyField - from users import models as UserModels from part import models as PartModels from stock import models as stock_models from company.models import Company, SupplierPart -from InvenTree.fields import RoundingDecimalField +from InvenTree.fields import InvenTreeModelMoneyField, RoundingDecimalField from InvenTree.helpers import decimal2string, increment, getSetting from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus, StockStatus, StockHistoryCode from InvenTree.models import InvenTreeAttachment @@ -664,7 +662,7 @@ class PurchaseOrderLineItem(OrderLineItem): received = models.DecimalField(decimal_places=5, max_digits=15, default=0, verbose_name=_('Received'), help_text=_('Number of items received')) - purchase_price = MoneyField( + purchase_price = InvenTreeModelMoneyField( max_digits=19, decimal_places=4, default_currency=currency_code_default(), @@ -716,7 +714,7 @@ class SalesOrderLineItem(OrderLineItem): part = models.ForeignKey('part.Part', on_delete=models.SET_NULL, related_name='sales_order_line_items', null=True, verbose_name=_('Part'), help_text=_('Part'), limit_choices_to={'salable': True}) - sale_price = MoneyField( + sale_price = InvenTreeModelMoneyField( max_digits=19, decimal_places=4, default_currency=currency_code_default(), diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 9786b360d9..cab3ed0d1b 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -26,8 +26,6 @@ from markdownx.models import MarkdownxField from mptt.models import MPTTModel, TreeForeignKey -from djmoney.models.fields import MoneyField - from decimal import Decimal, InvalidOperation from datetime import datetime, timedelta from InvenTree import helpers @@ -38,7 +36,7 @@ import label.models from InvenTree.status_codes import StockStatus, StockHistoryCode from InvenTree.models import InvenTreeTree, InvenTreeAttachment -from InvenTree.fields import InvenTreeURLField +from InvenTree.fields import InvenTreeModelMoneyField, InvenTreeURLField from users.models import Owner @@ -533,7 +531,7 @@ class StockItem(MPTTModel): help_text=_('Stock Item Notes') ) - purchase_price = MoneyField( + purchase_price = InvenTreeModelMoneyField( max_digits=19, decimal_places=4, default_currency=currency_code_default(), From 4b7e8c7d21e3821337f0e53ab16c5e75942fb32f Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 00:14:23 +0200 Subject: [PATCH 199/445] style fixes --- InvenTree/InvenTree/apps.py | 1 - 1 file changed, 1 deletion(-) diff --git a/InvenTree/InvenTree/apps.py b/InvenTree/InvenTree/apps.py index 79269d7b74..feb46ee667 100644 --- a/InvenTree/InvenTree/apps.py +++ b/InvenTree/InvenTree/apps.py @@ -4,7 +4,6 @@ import logging from django.apps import AppConfig from django.core.exceptions import AppRegistryNotReady -from django.conf import settings from InvenTree.ready import isInTestMode, canAppAccessDatabase import InvenTree.tasks From e2278fc26125d0da31c39e9b6fd9eac2973d6155 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 00:33:24 +0200 Subject: [PATCH 200/445] removing lambda --- InvenTree/common/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index cb6329bb39..30940027ec 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -745,7 +745,7 @@ class PriceBreak(models.Model): price = InvenTree.fields.InvenTreeModelMoneyField( max_digits=19, decimal_places=4, - default_currency=lambda: common.settings.currency_code_default(), + default_currency=common.settings.currency_code_default, null=True, verbose_name=_('Price'), help_text=_('Unit price at specified quantity'), From fcdefc4f839265f2eaaa5117beedd66a65246070 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 00:40:26 +0200 Subject: [PATCH 201/445] removing default_currency in fields --- InvenTree/common/models.py | 1 - InvenTree/company/forms.py | 1 - InvenTree/order/forms.py | 1 - InvenTree/order/models.py | 2 -- InvenTree/stock/models.py | 1 - 5 files changed, 6 deletions(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 30940027ec..c8a5839f4e 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -745,7 +745,6 @@ class PriceBreak(models.Model): price = InvenTree.fields.InvenTreeModelMoneyField( max_digits=19, decimal_places=4, - default_currency=common.settings.currency_code_default, null=True, verbose_name=_('Price'), help_text=_('Unit price at specified quantity'), diff --git a/InvenTree/company/forms.py b/InvenTree/company/forms.py index c9497ab89f..564b5fab53 100644 --- a/InvenTree/company/forms.py +++ b/InvenTree/company/forms.py @@ -130,7 +130,6 @@ class EditSupplierPartForm(HelperForm): single_pricing = InvenTreeMoneyField( label=_('Single Price'), - default_currency=currency_code_default(), help_text=_('Single quantity price'), decimal_places=4, max_digits=19, diff --git a/InvenTree/order/forms.py b/InvenTree/order/forms.py index 3dd687c685..aa91e114eb 100644 --- a/InvenTree/order/forms.py +++ b/InvenTree/order/forms.py @@ -321,7 +321,6 @@ class OrderMatchItemForm(MatchItemForm): elif 'price' in col_guess.lower(): return InvenTreeMoneyField( label=_(col_guess), - default_currency=InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY'), decimal_places=5, max_digits=19, required=False, diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index 8e5c881ebd..c3e794c3e3 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -665,7 +665,6 @@ class PurchaseOrderLineItem(OrderLineItem): purchase_price = InvenTreeModelMoneyField( max_digits=19, decimal_places=4, - default_currency=currency_code_default(), null=True, blank=True, verbose_name=_('Purchase Price'), help_text=_('Unit purchase price'), @@ -717,7 +716,6 @@ class SalesOrderLineItem(OrderLineItem): sale_price = InvenTreeModelMoneyField( max_digits=19, decimal_places=4, - default_currency=currency_code_default(), null=True, blank=True, verbose_name=_('Sale Price'), help_text=_('Unit sale price'), diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index cab3ed0d1b..f485771017 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -534,7 +534,6 @@ class StockItem(MPTTModel): purchase_price = InvenTreeModelMoneyField( max_digits=19, decimal_places=4, - default_currency=currency_code_default(), blank=True, null=True, verbose_name=_('Purchase Price'), From dbb9fbd9fde23bdd870096e9143192ac1c566057 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 00:46:53 +0200 Subject: [PATCH 202/445] set default currency in field --- InvenTree/InvenTree/fields.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/InvenTree/InvenTree/fields.py b/InvenTree/InvenTree/fields.py index 25fbf77c90..9010203199 100644 --- a/InvenTree/InvenTree/fields.py +++ b/InvenTree/InvenTree/fields.py @@ -17,6 +17,7 @@ from djmoney.models.fields import MoneyField as ModelMoneyField from djmoney.forms.fields import MoneyField import InvenTree.helpers +from common.settings import currency_code_default class InvenTreeURLFormField(FormURLField): @@ -37,6 +38,10 @@ class InvenTreeURLField(models.URLField): class InvenTreeModelMoneyField(ModelMoneyField): + def __init__(self, **kwargs): + default_currency=currency_code_default + + super().__init__(default_currency=default_currency, **kwargs) pass From 7c6a58e936f51b6c9a7a2b535a35c8fd1618400e Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 00:48:16 +0200 Subject: [PATCH 203/445] handle default in kwargs --- InvenTree/InvenTree/fields.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/InvenTree/InvenTree/fields.py b/InvenTree/InvenTree/fields.py index 9010203199..79724636d3 100644 --- a/InvenTree/InvenTree/fields.py +++ b/InvenTree/InvenTree/fields.py @@ -41,6 +41,11 @@ class InvenTreeModelMoneyField(ModelMoneyField): def __init__(self, **kwargs): default_currency=currency_code_default + # remove from kwargs if set + if 'default_currency' in kwargs: + default_currency = kwargs['default_currency'] + kwargs.pop('default_currency') + super().__init__(default_currency=default_currency, **kwargs) pass From ea8b102897b3c17a98d7cf7e2ca2cc5da38a394d Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 00:50:50 +0200 Subject: [PATCH 204/445] style fix --- InvenTree/InvenTree/fields.py | 2 +- InvenTree/order/forms.py | 1 - InvenTree/order/models.py | 2 -- InvenTree/stock/models.py | 2 -- 4 files changed, 1 insertion(+), 6 deletions(-) diff --git a/InvenTree/InvenTree/fields.py b/InvenTree/InvenTree/fields.py index 79724636d3..aae3ab8049 100644 --- a/InvenTree/InvenTree/fields.py +++ b/InvenTree/InvenTree/fields.py @@ -39,7 +39,7 @@ class InvenTreeURLField(models.URLField): class InvenTreeModelMoneyField(ModelMoneyField): def __init__(self, **kwargs): - default_currency=currency_code_default + default_currency = currency_code_default # remove from kwargs if set if 'default_currency' in kwargs: diff --git a/InvenTree/order/forms.py b/InvenTree/order/forms.py index aa91e114eb..f094caafbe 100644 --- a/InvenTree/order/forms.py +++ b/InvenTree/order/forms.py @@ -16,7 +16,6 @@ from InvenTree.fields import DatePickerFormField from InvenTree.helpers import clean_decimal -from common.models import InvenTreeSetting from common.forms import MatchItemForm import part.models diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index c3e794c3e3..669603f5ec 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -17,8 +17,6 @@ from django.contrib.auth.models import User from django.urls import reverse from django.utils.translation import ugettext_lazy as _ -from common.settings import currency_code_default - from markdownx.models import MarkdownxField from mptt.models import TreeForeignKey diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index f485771017..446dce5c75 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -20,8 +20,6 @@ from django.contrib.auth.models import User from django.db.models.signals import pre_delete from django.dispatch import receiver -from common.settings import currency_code_default - from markdownx.models import MarkdownxField from mptt.models import MPTTModel, TreeForeignKey From 59b794f0e5d9573ca65869b933b3e4ecdeafb632 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 1 Jul 2021 14:25:14 +1000 Subject: [PATCH 205/445] Cleanup old forms --- InvenTree/build/forms.py | 16 +--------------- InvenTree/order/forms.py | 28 ++-------------------------- InvenTree/part/forms.py | 14 +------------- 3 files changed, 4 insertions(+), 54 deletions(-) diff --git a/InvenTree/build/forms.py b/InvenTree/build/forms.py index e60df22c21..e2ca7c3f75 100644 --- a/InvenTree/build/forms.py +++ b/InvenTree/build/forms.py @@ -15,7 +15,7 @@ from InvenTree.fields import DatePickerFormField from InvenTree.status_codes import StockStatus -from .models import Build, BuildItem, BuildOrderAttachment +from .models import Build, BuildItem from stock.models import StockLocation, StockItem @@ -275,17 +275,3 @@ class EditBuildItemForm(HelperForm): 'quantity', 'install_into', ] - - -class EditBuildAttachmentForm(HelperForm): - """ - Form for creating / editing a BuildAttachment object - """ - - class Meta: - model = BuildOrderAttachment - fields = [ - 'build', - 'attachment', - 'comment' - ] diff --git a/InvenTree/order/forms.py b/InvenTree/order/forms.py index 48b5245a5f..39536d457a 100644 --- a/InvenTree/order/forms.py +++ b/InvenTree/order/forms.py @@ -24,8 +24,8 @@ from common.forms import MatchItemForm import part.models from stock.models import StockLocation -from .models import PurchaseOrder, PurchaseOrderLineItem, PurchaseOrderAttachment -from .models import SalesOrder, SalesOrderLineItem, SalesOrderAttachment +from .models import PurchaseOrder, PurchaseOrderLineItem +from .models import SalesOrder, SalesOrderLineItem from .models import SalesOrderAllocation @@ -170,30 +170,6 @@ class EditSalesOrderForm(HelperForm): ] -class EditPurchaseOrderAttachmentForm(HelperForm): - """ Form for editing a PurchaseOrderAttachment object """ - - class Meta: - model = PurchaseOrderAttachment - fields = [ - 'order', - 'attachment', - 'comment' - ] - - -class EditSalesOrderAttachmentForm(HelperForm): - """ Form for editing a SalesOrderAttachment object """ - - class Meta: - model = SalesOrderAttachment - fields = [ - 'order', - 'attachment', - 'comment' - ] - - class EditPurchaseOrderLineItemForm(HelperForm): """ Form for editing a PurchaseOrderLineItem object """ diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index ec799bcf8d..38d9b566aa 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -15,7 +15,7 @@ from django.utils.translation import ugettext_lazy as _ import common.models -from .models import Part, PartCategory, PartAttachment, PartRelated +from .models import Part, PartCategory, PartRelated from .models import BomItem from .models import PartParameterTemplate, PartParameter from .models import PartCategoryParameterTemplate @@ -185,18 +185,6 @@ class CreatePartRelatedForm(HelperForm): } -class EditPartAttachmentForm(HelperForm): - """ Form for editing a PartAttachment object """ - - class Meta: - model = PartAttachment - fields = [ - 'part', - 'attachment', - 'comment' - ] - - class SetPartCategoryForm(forms.Form): """ Form for setting the category of multiple Part objects """ From bb0a72f235da7b74e7ac3c236dc2f9e18b9c5640 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 1 Jul 2021 14:31:37 +1000 Subject: [PATCH 206/445] Refactor forms for StockItemTestResult - Add DETAIL endpoint for model - Remove old views - Remove old forms --- InvenTree/stock/api.py | 10 +++ InvenTree/stock/forms.py | 33 -------- .../stock/templates/stock/item_tests.html | 81 +++++++++++++------ InvenTree/stock/urls.py | 7 -- InvenTree/stock/views.py | 68 ---------------- 5 files changed, 65 insertions(+), 134 deletions(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 534d27a8f4..b946d66aa5 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -940,6 +940,15 @@ class StockAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMix serializer_class = StockItemAttachmentSerializer +class StockItemTestResultDetail(generics.RetrieveUpdateDestroyAPIView): + """ + Detail endpoint for StockItemTestResult + """ + + queryset = StockItemTestResult.objects.all() + serializer_class = StockItemTestResultSerializer + + class StockItemTestResultList(generics.ListCreateAPIView): """ API endpoint for listing (and creating) a StockItemTestResult object. @@ -1156,6 +1165,7 @@ stock_api_urls = [ # Base URL for StockItemTestResult API endpoints url(r'^test/', include([ + url(r'^(?P\d+)/', StockItemTestResultDetail.as_view(), name='api-stock-test-result-detail'), url(r'^$', StockItemTestResultList.as_view(), name='api-stock-test-result-list'), ])), diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py index 92089623f9..ec3eee09d5 100644 --- a/InvenTree/stock/forms.py +++ b/InvenTree/stock/forms.py @@ -23,22 +23,6 @@ from report.models import TestReport from part.models import Part from .models import StockLocation, StockItem, StockItemTracking -from .models import StockItemAttachment -from .models import StockItemTestResult - - -class EditStockItemAttachmentForm(HelperForm): - """ - Form for creating / editing a StockItemAttachment object - """ - - class Meta: - model = StockItemAttachment - fields = [ - 'stock_item', - 'attachment', - 'comment' - ] class AssignStockItemToCustomerForm(HelperForm): @@ -65,23 +49,6 @@ class ReturnStockItemForm(HelperForm): ] -class EditStockItemTestResultForm(HelperForm): - """ - Form for creating / editing a StockItemTestResult object. - """ - - class Meta: - model = StockItemTestResult - fields = [ - 'stock_item', - 'test', - 'result', - 'value', - 'attachment', - 'notes', - ] - - class EditStockLocationForm(HelperForm): """ Form for editing a StockLocation """ diff --git a/InvenTree/stock/templates/stock/item_tests.html b/InvenTree/stock/templates/stock/item_tests.html index 4b3d9dd028..d7d26fcbba 100644 --- a/InvenTree/stock/templates/stock/item_tests.html +++ b/InvenTree/stock/templates/stock/item_tests.html @@ -48,8 +48,7 @@ loadStockTestResultsTable( ); function reloadTable() { - location.reload(); - //$("#test-result-table").bootstrapTable("refresh"); + $("#test-result-table").bootstrapTable("refresh"); } {% if item.has_test_reports %} @@ -70,15 +69,23 @@ $("#delete-test-results").click(function() { {% endif %} $("#add-test-result").click(function() { - launchModalForm( - "{% url 'stock-item-test-create' %}", { - data: { - stock_item: {{ item.id }}, - }, - success: reloadTable, - focus: 'test', - } - ); + + constructForm('{% url "api-stock-test-result-list" %}', { + method: 'POST', + fields: { + test: {}, + result: {}, + value: {}, + attachment: {}, + notes: {}, + stock_item: { + value: {{ item.pk }}, + hidden: true, + } + }, + title: '{% trans "Add Test Result" %}', + onSuccess: reloadTable, + }); }); $("#test-result-table").on('click', '.button-test-add', function() { @@ -86,35 +93,57 @@ $("#test-result-table").on('click', '.button-test-add', function() { var test_name = button.attr('pk'); - launchModalForm( - "{% url 'stock-item-test-create' %}", { - data: { - stock_item: {{ item.id }}, - test: test_name + constructForm('{% url "api-stock-test-result-list" %}', { + method: 'POST', + fields: { + test: { + value: test_name, }, - success: reloadTable, - focus: 'value', - } - ); + result: {}, + value: {}, + attachment: {}, + notes: {}, + stock_item: { + value: {{ item.pk }}, + hidden: true, + } + }, + title: '{% trans "Add Test Result" %}', + onSuccess: reloadTable, + }); }); $("#test-result-table").on('click', '.button-test-edit', function() { var button = $(this); - var url = `/stock/item/test/${button.attr('pk')}/edit/`; + var pk = button.attr('pk'); - launchModalForm(url, { - success: reloadTable, + var url = `/api/stock/test/${pk}/`; + + constructForm(url, { + fields: { + test: {}, + result: {}, + value: {}, + attachment: {}, + notes: {}, + }, + title: '{% trans "Edit Test Result" %}', + onSuccess: reloadTable, }); }); $("#test-result-table").on('click', '.button-test-delete', function() { var button = $(this); - var url = `/stock/item/test/${button.attr('pk')}/delete/`; + var pk = button.attr('pk'); - launchModalForm(url, { - success: reloadTable, + var url = `/api/stock/test/${pk}/`; + + constructForm(url, { + method: 'DELETE', + title: '{% trans "Delete Test Result" %}', + onSuccess: reloadTable, }); }); diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index 3e38d48f0e..ac9474f805 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -62,13 +62,6 @@ stock_urls = [ url(r'^item/uninstall/', views.StockItemUninstall.as_view(), name='stock-item-uninstall'), - # URLs for StockItem tests - url(r'^item/test/', include([ - url(r'^new/', views.StockItemTestResultCreate.as_view(), name='stock-item-test-create'), - url(r'^(?P\d+)/edit/', views.StockItemTestResultEdit.as_view(), name='stock-item-test-edit'), - url(r'^(?P\d+)/delete/', views.StockItemTestResultDelete.as_view(), name='stock-item-test-delete'), - ])), - url(r'^track/', include(stock_tracking_urls)), url(r'^adjust/?', views.StockAdjust.as_view(), name='stock-adjust'), diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index e8a3b8614c..eca7485c40 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -355,74 +355,6 @@ class StockItemDeleteTestData(AjaxUpdateView): return self.renderJsonResponse(request, form, data) -class StockItemTestResultCreate(AjaxCreateView): - """ - View for adding a new StockItemTestResult - """ - - model = StockItemTestResult - form_class = StockForms.EditStockItemTestResultForm - ajax_form_title = _("Add Test Result") - - def save(self, form, **kwargs): - """ - Record the user that uploaded the test result - """ - - result = form.save(commit=False) - result.user = self.request.user - result.save() - - def get_initial(self): - - initials = super().get_initial() - - try: - stock_id = self.request.GET.get('stock_item', None) - initials['stock_item'] = StockItem.objects.get(pk=stock_id) - except (ValueError, StockItem.DoesNotExist): - pass - - initials['test'] = self.request.GET.get('test', '') - - return initials - - def get_form(self): - - form = super().get_form() - form.fields['stock_item'].widget = HiddenInput() - - return form - - -class StockItemTestResultEdit(AjaxUpdateView): - """ - View for editing a StockItemTestResult - """ - - model = StockItemTestResult - form_class = StockForms.EditStockItemTestResultForm - ajax_form_title = _("Edit Test Result") - - def get_form(self): - - form = super().get_form() - - form.fields['stock_item'].widget = HiddenInput() - - return form - - -class StockItemTestResultDelete(AjaxDeleteView): - """ - View for deleting a StockItemTestResult - """ - - model = StockItemTestResult - ajax_form_title = _("Delete Test Result") - context_object_name = "result" - - class StockExportOptions(AjaxView): """ Form for selecting StockExport options """ From 9d1c1b98df4fde92bd84c1afa8ba544672ad7814 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 1 Jul 2021 14:33:16 +1000 Subject: [PATCH 207/445] PEP fix --- InvenTree/stock/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index eca7485c40..280b1bb533 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -32,7 +32,7 @@ from datetime import datetime, timedelta from company.models import Company, SupplierPart from part.models import Part -from .models import StockItem, StockLocation, StockItemTracking, StockItemTestResult +from .models import StockItem, StockLocation, StockItemTracking import common.settings from common.models import InvenTreeSetting From bfc5a7dcf89d03173968a345604c7206354b9c8d Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 1 Jul 2021 14:44:23 +1000 Subject: [PATCH 208/445] Refactor forms for PartTestTemplate model: - Remove old forms - Remove old views - Add detail endpoint for the API --- InvenTree/part/api.py | 10 ++++ InvenTree/part/forms.py | 26 ++-------- InvenTree/part/templates/part/part_tests.html | 52 +++++++++++++------ InvenTree/part/urls.py | 7 --- InvenTree/part/views.py | 50 ------------------ 5 files changed, 50 insertions(+), 95 deletions(-) diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index d9fa77afd4..b31283e191 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -241,6 +241,15 @@ class PartAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixi serializer_class = part_serializers.PartAttachmentSerializer +class PartTestTemplateDetail(generics.RetrieveUpdateDestroyAPIView): + """ + Detail endpoint for PartTestTemplate model + """ + + queryset = PartTestTemplate.objects.all() + serializer_class = part_serializers.PartTestTemplateSerializer + + class PartTestTemplateList(generics.ListCreateAPIView): """ API endpoint for listing (and creating) a PartTestTemplate. @@ -1036,6 +1045,7 @@ part_api_urls = [ # Base URL for PartTestTemplate API endpoints url(r'^test-template/', include([ + url(r'^(?P\d+)/', PartTestTemplateDetail.as_view(), name='api-part-test-template-detail'), url(r'^$', PartTestTemplateList.as_view(), name='api-part-test-template-list'), ])), diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index 38d9b566aa..36a49006b0 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -5,21 +5,21 @@ Django Forms for interacting with Part objects # -*- coding: utf-8 -*- from __future__ import unicode_literals +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from mptt.fields import TreeNodeChoiceField + from InvenTree.forms import HelperForm from InvenTree.helpers import GetExportFormats from InvenTree.fields import RoundingDecimalFormField -from mptt.fields import TreeNodeChoiceField -from django import forms -from django.utils.translation import ugettext_lazy as _ - import common.models from .models import Part, PartCategory, PartRelated from .models import BomItem from .models import PartParameterTemplate, PartParameter from .models import PartCategoryParameterTemplate -from .models import PartTestTemplate from .models import PartSellPriceBreak, PartInternalPriceBreak @@ -65,22 +65,6 @@ class PartImageForm(HelperForm): ] -class EditPartTestTemplateForm(HelperForm): - """ Class for creating / editing a PartTestTemplate object """ - - class Meta: - model = PartTestTemplate - - fields = [ - 'part', - 'test_name', - 'description', - 'required', - 'requires_value', - 'requires_attachment', - ] - - class BomExportForm(forms.Form): """ Simple form to let user set BOM export options, before exporting a BOM (bill of materials) file. diff --git a/InvenTree/part/templates/part/part_tests.html b/InvenTree/part/templates/part/part_tests.html index dbd439afdb..3c131aa1d4 100644 --- a/InvenTree/part/templates/part/part_tests.html +++ b/InvenTree/part/templates/part/part_tests.html @@ -44,34 +44,52 @@ function reloadTable() { } $("#add-test-template").click(function() { - launchModalForm( - "{% url 'part-test-template-create' %}", - { - data: { - part: {{ part.id }}, - }, - success: reloadTable, - } - ); + + constructForm('{% url "api-part-test-template-list" %}', { + method: 'POST', + fields: { + test_name: {}, + description: {}, + required: {}, + requires_value: {}, + requires_attachment: {}, + part: { + value: {{ part.pk }}, + hidden: true, + } + }, + title: '{% trans "Add Test Result Template" %}', + onSuccess: reloadTable + }); }); $("#test-template-table").on('click', '.button-test-edit', function() { - var button = $(this); + var pk = $(this).attr('pk'); - var url = `/part/test-template/${button.attr('pk')}/edit/`; + var url = `/api/part/test-template/${pk}/`; - launchModalForm(url, { - success: reloadTable, + constructForm(url, { + fields: { + test_name: {}, + description: {}, + required: {}, + requires_value: {}, + requires_attachment: {}, + }, + title: '{% trans "Edit Test Result Template" %}', + onSuccess: reloadTable, }); }); $("#test-template-table").on('click', '.button-test-delete', function() { - var button = $(this); + var pk = $(this).attr('pk'); - var url = `/part/test-template/${button.attr('pk')}/delete/`; + var url = `/api/part/test-template/${pk}/`; - launchModalForm(url, { - success: reloadTable, + constructForm(url, { + method: 'DELETE', + title: '{% trans "Delete Test Result Template" %}', + onSuccess: reloadTable, }); }); diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 489df6c116..44336ab6a7 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -148,13 +148,6 @@ part_urls = [ # Part internal price breaks url(r'^internal-price/', include(internal_price_break_urls)), - # Part test templates - url(r'^test-template/', include([ - url(r'^new/', views.PartTestTemplateCreate.as_view(), name='part-test-template-create'), - url(r'^(?P\d+)/edit/', views.PartTestTemplateEdit.as_view(), name='part-test-template-edit'), - url(r'^(?P\d+)/delete/', views.PartTestTemplateDelete.as_view(), name='part-test-template-delete'), - ])), - # Part parameters url(r'^parameter/', include(part_parameter_urls)), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 0f0ccd8ba0..78fd0d7a27 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -36,7 +36,6 @@ from .models import PartParameterTemplate, PartParameter from .models import PartCategoryParameterTemplate from .models import BomItem from .models import match_part_names -from .models import PartTestTemplate from .models import PartSellPriceBreak, PartInternalPriceBreak from common.models import InvenTreeSetting @@ -154,55 +153,6 @@ class PartRelatedDelete(AjaxDeleteView): role_required = 'part.change' -class PartTestTemplateCreate(AjaxCreateView): - """ View for creating a PartTestTemplate """ - - model = PartTestTemplate - form_class = part_forms.EditPartTestTemplateForm - ajax_form_title = _("Create Test Template") - - def get_initial(self): - - initials = super().get_initial() - - try: - part_id = self.request.GET.get('part', None) - initials['part'] = Part.objects.get(pk=part_id) - except (ValueError, Part.DoesNotExist): - pass - - return initials - - def get_form(self): - - form = super().get_form() - form.fields['part'].widget = HiddenInput() - - return form - - -class PartTestTemplateEdit(AjaxUpdateView): - """ View for editing a PartTestTemplate """ - - model = PartTestTemplate - form_class = part_forms.EditPartTestTemplateForm - ajax_form_title = _("Edit Test Template") - - def get_form(self): - - form = super().get_form() - form.fields['part'].widget = HiddenInput() - - return form - - -class PartTestTemplateDelete(AjaxDeleteView): - """ View for deleting a PartTestTemplate """ - - model = PartTestTemplate - ajax_form_title = _("Delete Test Template") - - class PartSetCategory(AjaxUpdateView): """ View for settings the part category for multiple parts at once """ From 4d86f33e2357499a059f126316e85c8af881f60e Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 07:07:02 +0200 Subject: [PATCH 209/445] clean Money migrations! --- InvenTree/InvenTree/fields.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/InvenTree/InvenTree/fields.py b/InvenTree/InvenTree/fields.py index aae3ab8049..9d7f7f4464 100644 --- a/InvenTree/InvenTree/fields.py +++ b/InvenTree/InvenTree/fields.py @@ -11,13 +11,14 @@ from django.forms.fields import URLField as FormURLField from django.db import models as models from django.core import validators from django import forms +from django.conf import settings from decimal import Decimal from djmoney.models.fields import MoneyField as ModelMoneyField from djmoney.forms.fields import MoneyField import InvenTree.helpers -from common.settings import currency_code_default +import common.settings class InvenTreeURLFormField(FormURLField): @@ -38,20 +39,27 @@ class InvenTreeURLField(models.URLField): class InvenTreeModelMoneyField(ModelMoneyField): + """ custom MoneyField for clean migrations while havoing dynamic currency settings """ def __init__(self, **kwargs): - default_currency = currency_code_default + # remove currency information for a clean migration + kwargs['default_currency'] = '' + kwargs['currency_choices'] = [] - # remove from kwargs if set - if 'default_currency' in kwargs: - default_currency = kwargs['default_currency'] - kwargs.pop('default_currency') + super().__init__(**kwargs) - super().__init__(default_currency=default_currency, **kwargs) - pass + def formfield(self, **kwargs): + """ override form class to use own function """ + kwargs['form_class'] = InvenTreeMoneyField + return super().formfield(**kwargs) class InvenTreeMoneyField(MoneyField): - pass + """ custom MoneyField for clean migrations while havoing dynamic currency settings """ + def __init__(self, *args, **kwargs): + # override initial values with the real info from database + kwargs['currency_choices'] = [(a, a) for a in settings.CURRENCIES] + kwargs['default_currency'] = common.settings.currency_code_default + super().__init__(*args, **kwargs) class DatePickerFormField(forms.DateField): From 9b7a08f50f05fcb82ae9b07604a20da4d4135224 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 07:07:40 +0200 Subject: [PATCH 210/445] fixed doc --- InvenTree/InvenTree/fields.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/InvenTree/fields.py b/InvenTree/InvenTree/fields.py index 9d7f7f4464..c461c0e752 100644 --- a/InvenTree/InvenTree/fields.py +++ b/InvenTree/InvenTree/fields.py @@ -39,7 +39,7 @@ class InvenTreeURLField(models.URLField): class InvenTreeModelMoneyField(ModelMoneyField): - """ custom MoneyField for clean migrations while havoing dynamic currency settings """ + """ custom MoneyField for clean migrations while using dynamic currency settings """ def __init__(self, **kwargs): # remove currency information for a clean migration kwargs['default_currency'] = '' @@ -54,7 +54,7 @@ class InvenTreeModelMoneyField(ModelMoneyField): class InvenTreeMoneyField(MoneyField): - """ custom MoneyField for clean migrations while havoing dynamic currency settings """ + """ custom MoneyField for clean migrations while using dynamic currency settings """ def __init__(self, *args, **kwargs): # override initial values with the real info from database kwargs['currency_choices'] = [(a, a) for a in settings.CURRENCIES] From 3c6c9c59d6a53226c47bad58feb3f6f401f28281 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 07:11:15 +0200 Subject: [PATCH 211/445] added clean migration steps for all price fields --- .../migrations/0039_auto_20210701_0509.py | 25 +++++++++++++ .../migrations/0047_auto_20210701_0509.py | 35 +++++++++++++++++++ .../migrations/0069_auto_20210701_0509.py | 35 +++++++++++++++++++ .../migrations/0065_auto_20210701_0509.py | 25 +++++++++++++ 4 files changed, 120 insertions(+) create mode 100644 InvenTree/company/migrations/0039_auto_20210701_0509.py create mode 100644 InvenTree/order/migrations/0047_auto_20210701_0509.py create mode 100644 InvenTree/part/migrations/0069_auto_20210701_0509.py create mode 100644 InvenTree/stock/migrations/0065_auto_20210701_0509.py diff --git a/InvenTree/company/migrations/0039_auto_20210701_0509.py b/InvenTree/company/migrations/0039_auto_20210701_0509.py new file mode 100644 index 0000000000..094c7a5009 --- /dev/null +++ b/InvenTree/company/migrations/0039_auto_20210701_0509.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.4 on 2021-07-01 05:09 + +import InvenTree.fields +from django.db import migrations +import djmoney.models.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('company', '0038_manufacturerpartparameter'), + ] + + operations = [ + migrations.AlterField( + model_name='supplierpricebreak', + name='price', + field=InvenTree.fields.InvenTreeModelMoneyField(currency_choices=[], decimal_places=4, default_currency='', help_text='Unit price at specified quantity', max_digits=19, null=True, verbose_name='Price'), + ), + migrations.AlterField( + model_name='supplierpricebreak', + name='price_currency', + field=djmoney.models.fields.CurrencyField(choices=[], default='', editable=False, max_length=3), + ), + ] diff --git a/InvenTree/order/migrations/0047_auto_20210701_0509.py b/InvenTree/order/migrations/0047_auto_20210701_0509.py new file mode 100644 index 0000000000..1f732e5f61 --- /dev/null +++ b/InvenTree/order/migrations/0047_auto_20210701_0509.py @@ -0,0 +1,35 @@ +# Generated by Django 3.2.4 on 2021-07-01 05:09 + +import InvenTree.fields +from django.db import migrations +import djmoney.models.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0046_purchaseorderlineitem_destination'), + ] + + operations = [ + migrations.AlterField( + model_name='purchaseorderlineitem', + name='purchase_price', + field=InvenTree.fields.InvenTreeModelMoneyField(blank=True, currency_choices=[], decimal_places=4, default_currency='', help_text='Unit purchase price', max_digits=19, null=True, verbose_name='Purchase Price'), + ), + migrations.AlterField( + model_name='purchaseorderlineitem', + name='purchase_price_currency', + field=djmoney.models.fields.CurrencyField(choices=[], default='', editable=False, max_length=3), + ), + migrations.AlterField( + model_name='salesorderlineitem', + name='sale_price', + field=InvenTree.fields.InvenTreeModelMoneyField(blank=True, currency_choices=[], decimal_places=4, default_currency='', help_text='Unit sale price', max_digits=19, null=True, verbose_name='Sale Price'), + ), + migrations.AlterField( + model_name='salesorderlineitem', + name='sale_price_currency', + field=djmoney.models.fields.CurrencyField(choices=[], default='', editable=False, max_length=3), + ), + ] diff --git a/InvenTree/part/migrations/0069_auto_20210701_0509.py b/InvenTree/part/migrations/0069_auto_20210701_0509.py new file mode 100644 index 0000000000..86d8d2d44c --- /dev/null +++ b/InvenTree/part/migrations/0069_auto_20210701_0509.py @@ -0,0 +1,35 @@ +# Generated by Django 3.2.4 on 2021-07-01 05:09 + +import InvenTree.fields +from django.db import migrations +import djmoney.models.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0068_part_unique_part'), + ] + + operations = [ + migrations.AlterField( + model_name='partinternalpricebreak', + name='price', + field=InvenTree.fields.InvenTreeModelMoneyField(currency_choices=[], decimal_places=4, default_currency='', help_text='Unit price at specified quantity', max_digits=19, null=True, verbose_name='Price'), + ), + migrations.AlterField( + model_name='partinternalpricebreak', + name='price_currency', + field=djmoney.models.fields.CurrencyField(choices=[], default='', editable=False, max_length=3), + ), + migrations.AlterField( + model_name='partsellpricebreak', + name='price', + field=InvenTree.fields.InvenTreeModelMoneyField(currency_choices=[], decimal_places=4, default_currency='', help_text='Unit price at specified quantity', max_digits=19, null=True, verbose_name='Price'), + ), + migrations.AlterField( + model_name='partsellpricebreak', + name='price_currency', + field=djmoney.models.fields.CurrencyField(choices=[], default='', editable=False, max_length=3), + ), + ] diff --git a/InvenTree/stock/migrations/0065_auto_20210701_0509.py b/InvenTree/stock/migrations/0065_auto_20210701_0509.py new file mode 100644 index 0000000000..99cde1e7f7 --- /dev/null +++ b/InvenTree/stock/migrations/0065_auto_20210701_0509.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.4 on 2021-07-01 05:09 + +import InvenTree.fields +from django.db import migrations +import djmoney.models.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('stock', '0064_auto_20210621_1724'), + ] + + operations = [ + migrations.AlterField( + model_name='stockitem', + name='purchase_price', + field=InvenTree.fields.InvenTreeModelMoneyField(blank=True, currency_choices=[], decimal_places=4, default_currency='', help_text='Single unit purchase price at time of purchase', max_digits=19, null=True, verbose_name='Purchase Price'), + ), + migrations.AlterField( + model_name='stockitem', + name='purchase_price_currency', + field=djmoney.models.fields.CurrencyField(choices=[], default='', editable=False, max_length=3), + ), + ] From 870542e4c103ba4deb674d326a461a63680a4b5d Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 1 Jul 2021 16:05:23 +1000 Subject: [PATCH 212/445] Refactor forms for ManufacturerPartParameter --- InvenTree/company/forms.py | 17 +---- .../company/manufacturer_part_suppliers.html | 25 +++++--- InvenTree/company/views.py | 63 +------------------ InvenTree/templates/js/company.js | 31 ++++----- 4 files changed, 36 insertions(+), 100 deletions(-) diff --git a/InvenTree/company/forms.py b/InvenTree/company/forms.py index 3b54f3dc61..63c07ff7a4 100644 --- a/InvenTree/company/forms.py +++ b/InvenTree/company/forms.py @@ -15,7 +15,7 @@ from djmoney.forms.fields import MoneyField from common.settings import currency_code_default -from .models import Company, ManufacturerPartParameter +from .models import Company from .models import ManufacturerPart from .models import SupplierPart from .models import SupplierPriceBreak @@ -58,21 +58,6 @@ class EditManufacturerPartForm(HelperForm): ] -class EditManufacturerPartParameterForm(HelperForm): - """ - Form for creating / editing a ManufacturerPartParameter object - """ - - class Meta: - model = ManufacturerPartParameter - fields = [ - 'manufacturer_part', - 'name', - 'value', - 'units', - ] - - class EditSupplierPartForm(HelperForm): """ Form for editing a SupplierPart object """ diff --git a/InvenTree/company/templates/company/manufacturer_part_suppliers.html b/InvenTree/company/templates/company/manufacturer_part_suppliers.html index 59969d9708..f3b87f4658 100644 --- a/InvenTree/company/templates/company/manufacturer_part_suppliers.html +++ b/InvenTree/company/templates/company/manufacturer_part_suppliers.html @@ -57,15 +57,26 @@ {% block js_ready %} {{ block.super }} +function reloadParameters() { + $("#parameter-table").bootstrapTable("refresh"); +} + $('#parameter-create').click(function() { - launchModalForm( - "{% url 'manufacturer-part-parameter-create' %}", - { - data: { - manufacturer_part: {{ part.id }}, + + constructForm('{% url "api-manufacturer-part-parameter-list" %}', { + method: 'POST', + fields: { + name: {}, + value: {}, + units: {}, + manufacturer_part: { + value: {{ part.pk }}, + hidden: true, } - } - ); + }, + title: '{% trans "Add Parameter" %}', + onSuccess: reloadParameters + }); }); $('#supplier-create').click(function () { diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index 01b602d20a..c0fdcb912b 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -23,13 +23,12 @@ from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView from InvenTree.helpers import str2bool from InvenTree.views import InvenTreeRoleMixin -from .models import Company, ManufacturerPartParameter +from .models import Company from .models import ManufacturerPart from .models import SupplierPart from part.models import Part -from .forms import EditManufacturerPartParameterForm from .forms import EditManufacturerPartForm from .forms import EditSupplierPartForm from .forms import CompanyImageDownloadForm @@ -414,66 +413,6 @@ class ManufacturerPartDelete(AjaxDeleteView): part.delete() return self.renderJsonResponse(self.request, data=data, form=self.get_form()) - - -class ManufacturerPartParameterCreate(AjaxCreateView): - """ - View for creating a new ManufacturerPartParameter object - """ - - model = ManufacturerPartParameter - form_class = EditManufacturerPartParameterForm - ajax_form_title = _('Add Manufacturer Part Parameter') - - def get_form(self): - - form = super().get_form() - - # Hide the manufacturer_part field if specified - if form.initial.get('manufacturer_part', None): - form.fields['manufacturer_part'].widget = HiddenInput() - - return form - - def get_initial(self): - - initials = super().get_initial().copy() - - manufacturer_part = self.get_param('manufacturer_part') - - if manufacturer_part: - try: - initials['manufacturer_part'] = ManufacturerPartParameter.objects.get(pk=manufacturer_part) - except (ValueError, ManufacturerPartParameter.DoesNotExist): - pass - - return initials - - -class ManufacturerPartParameterEdit(AjaxUpdateView): - """ - View for editing a ManufacturerPartParameter object - """ - - model = ManufacturerPartParameter - form_class = EditManufacturerPartParameterForm - ajax_form_title = _('Edit Manufacturer Part Parameter') - - def get_form(self): - - form = super().get_form() - - form.fields['manufacturer_part'].widget = HiddenInput() - - return form - - -class ManufacturerPartParameterDelete(AjaxDeleteView): - """ - View for deleting a ManufacturerPartParameter object - """ - - model = ManufacturerPartParameter class SupplierPartDetail(DetailView): diff --git a/InvenTree/templates/js/company.js b/InvenTree/templates/js/company.js index 96beb0a041..dc0f0f4cc6 100644 --- a/InvenTree/templates/js/company.js +++ b/InvenTree/templates/js/company.js @@ -342,27 +342,28 @@ function loadManufacturerPartParameterTable(table, url, options) { $(table).find('.button-parameter-edit').click(function() { var pk = $(this).attr('pk'); - launchModalForm( - `/manufacturer-part/parameter/${pk}/edit/`, - { - success: function() { - $(table).bootstrapTable('refresh'); - } + constructForm(`/api/company/part/manufacturer/parameter/${pk}/`, { + fields: { + name: {}, + value: {}, + units: {}, + }, + title: '{% trans "Edit Parameter" %}', + onSuccess: function() { + $(table).bootstrapTable('refresh'); } - ); - + }); }); $(table).find('.button-parameter-delete').click(function() { var pk = $(this).attr('pk'); - launchModalForm( - `/manufacturer-part/parameter/${pk}/delete/`, - { - success: function() { - $(table).bootstrapTable('refresh'); - } + constructForm(`/api/company/part/manufacturer/parameter/${pk}/`, { + method: 'DELETE', + title: '{% trans "Delete Parameter" %}', + onSuccess: function() { + $(table).bootstrapTable('refresh'); } - ); + }); }); } }); From 96a2629fd23bfb1e8e3597f0cd380f7ce17c4502 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 1 Jul 2021 16:07:42 +1000 Subject: [PATCH 213/445] Remove old URL endpoints --- InvenTree/company/urls.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index 47a57d1df0..59d82e380f 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -44,15 +44,6 @@ manufacturer_part_urls = [ url(r'^delete/', views.ManufacturerPartDelete.as_view(), name='manufacturer-part-delete'), - # URLs for ManufacturerPartParameter views (create / edit / delete) - url(r'^parameter/', include([ - url(r'^new/', views.ManufacturerPartParameterCreate.as_view(), name='manufacturer-part-parameter-create'), - url(r'^(?P\d)/', include([ - url(r'^edit/', views.ManufacturerPartParameterEdit.as_view(), name='manufacturer-part-parameter-edit'), - url(r'^delete/', views.ManufacturerPartParameterDelete.as_view(), name='manufacturer-part-parameter-delete'), - ])), - ])), - url(r'^(?P\d+)/', include([ url(r'^edit/?', views.ManufacturerPartEdit.as_view(), name='manufacturer-part-edit'), url(r'^suppliers/', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part_suppliers.html'), name='manufacturer-part-suppliers'), From 206d7bd96a1126a2054c9b89ac21faa98a53041a Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 1 Jul 2021 16:28:46 +1000 Subject: [PATCH 214/445] Refactor edit and delete forms for ManufacturerPart --- .../company/manufacturer_part_base.html | 30 ++++--- .../company/manufacturer_part_delete.html | 46 ---------- InvenTree/company/urls.py | 3 - InvenTree/company/views.py | 89 ------------------- 4 files changed, 18 insertions(+), 150 deletions(-) delete mode 100644 InvenTree/company/templates/company/manufacturer_part_delete.html diff --git a/InvenTree/company/templates/company/manufacturer_part_base.html b/InvenTree/company/templates/company/manufacturer_part_base.html index c3a64d9d76..addd9265b8 100644 --- a/InvenTree/company/templates/company/manufacturer_part_base.html +++ b/InvenTree/company/templates/company/manufacturer_part_base.html @@ -113,21 +113,27 @@ $('#order-part, #order-part2').click(function() { }); $('#edit-part').click(function () { - launchModalForm( - "{% url 'manufacturer-part-edit' part.id %}", - { - reload: true - } - ); + + constructForm('{% url "api-manufacturer-part-detail" part.pk %}', { + fields: { + part: {}, + manufacturer: {}, + MPN: {}, + description: {}, + link: {}, + }, + title: '{% trans "Edit Manufacturer Part" %}', + reload: true, + }); }); $('#delete-part').click(function() { - launchModalForm( - "{% url 'manufacturer-part-delete' %}?part={{ part.id }}", - { - redirect: "{% url 'company-detail-manufacturer-parts' part.manufacturer.id %}" - } - ); + + constructForm('{% url "api-manufacturer-part-detail" part.pk %}', { + method: 'DELETE', + title: '{% trans "Delete Manufacturer Part" %}', + redirect: "{% url 'company-detail-manufacturer-parts' part.manufacturer.id %}", + }); }); {% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/manufacturer_part_delete.html b/InvenTree/company/templates/company/manufacturer_part_delete.html deleted file mode 100644 index 6c96c978d4..0000000000 --- a/InvenTree/company/templates/company/manufacturer_part_delete.html +++ /dev/null @@ -1,46 +0,0 @@ -{% extends "modal_delete_form.html" %} -{% load i18n %} - -{% block pre_form_content %} -
          - {% trans "Are you sure you want to delete the following Manufacturer Parts?" %} -
          -{% for part in parts %} - -{% endfor %} - -{% endblock %} - -{% block form_data %} - -{% for part in parts %} -
          - - - - - - - -
          - {% include "hover_image.html" with image=part.part.image %} - {{ part.part.full_name }} - - {% include "hover_image.html" with image=part.manufacturer.image %} - {{ part.manufacturer.name }} - - {{ part.MPN }} -
          -{% if part.supplier_parts.all|length > 0 %} -
          -

          {% blocktrans with count=part.supplier_parts.all|length %}There are {{count}} suppliers defined for this manufacturer part. If you delete it, the following supplier parts will also be deleted:{% endblocktrans %}

          -
            - {% for spart in part.supplier_parts.all %} -
          • {{ spart.supplier.name }} - {{ spart.SKU }}
          • - {% endfor %} -
          -
          -{% endif %} -{% endfor %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index 59d82e380f..105d7e89a2 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -42,10 +42,7 @@ company_urls = [ manufacturer_part_urls = [ url(r'^new/?', views.ManufacturerPartCreate.as_view(), name='manufacturer-part-create'), - url(r'^delete/', views.ManufacturerPartDelete.as_view(), name='manufacturer-part-delete'), - url(r'^(?P\d+)/', include([ - url(r'^edit/?', views.ManufacturerPartEdit.as_view(), name='manufacturer-part-edit'), url(r'^suppliers/', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part_suppliers.html'), name='manufacturer-part-suppliers'), url('^.*$', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part_suppliers.html'), name='manufacturer-part-detail'), ])), diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index c0fdcb912b..9c28f56fa8 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -258,16 +258,6 @@ class ManufacturerPartDetail(DetailView): return ctx -class ManufacturerPartEdit(AjaxUpdateView): - """ Update view for editing ManufacturerPart """ - - model = ManufacturerPart - context_object_name = 'part' - form_class = EditManufacturerPartForm - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Edit Manufacturer Part') - - class ManufacturerPartCreate(AjaxCreateView): """ Create view for making new ManufacturerPart """ @@ -336,85 +326,6 @@ class ManufacturerPartCreate(AjaxCreateView): return initials -class ManufacturerPartDelete(AjaxDeleteView): - """ Delete view for removing a ManufacturerPart. - - ManufacturerParts can be deleted using a variety of 'selectors'. - - - ?part= -> Delete a single ManufacturerPart object - - ?parts=[] -> Delete a list of ManufacturerPart objects - - """ - - success_url = '/manufacturer/' - ajax_template_name = 'company/manufacturer_part_delete.html' - ajax_form_title = _('Delete Manufacturer Part') - - role_required = 'purchase_order.delete' - - parts = [] - - def get_context_data(self): - ctx = {} - - ctx['parts'] = self.parts - - return ctx - - def get_parts(self): - """ Determine which ManufacturerPart object(s) the user wishes to delete. - """ - - self.parts = [] - - # User passes a single ManufacturerPart ID - if 'part' in self.request.GET: - try: - self.parts.append(ManufacturerPart.objects.get(pk=self.request.GET.get('part'))) - except (ValueError, ManufacturerPart.DoesNotExist): - pass - - elif 'parts[]' in self.request.GET: - - part_id_list = self.request.GET.getlist('parts[]') - - self.parts = ManufacturerPart.objects.filter(id__in=part_id_list) - - def get(self, request, *args, **kwargs): - self.request = request - self.get_parts() - - return self.renderJsonResponse(request, form=self.get_form()) - - def post(self, request, *args, **kwargs): - """ Handle the POST action for deleting ManufacturerPart object. - """ - - self.request = request - self.parts = [] - - for item in self.request.POST: - if item.startswith('manufacturer-part-'): - pk = item.replace('manufacturer-part-', '') - - try: - self.parts.append(ManufacturerPart.objects.get(pk=pk)) - except (ValueError, ManufacturerPart.DoesNotExist): - pass - - confirm = str2bool(self.request.POST.get('confirm_delete', False)) - - data = { - 'form_valid': confirm, - } - - if confirm: - for part in self.parts: - part.delete() - - return self.renderJsonResponse(self.request, data=data, form=self.get_form()) - - class SupplierPartDetail(DetailView): """ Detail view for SupplierPart """ model = SupplierPart From 9bd71c1184b7e58bceaef2f783de93b528762fd1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 1 Jul 2021 17:01:30 +1000 Subject: [PATCH 215/445] Refactor deletion of multiple manufacturer part objects - issues multiple DELETE requests via the API --- .../company/detail_manufacturer_part.html | 25 ++++----- InvenTree/company/test_views.py | 32 +---------- InvenTree/part/templates/part/bom.html | 4 +- .../part/templates/part/manufacturer.html | 17 ++---- InvenTree/templates/js/company.js | 55 +++++++++++++++++++ InvenTree/templates/js/stock.js | 2 +- 6 files changed, 74 insertions(+), 61 deletions(-) diff --git a/InvenTree/company/templates/company/detail_manufacturer_part.html b/InvenTree/company/templates/company/detail_manufacturer_part.html index a162334040..992753e97b 100644 --- a/InvenTree/company/templates/company/detail_manufacturer_part.html +++ b/InvenTree/company/templates/company/detail_manufacturer_part.html @@ -25,7 +25,7 @@ {% endif %}
          + - - - \ No newline at end of file From 52eedef82009c3d267fc3b4b33ec33a3542ec894 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jul 2021 21:03:28 +1000 Subject: [PATCH 371/445] remove old StockAdjust view --- InvenTree/stock/urls.py | 2 - InvenTree/stock/views.py | 337 --------------------------------------- 2 files changed, 339 deletions(-) diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index ac9474f805..67101c1f3b 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -64,8 +64,6 @@ stock_urls = [ url(r'^track/', include(stock_tracking_urls)), - url(r'^adjust/?', views.StockAdjust.as_view(), name='stock-adjust'), - url(r'^export-options/?', views.StockExportOptions.as_view(), name='stock-export-options'), url(r'^export/?', views.StockExport.as_view(), name='stock-export'), diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index c74b0bb2fc..6713909a2a 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -749,343 +749,6 @@ class StockItemUninstall(AjaxView, FormMixin): return context -class StockAdjust(AjaxView, FormMixin): - """ View for enacting simple stock adjustments: - - - Take items from stock - - Add items to stock - - Count items - - Move stock - - Delete stock items - - """ - - ajax_template_name = 'stock/stock_adjust.html' - ajax_form_title = _('Adjust Stock') - form_class = StockForms.AdjustStockForm - stock_items = [] - role_required = 'stock.change' - - def get_GET_items(self): - """ Return list of stock items initally requested using GET. - - Items can be retrieved by: - - a) List of stock ID - stock[]=1,2,3,4,5 - b) Parent part - part=3 - c) Parent location - location=78 - d) Single item - item=2 - """ - - # Start with all 'in stock' items - items = StockItem.objects.filter(StockItem.IN_STOCK_FILTER) - - # Client provides a list of individual stock items - if 'stock[]' in self.request.GET: - items = items.filter(id__in=self.request.GET.getlist('stock[]')) - - # Client provides a PART reference - elif 'part' in self.request.GET: - items = items.filter(part=self.request.GET.get('part')) - - # Client provides a LOCATION reference - elif 'location' in self.request.GET: - items = items.filter(location=self.request.GET.get('location')) - - # Client provides a single StockItem lookup - elif 'item' in self.request.GET: - items = [StockItem.objects.get(id=self.request.GET.get('item'))] - - # Unsupported query (no items) - else: - items = [] - - for item in items: - - # Initialize quantity to zero for addition/removal - if self.stock_action in ['take', 'add']: - item.new_quantity = 0 - # Initialize quantity at full amount for counting or moving - else: - item.new_quantity = item.quantity - - return items - - def get_POST_items(self): - """ Return list of stock items sent back by client on a POST request """ - - items = [] - - for item in self.request.POST: - if item.startswith('stock-id-'): - - pk = item.replace('stock-id-', '') - q = self.request.POST[item] - - try: - stock_item = StockItem.objects.get(pk=pk) - except StockItem.DoesNotExist: - continue - - stock_item.new_quantity = q - - items.append(stock_item) - - return items - - def get_stock_action_titles(self): - - # Choose form title and action column based on the action - titles = { - 'move': [_('Move Stock Items'), _('Move')], - 'count': [_('Count Stock Items'), _('Count')], - 'take': [_('Remove From Stock'), _('Take')], - 'add': [_('Add Stock Items'), _('Add')], - 'delete': [_('Delete Stock Items'), _('Delete')], - } - - self.ajax_form_title = titles[self.stock_action][0] - self.stock_action_title = titles[self.stock_action][1] - - def get_context_data(self): - - context = super().get_context_data() - - context['stock_items'] = self.stock_items - - context['stock_action'] = self.stock_action.strip().lower() - - self.get_stock_action_titles() - context['stock_action_title'] = self.stock_action_title - - # Quantity column will be read-only in some circumstances - context['edit_quantity'] = not self.stock_action == 'delete' - - return context - - def get_form(self): - - form = super().get_form() - - if not self.stock_action == 'move': - form.fields.pop('destination') - form.fields.pop('set_loc') - - return form - - def get(self, request, *args, **kwargs): - - self.request = request - - # Action - self.stock_action = request.GET.get('action', '').lower() - - # Pick a default action... - if self.stock_action not in ['move', 'count', 'take', 'add', 'delete']: - self.stock_action = 'count' - - # Save list of items! - self.stock_items = self.get_GET_items() - - return self.renderJsonResponse(request, self.get_form()) - - def post(self, request, *args, **kwargs): - - self.request = request - - self.stock_action = request.POST.get('stock_action', 'invalid').strip().lower() - - # Update list of stock items - self.stock_items = self.get_POST_items() - - form = self.get_form() - - valid = form.is_valid() - - for item in self.stock_items: - - try: - item.new_quantity = Decimal(item.new_quantity) - except ValueError: - item.error = _('Must enter integer value') - valid = False - continue - - if item.new_quantity < 0: - item.error = _('Quantity must be positive') - valid = False - continue - - if self.stock_action in ['move', 'take']: - - if item.new_quantity > item.quantity: - item.error = _('Quantity must not exceed {x}').format(x=item.quantity) - valid = False - continue - - confirmed = str2bool(request.POST.get('confirm')) - - if not confirmed: - valid = False - form.add_error('confirm', _('Confirm stock adjustment')) - - data = { - 'form_valid': valid, - } - - if valid: - result = self.do_action(note=form.cleaned_data['note']) - - data['success'] = result - - # Special case - Single Stock Item - # If we deplete the stock item, we MUST redirect to a new view - single_item = len(self.stock_items) == 1 - - if result and single_item: - - # Was the entire stock taken? - item = self.stock_items[0] - - if item.quantity == 0: - # Instruct the form to redirect - data['url'] = reverse('stock-index') - - return self.renderJsonResponse(request, form, data=data, context=self.get_context_data()) - - def do_action(self, note=None): - """ Perform stock adjustment action """ - - if self.stock_action == 'move': - destination = None - - set_default_loc = str2bool(self.request.POST.get('set_loc', False)) - - try: - destination = StockLocation.objects.get(id=self.request.POST.get('destination')) - except StockLocation.DoesNotExist: - pass - except ValueError: - pass - - return self.do_move(destination, set_default_loc, note=note) - - elif self.stock_action == 'add': - return self.do_add(note=note) - - elif self.stock_action == 'take': - return self.do_take(note=note) - - elif self.stock_action == 'count': - return self.do_count(note=note) - - elif self.stock_action == 'delete': - return self.do_delete(note=note) - - else: - return _('No action performed') - - def do_add(self, note=None): - - count = 0 - - for item in self.stock_items: - if item.new_quantity <= 0: - continue - - item.add_stock(item.new_quantity, self.request.user, notes=note) - - count += 1 - - return _('Added stock to {n} items').format(n=count) - - def do_take(self, note=None): - - count = 0 - - for item in self.stock_items: - if item.new_quantity <= 0: - continue - - item.take_stock(item.new_quantity, self.request.user, notes=note) - - count += 1 - - return _('Removed stock from {n} items').format(n=count) - - def do_count(self, note=None): - - count = 0 - - for item in self.stock_items: - - item.stocktake(item.new_quantity, self.request.user, notes=note) - - count += 1 - - return _("Counted stock for {n} items".format(n=count)) - - def do_move(self, destination, set_loc=None, note=None): - """ Perform actual stock movement """ - - count = 0 - - for item in self.stock_items: - # Avoid moving zero quantity - if item.new_quantity <= 0: - continue - - # If we wish to set the destination location to the default one - if set_loc: - item.part.default_location = destination - item.part.save() - - # Do not move to the same location (unless the quantity is different) - if destination == item.location and item.new_quantity == item.quantity: - continue - - item.move(destination, note, self.request.user, quantity=item.new_quantity) - - count += 1 - - # Is ownership control enabled? - stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL') - - if stock_ownership_control: - # Fetch destination owner - destination_owner = destination.owner - - if destination_owner: - # Update owner - item.owner = destination_owner - item.save() - - if count == 0: - return _('No items were moved') - - else: - return _('Moved {n} items to {dest}').format( - n=count, - dest=destination.pathstring) - - def do_delete(self): - """ Delete multiple stock items """ - - count = 0 - # note = self.request.POST['note'] - - for item in self.stock_items: - - # TODO - In the future, StockItems should not be 'deleted' - # TODO - Instead, they should be marked as "inactive" - - item.delete() - - count += 1 - - return _("Deleted {n} stock items").format(n=count) - - class StockItemEdit(AjaxUpdateView): """ View for editing details of a single StockItem From 77cfadad42fbcaccac680dc6d168e406b2f087ee Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jul 2021 21:11:29 +1000 Subject: [PATCH 372/445] Add 'title' option for contsructed fields --- InvenTree/stock/api.py | 4 ---- InvenTree/templates/js/forms.js | 5 +++++ InvenTree/templates/js/stock.js | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 91810dddc6..08e948607a 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -120,9 +120,6 @@ class StockAdjust(APIView): - StockAdd: add stock items - StockRemove: remove stock items - StockTransfer: transfer stock items - - # TODO - This needs serious refactoring!!! - """ queryset = StockItem.objects.none() @@ -502,7 +499,6 @@ class StockList(generics.ListCreateAPIView): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) - # TODO - Save the user who created this item item = serializer.save() # A location was *not* specified - try to infer it diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index a9747d8f7d..b71551747c 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -1473,6 +1473,11 @@ function constructInputOptions(name, classes, type, parameters) { opts.push(`required=''`); } + // Custom mouseover title? + if (parameters.title != null) { + opts.push(`title='${parameters.title}'`); + } + // Placeholder? if (parameters.placeholder != null) { opts.push(`placeholder='${parameters.placeholder}'`); diff --git a/InvenTree/templates/js/stock.js b/InvenTree/templates/js/stock.js index 6ce4c3aae4..f173f868f7 100644 --- a/InvenTree/templates/js/stock.js +++ b/InvenTree/templates/js/stock.js @@ -147,6 +147,7 @@ function adjustStock(action, items, options={}) { min_value: minValue, max_value: maxValue, read_only: readonly, + title: readonly ? '{% trans "Quantity cannot be adjusted for serialized stock" %}' : '{% trans "Specify stock quantity" %}', } ) }; From ccf17bf4c5c0d954f2fec6ae4c25cbcfa718c62e Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jul 2021 21:19:00 +1000 Subject: [PATCH 373/445] Fix dodgy CSS file --- .../static/select2/css/select2-bootstrap.css | 4052 ----------------- InvenTree/templates/base.html | 1 - 2 files changed, 4053 deletions(-) delete mode 100644 InvenTree/InvenTree/static/select2/css/select2-bootstrap.css diff --git a/InvenTree/InvenTree/static/select2/css/select2-bootstrap.css b/InvenTree/InvenTree/static/select2/css/select2-bootstrap.css deleted file mode 100644 index 50c94c4e1f..0000000000 --- a/InvenTree/InvenTree/static/select2/css/select2-bootstrap.css +++ /dev/null @@ -1,4052 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - select2-bootstrap-theme/select2-bootstrap.css at master · select2/select2-bootstrap-theme - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          - Skip to content -
          - - - - - - - - - - - -
          - -
          - -
          - -
          - - - -
          -
          -
          - - - - - - - - - - - - -
          -
          - -
            - - - -
          • - -
            - -
            - - - Watch - - -
            - Notifications -
            -
            - - - - - - - - -
            -
            -
            - -
            -
          • - -
          • -
            -
            - - -
            -
            - - -
            - -
          • - -
          • -
            - - Fork - -
            - -

            Fork select2-bootstrap-theme

            -
            -
            - -
            -

            If this dialog fails to load, you can visit the fork page directly.

            -
            -
            -
            -
            - - -
          • -
          - -

          - - /select2-bootstrap-theme - -

          - -
          - - - - -
          -
          -
          - - - - - - - - Permalink - - - - - -
          - - -
          - - Branch: - master - - - - - - - -
          - -
          - - Find file - - - Copy path - -
          -
          - - -
          - - Find file - - - Copy path - -
          -
          - - - - -
          -
          - - @fk - fk - - 0.1.0-beta.10 - - - - 87f8621 - Mar 30, 2017 - -
          - -
          -
          - - 1 contributor - - -
          - -

          - Users who have contributed to this file -

          -
          - - -
          -
          -
          -
          - - - - - -
          - -
          - -
          - 722 lines (625 sloc) - - 22.6 KB -
          - -
          - -
          - Raw - Blame - History -
          - - -
          - - - - -
          - -
          -
          - -
          -
          -
          - - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          /*!
          * Select2 Bootstrap Theme v0.1.0-beta.10 (https://select2.github.io/select2-bootstrap-theme)
          * Copyright 2015-2017 Florian Kissling and contributors (https://github.com/select2/select2-bootstrap-theme/graphs/contributors)
          * Licensed under MIT (https://github.com/select2/select2-bootstrap-theme/blob/master/LICENSE)
          */
          -
          .select2-container--bootstrap {
          display: block;
          /*------------------------------------* #COMMON STYLES
          \*------------------------------------*/
          /**
          * Search field in the Select2 dropdown.
          */
          /**
          * No outline for all search fields - in the dropdown
          * and inline in multi Select2s.
          */
          /**
          * Adjust Select2's choices hover and selected styles to match
          * Bootstrap 3's default dropdown styles.
          *
          * @see http://getbootstrap.com/components/#dropdowns
          */
          /**
          * Clear the selection.
          */
          /**
          * Address disabled Select2 styles.
          *
          * @see https://select2.github.io/examples.html#disabled
          * @see http://getbootstrap.com/css/#forms-control-disabled
          */
          /*------------------------------------* #DROPDOWN
          \*------------------------------------*/
          /**
          * Dropdown border color and box-shadow.
          */
          /**
          * Limit the dropdown height.
          */
          /*------------------------------------* #SINGLE SELECT2
          \*------------------------------------*/
          /*------------------------------------* #MULTIPLE SELECT2
          \*------------------------------------*/
          /**
          * Address Bootstrap control sizing classes
          *
          * 1. Reset Bootstrap defaults.
          * 2. Adjust the dropdown arrow button icon position.
          *
          * @see http://getbootstrap.com/css/#forms-control-sizes
          */
          /* 1 */
          /*------------------------------------* #RTL SUPPORT
          \*------------------------------------*/
          }
          -
          .select2-container--bootstrap .select2-selection {
          -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
          background-color: #fff;
          border: 1px solid #ccc;
          border-radius: 4px;
          color: #555555;
          font-size: 14px;
          outline: 0;
          }
          -
          .select2-container--bootstrap .select2-selection.form-control {
          border-radius: 4px;
          }
          -
          .select2-container--bootstrap .select2-search--dropdown .select2-search__field {
          -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
          background-color: #fff;
          border: 1px solid #ccc;
          border-radius: 4px;
          color: #555555;
          font-size: 14px;
          }
          -
          .select2-container--bootstrap .select2-search__field {
          outline: 0;
          /* Firefox 18- */
          /**
          * Firefox 19+
          *
          * @see http://stackoverflow.com/questions/24236240/color-for-styled-placeholder-text-is-muted-in-firefox
          */
          }
          -
          .select2-container--bootstrap .select2-search__field::-webkit-input-placeholder {
          color: #999;
          }
          -
          .select2-container--bootstrap .select2-search__field:-moz-placeholder {
          color: #999;
          }
          -
          .select2-container--bootstrap .select2-search__field::-moz-placeholder {
          color: #999;
          opacity: 1;
          }
          -
          .select2-container--bootstrap .select2-search__field:-ms-input-placeholder {
          color: #999;
          }
          -
          .select2-container--bootstrap .select2-results__option {
          padding: 6px 12px;
          /**
          * Disabled results.
          *
          * @see https://select2.github.io/examples.html#disabled-results
          */
          /**
          * Hover state.
          */
          /**
          * Selected state.
          */
          }
          -
          .select2-container--bootstrap .select2-results__option[role=group] {
          padding: 0;
          }
          -
          .select2-container--bootstrap .select2-results__option[aria-disabled=true] {
          color: #777777;
          cursor: not-allowed;
          }
          -
          .select2-container--bootstrap .select2-results__option[aria-selected=true] {
          background-color: #f5f5f5;
          color: #262626;
          }
          -
          .select2-container--bootstrap .select2-results__option--highlighted[aria-selected] {
          background-color: #337ab7;
          color: #fff;
          }
          -
          .select2-container--bootstrap .select2-results__option .select2-results__option {
          padding: 6px 12px;
          }
          -
          .select2-container--bootstrap .select2-results__option .select2-results__option .select2-results__group {
          padding-left: 0;
          }
          -
          .select2-container--bootstrap .select2-results__option .select2-results__option .select2-results__option {
          margin-left: -12px;
          padding-left: 24px;
          }
          -
          .select2-container--bootstrap .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
          margin-left: -24px;
          padding-left: 36px;
          }
          -
          .select2-container--bootstrap .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
          margin-left: -36px;
          padding-left: 48px;
          }
          -
          .select2-container--bootstrap .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
          margin-left: -48px;
          padding-left: 60px;
          }
          -
          .select2-container--bootstrap .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
          margin-left: -60px;
          padding-left: 72px;
          }
          -
          .select2-container--bootstrap .select2-results__group {
          color: #777777;
          display: block;
          padding: 6px 12px;
          font-size: 12px;
          line-height: 1.42857143;
          white-space: nowrap;
          }
          -
          .select2-container--bootstrap.select2-container--focus .select2-selection, .select2-container--bootstrap.select2-container--open .select2-selection {
          -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
          -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
          -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
          -webkit-transition: border-color ease-in-out 0.15s, -webkit-box-shadow ease-in-out 0.15s;
          transition: border-color ease-in-out 0.15s, -webkit-box-shadow ease-in-out 0.15s;
          transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
          transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s, -webkit-box-shadow ease-in-out 0.15s;
          border-color: #66afe9;
          }
          -
          .select2-container--bootstrap.select2-container--open {
          /**
          * Make the dropdown arrow point up while the dropdown is visible.
          */
          /**
          * Handle border radii of the container when the dropdown is showing.
          */
          }
          -
          .select2-container--bootstrap.select2-container--open .select2-selection .select2-selection__arrow b {
          border-color: transparent transparent #999 transparent;
          border-width: 0 4px 4px 4px;
          }
          -
          .select2-container--bootstrap.select2-container--open.select2-container--below .select2-selection {
          border-bottom-right-radius: 0;
          border-bottom-left-radius: 0;
          border-bottom-color: transparent;
          }
          -
          .select2-container--bootstrap.select2-container--open.select2-container--above .select2-selection {
          border-top-right-radius: 0;
          border-top-left-radius: 0;
          border-top-color: transparent;
          }
          -
          .select2-container--bootstrap .select2-selection__clear {
          color: #999;
          cursor: pointer;
          float: right;
          font-weight: bold;
          margin-right: 10px;
          }
          -
          .select2-container--bootstrap .select2-selection__clear:hover {
          color: #333;
          }
          -
          .select2-container--bootstrap.select2-container--disabled .select2-selection {
          border-color: #ccc;
          -webkit-box-shadow: none;
          box-shadow: none;
          }
          -
          .select2-container--bootstrap.select2-container--disabled .select2-selection,
          .select2-container--bootstrap.select2-container--disabled .select2-search__field {
          cursor: not-allowed;
          }
          -
          .select2-container--bootstrap.select2-container--disabled .select2-selection,
          .select2-container--bootstrap.select2-container--disabled .select2-selection--multiple .select2-selection__choice {
          background-color: #eeeeee;
          }
          -
          .select2-container--bootstrap.select2-container--disabled .select2-selection__clear,
          .select2-container--bootstrap.select2-container--disabled .select2-selection--multiple .select2-selection__choice__remove {
          display: none;
          }
          -
          .select2-container--bootstrap .select2-dropdown {
          -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
          box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
          border-color: #66afe9;
          overflow-x: hidden;
          margin-top: -1px;
          }
          -
          .select2-container--bootstrap .select2-dropdown--above {
          -webkit-box-shadow: 0px -6px 12px rgba(0, 0, 0, 0.175);
          box-shadow: 0px -6px 12px rgba(0, 0, 0, 0.175);
          margin-top: 1px;
          }
          -
          .select2-container--bootstrap .select2-results > .select2-results__options {
          max-height: 200px;
          overflow-y: auto;
          }
          -
          .select2-container--bootstrap .select2-selection--single {
          height: 34px;
          line-height: 1.42857143;
          padding: 6px 24px 6px 12px;
          /**
          * Adjust the single Select2's dropdown arrow button appearance.
          */
          }
          -
          .select2-container--bootstrap .select2-selection--single .select2-selection__arrow {
          position: absolute;
          bottom: 0;
          right: 12px;
          top: 0;
          width: 4px;
          }
          -
          .select2-container--bootstrap .select2-selection--single .select2-selection__arrow b {
          border-color: #999 transparent transparent transparent;
          border-style: solid;
          border-width: 4px 4px 0 4px;
          height: 0;
          left: 0;
          margin-left: -4px;
          margin-top: -2px;
          position: absolute;
          top: 50%;
          width: 0;
          }
          -
          .select2-container--bootstrap .select2-selection--single .select2-selection__rendered {
          color: #555555;
          padding: 0;
          }
          -
          .select2-container--bootstrap .select2-selection--single .select2-selection__placeholder {
          color: #999;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple {
          min-height: 34px;
          padding: 0;
          height: auto;
          /**
          * Make Multi Select2's choices match Bootstrap 3's default button styles.
          */
          /**
          * Minus 2px borders.
          */
          /**
          * Clear the selection.
          */
          }
          -
          .select2-container--bootstrap .select2-selection--multiple .select2-selection__rendered {
          -webkit-box-sizing: border-box;
          -moz-box-sizing: border-box;
          box-sizing: border-box;
          display: block;
          line-height: 1.42857143;
          list-style: none;
          margin: 0;
          overflow: hidden;
          padding: 0;
          width: 100%;
          text-overflow: ellipsis;
          white-space: nowrap;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple .select2-selection__placeholder {
          color: #999;
          float: left;
          margin-top: 5px;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice {
          color: #555555;
          background: #fff;
          border: 1px solid #ccc;
          border-radius: 4px;
          cursor: default;
          float: left;
          margin: 5px 0 0 6px;
          padding: 0 6px;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple .select2-search--inline .select2-search__field {
          background: transparent;
          padding: 0 12px;
          height: 32px;
          line-height: 1.42857143;
          margin-top: 0;
          min-width: 5em;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice__remove {
          color: #999;
          cursor: pointer;
          display: inline-block;
          font-weight: bold;
          margin-right: 3px;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice__remove:hover {
          color: #333;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple .select2-selection__clear {
          margin-top: 6px;
          }
          -
          .select2-container--bootstrap .select2-selection--single.input-sm,
          .input-group-sm .select2-container--bootstrap .select2-selection--single,
          .form-group-sm .select2-container--bootstrap .select2-selection--single {
          border-radius: 3px;
          font-size: 12px;
          height: 30px;
          line-height: 1.5;
          padding: 5px 22px 5px 10px;
          /* 2 */
          }
          -
          .select2-container--bootstrap .select2-selection--single.input-sm .select2-selection__arrow b,
          .input-group-sm .select2-container--bootstrap .select2-selection--single .select2-selection__arrow b,
          .form-group-sm .select2-container--bootstrap .select2-selection--single .select2-selection__arrow b {
          margin-left: -5px;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple.input-sm,
          .input-group-sm .select2-container--bootstrap .select2-selection--multiple,
          .form-group-sm .select2-container--bootstrap .select2-selection--multiple {
          min-height: 30px;
          border-radius: 3px;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple.input-sm .select2-selection__choice,
          .input-group-sm .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice,
          .form-group-sm .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice {
          font-size: 12px;
          line-height: 1.5;
          margin: 4px 0 0 5px;
          padding: 0 5px;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple.input-sm .select2-search--inline .select2-search__field,
          .input-group-sm .select2-container--bootstrap .select2-selection--multiple .select2-search--inline .select2-search__field,
          .form-group-sm .select2-container--bootstrap .select2-selection--multiple .select2-search--inline .select2-search__field {
          padding: 0 10px;
          font-size: 12px;
          height: 28px;
          line-height: 1.5;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple.input-sm .select2-selection__clear,
          .input-group-sm .select2-container--bootstrap .select2-selection--multiple .select2-selection__clear,
          .form-group-sm .select2-container--bootstrap .select2-selection--multiple .select2-selection__clear {
          margin-top: 5px;
          }
          -
          .select2-container--bootstrap .select2-selection--single.input-lg,
          .input-group-lg .select2-container--bootstrap .select2-selection--single,
          .form-group-lg .select2-container--bootstrap .select2-selection--single {
          border-radius: 6px;
          font-size: 18px;
          height: 46px;
          line-height: 1.3333333;
          padding: 10px 31px 10px 16px;
          /* 1 */
          }
          -
          .select2-container--bootstrap .select2-selection--single.input-lg .select2-selection__arrow,
          .input-group-lg .select2-container--bootstrap .select2-selection--single .select2-selection__arrow,
          .form-group-lg .select2-container--bootstrap .select2-selection--single .select2-selection__arrow {
          width: 5px;
          }
          -
          .select2-container--bootstrap .select2-selection--single.input-lg .select2-selection__arrow b,
          .input-group-lg .select2-container--bootstrap .select2-selection--single .select2-selection__arrow b,
          .form-group-lg .select2-container--bootstrap .select2-selection--single .select2-selection__arrow b {
          border-width: 5px 5px 0 5px;
          margin-left: -5px;
          margin-left: -10px;
          margin-top: -2.5px;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple.input-lg,
          .input-group-lg .select2-container--bootstrap .select2-selection--multiple,
          .form-group-lg .select2-container--bootstrap .select2-selection--multiple {
          min-height: 46px;
          border-radius: 6px;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple.input-lg .select2-selection__choice,
          .input-group-lg .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice,
          .form-group-lg .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice {
          font-size: 18px;
          line-height: 1.3333333;
          border-radius: 4px;
          margin: 9px 0 0 8px;
          padding: 0 10px;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple.input-lg .select2-search--inline .select2-search__field,
          .input-group-lg .select2-container--bootstrap .select2-selection--multiple .select2-search--inline .select2-search__field,
          .form-group-lg .select2-container--bootstrap .select2-selection--multiple .select2-search--inline .select2-search__field {
          padding: 0 16px;
          font-size: 18px;
          height: 44px;
          line-height: 1.3333333;
          }
          -
          .select2-container--bootstrap .select2-selection--multiple.input-lg .select2-selection__clear,
          .input-group-lg .select2-container--bootstrap .select2-selection--multiple .select2-selection__clear,
          .form-group-lg .select2-container--bootstrap .select2-selection--multiple .select2-selection__clear {
          margin-top: 10px;
          }
          -
          .select2-container--bootstrap .select2-selection.input-lg.select2-container--open .select2-selection--single {
          /**
          * Make the dropdown arrow point up while the dropdown is visible.
          */
          }
          -
          .select2-container--bootstrap .select2-selection.input-lg.select2-container--open .select2-selection--single .select2-selection__arrow b {
          border-color: transparent transparent #999 transparent;
          border-width: 0 5px 5px 5px;
          }
          -
          .input-group-lg .select2-container--bootstrap .select2-selection.select2-container--open .select2-selection--single {
          /**
          * Make the dropdown arrow point up while the dropdown is visible.
          */
          }
          -
          .input-group-lg .select2-container--bootstrap .select2-selection.select2-container--open .select2-selection--single .select2-selection__arrow b {
          border-color: transparent transparent #999 transparent;
          border-width: 0 5px 5px 5px;
          }
          -
          .select2-container--bootstrap[dir="rtl"] {
          /**
          * Single Select2
          *
          * 1. Makes sure that .select2-selection__placeholder is positioned
          * correctly.
          */
          /**
          * Multiple Select2
          */
          }
          -
          .select2-container--bootstrap[dir="rtl"] .select2-selection--single {
          padding-left: 24px;
          padding-right: 12px;
          }
          -
          .select2-container--bootstrap[dir="rtl"] .select2-selection--single .select2-selection__rendered {
          padding-right: 0;
          padding-left: 0;
          text-align: right;
          /* 1 */
          }
          -
          .select2-container--bootstrap[dir="rtl"] .select2-selection--single .select2-selection__clear {
          float: left;
          }
          -
          .select2-container--bootstrap[dir="rtl"] .select2-selection--single .select2-selection__arrow {
          left: 12px;
          right: auto;
          }
          -
          .select2-container--bootstrap[dir="rtl"] .select2-selection--single .select2-selection__arrow b {
          margin-left: 0;
          }
          -
          .select2-container--bootstrap[dir="rtl"] .select2-selection--multiple .select2-selection__choice,
          .select2-container--bootstrap[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder,
          .select2-container--bootstrap[dir="rtl"] .select2-selection--multiple .select2-search--inline {
          float: right;
          }
          -
          .select2-container--bootstrap[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
          margin-left: 0;
          margin-right: 6px;
          }
          -
          .select2-container--bootstrap[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
          margin-left: 2px;
          margin-right: auto;
          }
          -
          /*------------------------------------* #ADDITIONAL GOODIES
          \*------------------------------------*/
          /**
          * Address Bootstrap's validation states
          *
          * If a Select2 widget parent has one of Bootstrap's validation state modifier
          * classes, adjust Select2's border colors and focus states accordingly.
          * You may apply said classes to the Select2 dropdown (body > .select2-container)
          * via JavaScript match Bootstraps' to make its styles match.
          *
          * @see http://getbootstrap.com/css/#forms-control-validation
          */
          .has-warning .select2-dropdown,
          .has-warning .select2-selection {
          border-color: #8a6d3b;
          }
          -
          .has-warning .select2-container--focus .select2-selection,
          .has-warning .select2-container--open .select2-selection {
          -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
          border-color: #66512c;
          }
          -
          .has-warning.select2-drop-active {
          border-color: #66512c;
          }
          -
          .has-warning.select2-drop-active.select2-drop.select2-drop-above {
          border-top-color: #66512c;
          }
          -
          .has-error .select2-dropdown,
          .has-error .select2-selection {
          border-color: #a94442;
          }
          -
          .has-error .select2-container--focus .select2-selection,
          .has-error .select2-container--open .select2-selection {
          -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
          border-color: #843534;
          }
          -
          .has-error.select2-drop-active {
          border-color: #843534;
          }
          -
          .has-error.select2-drop-active.select2-drop.select2-drop-above {
          border-top-color: #843534;
          }
          -
          .has-success .select2-dropdown,
          .has-success .select2-selection {
          border-color: #3c763d;
          }
          -
          .has-success .select2-container--focus .select2-selection,
          .has-success .select2-container--open .select2-selection {
          -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
          border-color: #2b542c;
          }
          -
          .has-success.select2-drop-active {
          border-color: #2b542c;
          }
          -
          .has-success.select2-drop-active.select2-drop.select2-drop-above {
          border-top-color: #2b542c;
          }
          -
          /**
          * Select2 widgets in Bootstrap Input Groups
          *
          * @see http://getbootstrap.com/components/#input-groups
          * @see https://github.com/twbs/bootstrap/blob/master/less/input-groups.less
          */
          /**
          * Reset rounded corners
          */
          .input-group > .select2-hidden-accessible:first-child + .select2-container--bootstrap > .selection > .select2-selection,
          .input-group > .select2-hidden-accessible:first-child + .select2-container--bootstrap > .selection > .select2-selection.form-control {
          border-bottom-right-radius: 0;
          border-top-right-radius: 0;
          }
          -
          .input-group > .select2-hidden-accessible:not(:first-child) + .select2-container--bootstrap:not(:last-child) > .selection > .select2-selection,
          .input-group > .select2-hidden-accessible:not(:first-child) + .select2-container--bootstrap:not(:last-child) > .selection > .select2-selection.form-control {
          border-radius: 0;
          }
          -
          .input-group > .select2-hidden-accessible:not(:first-child):not(:last-child) + .select2-container--bootstrap:last-child > .selection > .select2-selection,
          .input-group > .select2-hidden-accessible:not(:first-child):not(:last-child) + .select2-container--bootstrap:last-child > .selection > .select2-selection.form-control {
          border-bottom-left-radius: 0;
          border-top-left-radius: 0;
          }
          -
          .input-group > .select2-container--bootstrap {
          display: table;
          table-layout: fixed;
          position: relative;
          z-index: 2;
          width: 100%;
          margin-bottom: 0;
          /**
          * Adjust z-index like Bootstrap does to show the focus-box-shadow
          * above appended buttons in .input-group and .form-group.
          */
          /**
          * Adjust alignment of Bootstrap buttons in Bootstrap Input Groups to address
          * Multi Select2's height which - depending on how many elements have been selected -
          * may grow taller than its initial size.
          *
          * @see http://getbootstrap.com/components/#input-groups
          */
          }
          -
          .input-group > .select2-container--bootstrap > .selection > .select2-selection.form-control {
          float: none;
          }
          -
          .input-group > .select2-container--bootstrap.select2-container--open, .input-group > .select2-container--bootstrap.select2-container--focus {
          z-index: 3;
          }
          -
          .input-group > .select2-container--bootstrap,
          .input-group > .select2-container--bootstrap .input-group-btn,
          .input-group > .select2-container--bootstrap .input-group-btn .btn {
          vertical-align: top;
          }
          -
          /**
          * Temporary fix for https://github.com/select2/select2-bootstrap-theme/issues/9
          *
          * Provides `!important` for certain properties of the class applied to the
          * original `<select>` element to hide it.
          *
          * @see https://github.com/select2/select2/pull/3301
          * @see https://github.com/fk/select2/commit/31830c7b32cb3d8e1b12d5b434dee40a6e753ada
          */
          .form-control.select2-hidden-accessible {
          position: absolute !important;
          width: 1px !important;
          }
          -
          /**
          * Display override for inline forms
          */
          @media (min-width: 768px) {
          .form-inline .select2-container--bootstrap {
          display: inline-block;
          }
          }
          - - - -
          - -
          - - - -
          - - -
          - - -
          -
          - - - -
          - -
          - -
          -
          - - -
          - - - - - - -
          - - - You can’t perform that action at this time. -
          - - - - - - - - - - - - - - -
          - - - - diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html index 76104d8fe2..4818fda1c6 100644 --- a/InvenTree/templates/base.html +++ b/InvenTree/templates/base.html @@ -41,7 +41,6 @@ - From c3b0593abadc3772ab675bce761dd6a1a09de6ca Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jul 2021 21:32:09 +1000 Subject: [PATCH 374/445] Refactor ManufacturerPartCreate form --- .../company/detail_manufacturer_part.html | 38 +++++------ InvenTree/company/test_views.py | 39 ----------- InvenTree/company/urls.py | 3 +- InvenTree/company/views.py | 68 ------------------- InvenTree/part/templates/part/supplier.html | 31 +++++---- 5 files changed, 34 insertions(+), 145 deletions(-) diff --git a/InvenTree/company/templates/company/detail_manufacturer_part.html b/InvenTree/company/templates/company/detail_manufacturer_part.html index 41eb005b2f..4990874059 100644 --- a/InvenTree/company/templates/company/detail_manufacturer_part.html +++ b/InvenTree/company/templates/company/detail_manufacturer_part.html @@ -53,29 +53,23 @@ {{ block.super }} $("#manufacturer-part-create").click(function () { - launchModalForm( - "{% url 'manufacturer-part-create' %}", - { - data: { - manufacturer: {{ company.id }}, + + constructForm('{% url "api-manufacturer-part-list" %}', { + fields: { + part: {}, + manufacturer: { + value: {{ company.pk }}, }, - success: function() { - $("#part-table").bootstrapTable("refresh"); - }, - secondary: [ - { - field: 'part', - label: '{% trans "New Part" %}', - title: '{% trans "Create new Part" %}', - url: "{% url 'part-create' %}" - }, - { - field: 'manufacturer', - label: '{% trans "New Manufacturer" %}', - title: '{% trans "Create new Manufacturer" %}', - }, - ] - }); + MPN: {}, + description: {}, + link: {}, + }, + method: 'POST', + title: '{% trans "Add Manufacturer Part" %}', + onSuccess: function() { + $("#part-table").bootstrapTable("refresh"); + } + }); }); loadManufacturerPartTable( diff --git a/InvenTree/company/test_views.py b/InvenTree/company/test_views.py index 4c53bbb8c4..6fc4281f2b 100644 --- a/InvenTree/company/test_views.py +++ b/InvenTree/company/test_views.py @@ -194,45 +194,6 @@ class ManufacturerPartViewTests(CompanyViewTestBase): Tests for the ManufacturerPart views. """ - def test_manufacturer_part_create(self): - """ - Test the ManufacturerPartCreate view. - """ - - url = reverse('manufacturer-part-create') - - # First check that we can GET the form - response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # How many manufaturer parts are already in the database? - n = ManufacturerPart.objects.all().count() - - data = { - 'part': 1, - 'manufacturer': 6, - } - - # MPN is required! (form should fail) - (response, errors) = self.post(url, data, valid=False) - - self.assertIsNotNone(errors.get('MPN', None)) - - data['MPN'] = 'TEST-ME-123' - - (response, errors) = self.post(url, data, valid=True) - - # Check that the ManufacturerPart was created! - self.assertEqual(n + 1, ManufacturerPart.objects.all().count()) - - # Try to create duplicate ManufacturerPart - (response, errors) = self.post(url, data, valid=False) - - self.assertIsNotNone(errors.get('__all__', None)) - - # Check that the ManufacturerPart count stayed the same - self.assertEqual(n + 1, ManufacturerPart.objects.all().count()) - def test_supplier_part_create(self): """ Test that the SupplierPartCreate view creates Manufacturer Part. diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index 4fe0519ea9..e9e125d9e4 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -38,8 +38,7 @@ company_urls = [ ] manufacturer_part_urls = [ - url(r'^new/?', views.ManufacturerPartCreate.as_view(), name='manufacturer-part-create'), - + url(r'^(?P\d+)/', include([ url(r'^suppliers/', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part_suppliers.html'), name='manufacturer-part-suppliers'), url('^.*$', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part_suppliers.html'), name='manufacturer-part-detail'), diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index 60c37a392a..afdf2b87dc 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -242,74 +242,6 @@ class ManufacturerPartDetail(DetailView): return ctx -class ManufacturerPartCreate(AjaxCreateView): - """ Create view for making new ManufacturerPart """ - - model = ManufacturerPart - form_class = EditManufacturerPartForm - ajax_template_name = 'company/manufacturer_part_create.html' - ajax_form_title = _('Create New Manufacturer Part') - context_object_name = 'part' - - def get_context_data(self): - """ - Supply context data to the form - """ - - ctx = super().get_context_data() - - # Add 'part' object - form = self.get_form() - - part = form['part'].value() - - try: - part = Part.objects.get(pk=part) - except (ValueError, Part.DoesNotExist): - part = None - - ctx['part'] = part - - return ctx - - def get_form(self): - """ Create Form instance to create a new ManufacturerPart object. - Hide some fields if they are not appropriate in context - """ - form = super(AjaxCreateView, self).get_form() - - if form.initial.get('part', None): - # Hide the part field - form.fields['part'].widget = HiddenInput() - - return form - - def get_initial(self): - """ Provide initial data for new ManufacturerPart: - - - If 'manufacturer_id' provided, pre-fill manufacturer field - - If 'part_id' provided, pre-fill part field - """ - initials = super(ManufacturerPartCreate, self).get_initial().copy() - - manufacturer_id = self.get_param('manufacturer') - part_id = self.get_param('part') - - if manufacturer_id: - try: - initials['manufacturer'] = Company.objects.get(pk=manufacturer_id) - except (ValueError, Company.DoesNotExist): - pass - - if part_id: - try: - initials['part'] = Part.objects.get(pk=part_id) - except (ValueError, Part.DoesNotExist): - pass - - return initials - - class SupplierPartDetail(DetailView): """ Detail view for SupplierPart """ model = SupplierPart diff --git a/InvenTree/part/templates/part/supplier.html b/InvenTree/part/templates/part/supplier.html index 8c01243541..8ae73cd07c 100644 --- a/InvenTree/part/templates/part/supplier.html +++ b/InvenTree/part/templates/part/supplier.html @@ -148,21 +148,24 @@ }); $('#manufacturer-create').click(function () { - launchModalForm( - "{% url 'manufacturer-part-create' %}", - { - reload: true, - data: { - part: {{ part.id }} + + constructForm('{% url "api-manufacturer-part-list" %}', { + fields: { + part: { + value: {{ part.pk }}, + hidden: true, }, - secondary: [ - { - field: 'manufacturer', - label: '{% trans "New Manufacturer" %}', - title: '{% trans "Create new manufacturer" %}', - } - ] - }); + manufacturer: {}, + MPN: {}, + description: {}, + link: {}, + }, + method: 'POST', + title: '{% trans "Add Manufacturer Part" %}', + onSuccess: function() { + $("#manufacturer-table").bootstrapTable("refresh"); + } + }); }); {% endblock %} \ No newline at end of file From 30fd3c8841f0e35020e126565d114d2b0e0dd131 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jul 2021 22:03:36 +1000 Subject: [PATCH 375/445] Unit test fixes --- InvenTree/stock/test_api.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index 729bf25a9b..74f9505c4a 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -7,8 +7,8 @@ from __future__ import unicode_literals from datetime import datetime, timedelta -from rest_framework import status from django.urls import reverse +from rest_framework import status from InvenTree.status_codes import StockStatus from InvenTree.api_tester import InvenTreeAPITestCase @@ -456,30 +456,32 @@ class StocktakeTest(StockAPITestCase): # POST without a PK response = self.post(url, data) - self.assertContains(response, 'must contain a valid pk', status_code=status.HTTP_400_BAD_REQUEST) + self.assertContains(response, 'must contain a valid integer primary-key', status_code=status.HTTP_400_BAD_REQUEST) - # POST with a PK but no quantity + # POST with an invalid PK data['items'] = [{ 'pk': 10 }] response = self.post(url, data) - self.assertContains(response, 'must contain a valid pk', status_code=status.HTTP_400_BAD_REQUEST) + self.assertContains(response, 'does not match valid stock item', status_code=status.HTTP_400_BAD_REQUEST) + # POST with missing quantity value data['items'] = [{ 'pk': 1234 }] response = self.post(url, data) - self.assertContains(response, 'must contain a valid quantity', status_code=status.HTTP_400_BAD_REQUEST) + self.assertContains(response, 'Invalid quantity value', status_code=status.HTTP_400_BAD_REQUEST) + # POST with an invalid quantity value data['items'] = [{ 'pk': 1234, 'quantity': '10x0d' }] response = self.post(url, data) - self.assertContains(response, 'must contain a valid quantity', status_code=status.HTTP_400_BAD_REQUEST) + self.assertContains(response, 'Invalid quantity value', status_code=status.HTTP_400_BAD_REQUEST) data['items'] = [{ 'pk': 1234, From 7c807674143fe26ce80446f9607b83a606582b00 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jul 2021 22:06:03 +1000 Subject: [PATCH 376/445] PEP fixes --- InvenTree/company/forms.py | 20 ------------------- .../company/detail_manufacturer_part.html | 8 ++++++-- .../company/manufacturer_part_base.html | 8 ++++++-- InvenTree/company/views.py | 1 - 4 files changed, 12 insertions(+), 25 deletions(-) diff --git a/InvenTree/company/forms.py b/InvenTree/company/forms.py index 15f380ae44..079e871b84 100644 --- a/InvenTree/company/forms.py +++ b/InvenTree/company/forms.py @@ -12,7 +12,6 @@ from django.utils.translation import ugettext_lazy as _ import django.forms from .models import Company -from .models import ManufacturerPart from .models import SupplierPart from .models import SupplierPriceBreak @@ -35,25 +34,6 @@ class CompanyImageDownloadForm(HelperForm): ] -class EditManufacturerPartForm(HelperForm): - """ Form for editing a ManufacturerPart object """ - - field_prefix = { - 'link': 'fa-link', - 'MPN': 'fa-hashtag', - } - - class Meta: - model = ManufacturerPart - fields = [ - 'part', - 'manufacturer', - 'MPN', - 'description', - 'link', - ] - - class EditSupplierPartForm(HelperForm): """ Form for editing a SupplierPart object """ diff --git a/InvenTree/company/templates/company/detail_manufacturer_part.html b/InvenTree/company/templates/company/detail_manufacturer_part.html index 4990874059..0ff261ec67 100644 --- a/InvenTree/company/templates/company/detail_manufacturer_part.html +++ b/InvenTree/company/templates/company/detail_manufacturer_part.html @@ -60,9 +60,13 @@ manufacturer: { value: {{ company.pk }}, }, - MPN: {}, + MPN: { + icon: 'fa-hashtag', + }, description: {}, - link: {}, + link: { + icon: 'fa-link', + }, }, method: 'POST', title: '{% trans "Add Manufacturer Part" %}', diff --git a/InvenTree/company/templates/company/manufacturer_part_base.html b/InvenTree/company/templates/company/manufacturer_part_base.html index 8fdcd79f71..ed1612ea76 100644 --- a/InvenTree/company/templates/company/manufacturer_part_base.html +++ b/InvenTree/company/templates/company/manufacturer_part_base.html @@ -118,9 +118,13 @@ $('#edit-part').click(function () { fields: { part: {}, manufacturer: {}, - MPN: {}, + MPN: { + icon: 'fa-hashtag', + }, description: {}, - link: {}, + link: { + icon: 'fa-link', + }, }, title: '{% trans "Edit Manufacturer Part" %}', reload: true, diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index afdf2b87dc..03fe03d411 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -29,7 +29,6 @@ from .models import SupplierPart from part.models import Part -from .forms import EditManufacturerPartForm from .forms import EditSupplierPartForm from .forms import CompanyImageDownloadForm From 0cb2b4933361ecac611755ff3fd857315c1273ea Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jul 2021 22:23:08 +1000 Subject: [PATCH 377/445] Remove unused forms --- InvenTree/part/forms.py | 10 --------- InvenTree/stock/forms.py | 44 ---------------------------------------- 2 files changed, 54 deletions(-) diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index 3b60567695..f04f512045 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -56,16 +56,6 @@ class PartImageDownloadForm(HelperForm): ] -class PartImageForm(HelperForm): - """ Form for uploading a Part image """ - - class Meta: - model = Part - fields = [ - 'image', - ] - - class BomExportForm(forms.Form): """ Simple form to let user set BOM export options, before exporting a BOM (bill of materials) file. diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py index ec3eee09d5..0061bbb984 100644 --- a/InvenTree/stock/forms.py +++ b/InvenTree/stock/forms.py @@ -328,50 +328,6 @@ class UninstallStockForm(forms.ModelForm): ] -class AdjustStockForm(forms.ModelForm): - """ Form for performing simple stock adjustments. - - - Add stock - - Remove stock - - Count stock - - Move stock - - This form is used for managing stock adjuments for single or multiple stock items. - """ - - destination = TreeNodeChoiceField(queryset=StockLocation.objects.all(), label=_('Destination'), required=True, help_text=_('Destination stock location')) - - note = forms.CharField(label=_('Notes'), required=True, help_text=_('Add note (required)')) - - # transaction = forms.BooleanField(required=False, initial=False, label='Create Transaction', help_text='Create a stock transaction for these parts') - - confirm = forms.BooleanField(required=False, initial=False, label=_('Confirm stock adjustment'), help_text=_('Confirm movement of stock items')) - - set_loc = forms.BooleanField(required=False, initial=False, label=_('Set Default Location'), help_text=_('Set the destination as the default location for selected parts')) - - class Meta: - model = StockItem - - fields = [ - 'destination', - 'note', - # 'transaction', - 'confirm', - ] - - -class EditStockItemStatusForm(HelperForm): - """ - Simple form for editing StockItem status field - """ - - class Meta: - model = StockItem - fields = [ - 'status', - ] - - class EditStockItemForm(HelperForm): """ Form for editing a StockItem object. Note that not all fields can be edited here (even if they can be specified during creation. From 77d80f5c0fabab48b193a0770d264e2e6f5b25fb Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jul 2021 23:27:11 +1000 Subject: [PATCH 378/445] Move "attachments" and "notes" to "Part Detail" page (cherry picked from commit daf0a082dc04c04cfd68cab70148a7d7cf28460f) --- InvenTree/InvenTree/static/css/inventree.css | 11 ++ InvenTree/part/templates/part/detail.html | 148 +++++++++++++++++-- InvenTree/templates/js/forms.js | 10 +- 3 files changed, 152 insertions(+), 17 deletions(-) diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index 61815f0587..ac7cf1f4e1 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -837,6 +837,12 @@ input[type="submit"] { pointer-events: none; /* Prevent this div from blocking links underneath */ } +.notes { + border-radius: 5px; + background-color: #fafafa; + padding: 5px; +} + .alert { display: none; border-radius: 5px; @@ -853,6 +859,11 @@ input[type="submit"] { margin-right: 2px; } +.btn-small { + padding: 3px; + padding-left: 5px; +} + .btn-remove { padding: 3px; padding-left: 5px; diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 5132721fec..8a78eb85a5 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -1,6 +1,7 @@ {% extends "part/part_base.html" %} {% load static %} {% load i18n %} +{% load markdownify %} {% block menubar %} @@ -135,11 +136,38 @@ {% endif %} {% if part.responsible %} - d + {% trans "Responsible User" %} {{ part.responsible }} {% endif %} + + + + + + + {% trans "Notes" %} + + +
          + +
          + + + + + {% if part.notes %} +
          + {{ part.notes | markdownify }} +
          + {% endif %} + + +
          @@ -115,6 +118,46 @@ $("#supplier-part-delete").click(function() { }); }); +$("#multi-parameter-delete").click(function() { + + var selections = $("#parameter-table").bootstrapTable("getSelections"); + + var text = ` +
          +

          {% trans "Selected parameters will be deleted" %}:

          +
            `; + + selections.forEach(function(item) { + text += `
          • ${item.name} - ${item.value}
          • `; + }); + + text += ` +
          +
          `; + + showQuestionDialog( + '{% trans "Delete Parameters" %}', + text, + { + accept_text: '{% trans "Delete" %}', + accept: function() { + // Delete each parameter via the API + var requests = []; + + selections.forEach(function(item) { + var url = `/api/company/part/manufacturer/parameter/${item.pk}/`; + + requests.push(inventreeDelete(url)); + }); + + $.when.apply($, requests).then(function() { + $('#parameter-table').bootstrapTable('refresh'); + }); + } + } + ); +}); + loadSupplierPartTable( "#supplier-table", "{% url 'api-supplier-part-list' %}", @@ -140,5 +183,5 @@ loadManufacturerPartParameterTable( ); linkButtonsToSelection($("#supplier-table"), ['#supplier-part-options']) - +linkButtonsToSelection($("#parameter-table"), ['#parameter-options']) {% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/bom.html b/InvenTree/part/templates/part/bom.html index 07da7af926..ba3e9be2b9 100644 --- a/InvenTree/part/templates/part/bom.html +++ b/InvenTree/part/templates/part/bom.html @@ -123,7 +123,7 @@ }); // Wait for *all* the requests to complete - $.when(requests).then(function() { + $.when.apply($, requests).then(function() { location.reload(); }); } diff --git a/InvenTree/templates/js/company.js b/InvenTree/templates/js/company.js index 7c70af866b..d28bca5547 100644 --- a/InvenTree/templates/js/company.js +++ b/InvenTree/templates/js/company.js @@ -213,7 +213,7 @@ function deleteManufacturerParts(selections, options={}) { }); // Wait for all the requests to complete - $.when(requests).then(function() { + $.when.apply($, requests).then(function() { if (options.onSuccess) { options.onSuccess(); @@ -352,7 +352,7 @@ function loadManufacturerPartParameterTable(table, url, options) { { checkbox: true, switchable: false, - visible: false, + visible: true, }, { field: 'name', diff --git a/InvenTree/templates/js/stock.js b/InvenTree/templates/js/stock.js index 97b9df0c68..b557f0c327 100644 --- a/InvenTree/templates/js/stock.js +++ b/InvenTree/templates/js/stock.js @@ -906,7 +906,7 @@ function loadStockTable(table, options) { ); }); - $.when(requests).then(function() { + $.when.apply($, requests).then(function() { $("#stock-table").bootstrapTable('refresh'); }); }) From 66c1e9c97d97b76e9c35ce070b3f7860769a1baa Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 10:32:07 +0200 Subject: [PATCH 218/445] currency codes in own function --- InvenTree/InvenTree/fields.py | 24 ++++++++++++++++++------ InvenTree/common/settings.py | 9 +++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/InvenTree/InvenTree/fields.py b/InvenTree/InvenTree/fields.py index c461c0e752..6fd0637045 100644 --- a/InvenTree/InvenTree/fields.py +++ b/InvenTree/InvenTree/fields.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import sys from .validators import allowable_url_schemes @@ -11,7 +12,6 @@ from django.forms.fields import URLField as FormURLField from django.db import models as models from django.core import validators from django import forms -from django.conf import settings from decimal import Decimal from djmoney.models.fields import MoneyField as ModelMoneyField @@ -38,12 +38,25 @@ class InvenTreeURLField(models.URLField): }) +def money_kwargs(): + """ returns the database settings for MoneyFields """ + kwargs = {} + kwargs['currency_choices'] = common.settings.currency_codes() + kwargs['default_currency'] = common.settings.currency_code_default + return kwargs + + class InvenTreeModelMoneyField(ModelMoneyField): """ custom MoneyField for clean migrations while using dynamic currency settings """ def __init__(self, **kwargs): - # remove currency information for a clean migration - kwargs['default_currency'] = '' - kwargs['currency_choices'] = [] + # detect if creating migration + if 'makemigrations' in sys.argv: + # remove currency information for a clean migration + kwargs['default_currency'] = '' + kwargs['currency_choices'] = [] + else: + # set defaults + kwargs.update(money_kwargs()) super().__init__(**kwargs) @@ -57,8 +70,7 @@ class InvenTreeMoneyField(MoneyField): """ custom MoneyField for clean migrations while using dynamic currency settings """ def __init__(self, *args, **kwargs): # override initial values with the real info from database - kwargs['currency_choices'] = [(a, a) for a in settings.CURRENCIES] - kwargs['default_currency'] = common.settings.currency_code_default + kwargs.update(money_kwargs()) super().__init__(*args, **kwargs) diff --git a/InvenTree/common/settings.py b/InvenTree/common/settings.py index 299d142ea9..9b107e9282 100644 --- a/InvenTree/common/settings.py +++ b/InvenTree/common/settings.py @@ -6,6 +6,7 @@ User-configurable settings for the common app from __future__ import unicode_literals from moneyed import CURRENCIES +from django.conf import settings import common.models @@ -23,6 +24,14 @@ def currency_code_default(): return code +def currency_codes(): + """ + Returns the current currency choices + """ + return [(a, a) for a in settings.CURRENCIES] + + + def stock_expiry_enabled(): """ Returns True if the stock expiry feature is enabled From 983255a05e8f39b1be598ed1f954a4e4c507602b Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 10:37:16 +0200 Subject: [PATCH 219/445] naming refactor --- InvenTree/InvenTree/fields.py | 2 +- InvenTree/common/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/InvenTree/fields.py b/InvenTree/InvenTree/fields.py index 6fd0637045..8d9ab77463 100644 --- a/InvenTree/InvenTree/fields.py +++ b/InvenTree/InvenTree/fields.py @@ -41,7 +41,7 @@ class InvenTreeURLField(models.URLField): def money_kwargs(): """ returns the database settings for MoneyFields """ kwargs = {} - kwargs['currency_choices'] = common.settings.currency_codes() + kwargs['currency_choices'] = common.settings.currency_code_mappings() kwargs['default_currency'] = common.settings.currency_code_default return kwargs diff --git a/InvenTree/common/settings.py b/InvenTree/common/settings.py index 9b107e9282..4d3b0c7940 100644 --- a/InvenTree/common/settings.py +++ b/InvenTree/common/settings.py @@ -24,7 +24,7 @@ def currency_code_default(): return code -def currency_codes(): +def currency_code_mappings(): """ Returns the current currency choices """ From 951e8910ba1cf50b9af75d3a1d629c74e2204d18 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 10:41:23 +0200 Subject: [PATCH 220/445] using functions for currency codes --- InvenTree/InvenTree/exchange.py | 4 ++-- InvenTree/InvenTree/tasks.py | 4 ++-- InvenTree/InvenTree/tests.py | 5 ++--- InvenTree/InvenTree/views.py | 4 ++-- InvenTree/common/settings.py | 7 +++++++ 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/InvenTree/InvenTree/exchange.py b/InvenTree/InvenTree/exchange.py index f5c1ad4d48..149ef6b794 100644 --- a/InvenTree/InvenTree/exchange.py +++ b/InvenTree/InvenTree/exchange.py @@ -1,5 +1,5 @@ from django.conf import settings as inventree_settings -from common.settings import currency_code_default +from common.settings import currency_code_default, currency_codes from djmoney.contrib.exchange.backends.base import SimpleExchangeBackend @@ -25,6 +25,6 @@ class InvenTreeExchange(SimpleExchangeBackend): def update_rates(self, base_currency=currency_code_default()): - symbols = ','.join(inventree_settings.CURRENCIES) + symbols = ','.join(currency_codes()) super().update_rates(base=base_currency, symbols=symbols) diff --git a/InvenTree/InvenTree/tasks.py b/InvenTree/InvenTree/tasks.py index 6397ea72e7..b01b362760 100644 --- a/InvenTree/InvenTree/tasks.py +++ b/InvenTree/InvenTree/tasks.py @@ -171,7 +171,7 @@ def update_exchange_rates(): from InvenTree.exchange import InvenTreeExchange from djmoney.contrib.exchange.models import ExchangeBackend, Rate from django.conf import settings - from common.settings import currency_code_default + from common.settings import currency_code_default, currency_codes except AppRegistryNotReady: # Apps not yet loaded! logger.info("Could not perform 'update_exchange_rates' - App registry not ready") @@ -200,7 +200,7 @@ def update_exchange_rates(): backend.update_rates(base_currency=base) # Remove any exchange rates which are not in the provided currencies - Rate.objects.filter(backend="InvenTreeExchange").exclude(currency__in=settings.CURRENCIES).delete() + Rate.objects.filter(backend="InvenTreeExchange").exclude(currency__in=currency_codes()).delete() def send_email(subject, body, recipients, from_email=None): diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index b7e5b98c1b..44f907e21a 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -22,6 +22,7 @@ from decimal import Decimal import InvenTree.tasks from stock.models import StockLocation +from common.settings import currency_codes class ValidatorTest(TestCase): @@ -337,13 +338,11 @@ class CurrencyTests(TestCase): with self.assertRaises(MissingRate): convert_money(Money(100, 'AUD'), 'USD') - currencies = settings.CURRENCIES - InvenTree.tasks.update_exchange_rates() rates = Rate.objects.all() - self.assertEqual(rates.count(), len(currencies)) + self.assertEqual(rates.count(), len(currency_codes())) # Now that we have some exchange rate information, we can perform conversions diff --git a/InvenTree/InvenTree/views.py b/InvenTree/InvenTree/views.py index 9a5e7176a1..9ce9e91ee9 100644 --- a/InvenTree/InvenTree/views.py +++ b/InvenTree/InvenTree/views.py @@ -21,7 +21,7 @@ from django.views.generic import ListView, DetailView, CreateView, FormView, Del from django.views.generic.base import RedirectView, TemplateView from djmoney.contrib.exchange.models import ExchangeBackend, Rate -from common.settings import currency_code_default +from common.settings import currency_code_default, currency_codes from part.models import Part, PartCategory from stock.models import StockLocation, StockItem @@ -822,7 +822,7 @@ class CurrencySettingsView(TemplateView): ctx['settings'] = InvenTreeSetting.objects.all().order_by('key') ctx["base_currency"] = currency_code_default() - ctx["currencies"] = settings.CURRENCIES + ctx["currencies"] = currency_codes ctx["rates"] = Rate.objects.filter(backend="InvenTreeExchange") diff --git a/InvenTree/common/settings.py b/InvenTree/common/settings.py index 4d3b0c7940..de543c2620 100644 --- a/InvenTree/common/settings.py +++ b/InvenTree/common/settings.py @@ -31,6 +31,13 @@ def currency_code_mappings(): return [(a, a) for a in settings.CURRENCIES] +def currency_codes(): + """ + Returns the current currency codes + """ + return [a for a in settings.CURRENCIES] + + def stock_expiry_enabled(): """ From 14c904c0c5cb3b0358b90f4e65e3335fb9b681f1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 10:45:33 +0200 Subject: [PATCH 221/445] style fixes --- InvenTree/InvenTree/exchange.py | 1 - InvenTree/InvenTree/tasks.py | 1 - InvenTree/InvenTree/tests.py | 2 -- InvenTree/InvenTree/views.py | 1 - InvenTree/common/settings.py | 1 - 5 files changed, 6 deletions(-) diff --git a/InvenTree/InvenTree/exchange.py b/InvenTree/InvenTree/exchange.py index 149ef6b794..c75a827cc7 100644 --- a/InvenTree/InvenTree/exchange.py +++ b/InvenTree/InvenTree/exchange.py @@ -1,4 +1,3 @@ -from django.conf import settings as inventree_settings from common.settings import currency_code_default, currency_codes from djmoney.contrib.exchange.backends.base import SimpleExchangeBackend diff --git a/InvenTree/InvenTree/tasks.py b/InvenTree/InvenTree/tasks.py index b01b362760..cab87ee64b 100644 --- a/InvenTree/InvenTree/tasks.py +++ b/InvenTree/InvenTree/tasks.py @@ -170,7 +170,6 @@ def update_exchange_rates(): try: from InvenTree.exchange import InvenTreeExchange from djmoney.contrib.exchange.models import ExchangeBackend, Rate - from django.conf import settings from common.settings import currency_code_default, currency_codes except AppRegistryNotReady: # Apps not yet loaded! diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index 44f907e21a..150662cb8e 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -5,8 +5,6 @@ from django.test import TestCase import django.core.exceptions as django_exceptions from django.core.exceptions import ValidationError -from django.conf import settings - from djmoney.money import Money from djmoney.contrib.exchange.models import Rate, convert_money from djmoney.contrib.exchange.exceptions import MissingRate diff --git a/InvenTree/InvenTree/views.py b/InvenTree/InvenTree/views.py index 9ce9e91ee9..4b559642ca 100644 --- a/InvenTree/InvenTree/views.py +++ b/InvenTree/InvenTree/views.py @@ -12,7 +12,6 @@ from django.utils.translation import gettext_lazy as _ from django.template.loader import render_to_string from django.http import HttpResponse, JsonResponse, HttpResponseRedirect from django.urls import reverse_lazy -from django.conf import settings from django.contrib.auth.mixins import PermissionRequiredMixin diff --git a/InvenTree/common/settings.py b/InvenTree/common/settings.py index de543c2620..e255ed0904 100644 --- a/InvenTree/common/settings.py +++ b/InvenTree/common/settings.py @@ -38,7 +38,6 @@ def currency_codes(): return [a for a in settings.CURRENCIES] - def stock_expiry_enabled(): """ Returns True if the stock expiry feature is enabled From e0f8310ca8ee17cc8a942fc6a14f4d5217ba6b9d Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 1 Jul 2021 21:57:07 +1000 Subject: [PATCH 222/445] Adds the ability to "clear" a non-required field with an obvious button --- InvenTree/templates/js/forms.js | 103 ++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 18 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 76f0dba2dd..a4a1d8e502 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -423,6 +423,9 @@ function constructFormBody(fields, options) { // Attach edit callbacks (if required) addFieldCallbacks(fields, options); + // Attach clear callbacks (if required) + addClearCallbacks(fields, options); + attachToggle(modal); $(modal + ' .select2-container').addClass('select-full-width'); @@ -571,22 +574,31 @@ function updateFieldValues(fields, options) { if (value == null) { continue; } - var el = $(options.modal).find(`#id_${name}`); + updateFieldValue(name, value, field, options); + } +} - switch (field.type) { - case 'boolean': - el.prop('checked', value); - break; - case 'related field': - // TODO? - break; - case 'file upload': - case 'image upload': - break; - default: - el.val(value); - break; - } + +function updateFieldValue(name, value, field, options) { + var el = $(options.modal).find(`#id_${name}`); + + switch (field.type) { + case 'boolean': + el.prop('checked', value); + break; + case 'related field': + // Clear? + if (value == null && !field.required) { + el.val(null).trigger('change'); + } + // TODO - Specify an actual value! + break; + case 'file upload': + case 'image upload': + break; + default: + el.val(value); + break; } } @@ -777,6 +789,29 @@ function addFieldCallback(name, field, options) { } +function addClearCallbacks(fields, options) { + + for (var idx = 0; idx < options.field_names.length; idx++) { + + var name = options.field_names[idx]; + + var field = fields[name]; + + if (!field || field.required) continue; + + addClearCallback(name, field, options); + } +} + + +function addClearCallback(name, field, options) { + + $(options.modal).find(`#clear_${name}`).click(function() { + updateFieldValue(name, null, field, options); + }); +} + + function initializeRelatedFields(fields, options) { var field_names = options.field_names; @@ -1114,14 +1149,46 @@ function constructField(name, parameters, options) { html += constructLabel(name, parameters); html += `
          `; + + // Does this input deserve "extra" decorators? + var extra = parameters.prefix != null; - if (parameters.prefix) { - html += `
          ${parameters.prefix}`; + // Some fields can have 'clear' inputs associated with them + if (!parameters.required) { + switch (parameters.type) { + case 'string': + case 'url': + case 'email': + case 'integer': + case 'float': + case 'decimal': + case 'related field': + extra = true; + break; + default: + break; + } + } + + if (extra) { + html += `
          `; + + if (parameters.prefix) { + html += `${parameters.prefix}`; + } } html += constructInput(name, parameters, options); - if (parameters.prefix) { + if (extra) { + + if (!parameters.required) { + html += ` + + + `; + } + html += `
          `; // input-group } From a771d7732bd696642af8199de65527e7411b3c0f Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 1 Jul 2021 21:58:05 +1000 Subject: [PATCH 223/445] Icon tweak --- InvenTree/templates/js/forms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index a4a1d8e502..d372b10db2 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -1185,7 +1185,7 @@ function constructField(name, parameters, options) { if (!parameters.required) { html += ` - + `; } From 5aaced6e66bfb8317f691e7fafe655da1070100f Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 1 Jul 2021 18:20:39 +0200 Subject: [PATCH 224/445] migration for file-based currency setting --- .../0010_migrate_currency_setting.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 InvenTree/common/migrations/0010_migrate_currency_setting.py diff --git a/InvenTree/common/migrations/0010_migrate_currency_setting.py b/InvenTree/common/migrations/0010_migrate_currency_setting.py new file mode 100644 index 0000000000..23076ff200 --- /dev/null +++ b/InvenTree/common/migrations/0010_migrate_currency_setting.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.4 on 2021-07-01 15:39 + +from django.db import migrations +from common.models import InvenTreeSetting +from InvenTree.settings import get_setting, CONFIG + +def set_default_currency(apps, schema_editor): + """ migrate the currency setting from config.yml to db """ + # get value from settings-file + base_currency = get_setting('INVENTREE_BASE_CURRENCY', CONFIG.get('base_currency', 'USD')) + # write to database + InvenTreeSetting.set_setting('INVENTREE_DEFAULT_CURRENCY', base_currency, None, create=True) + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0009_delete_currency'), + ] + + operations = [ + migrations.RunPython(set_default_currency), + ] From 2f1dea11239af41c838944bb0bac484e2d6d033b Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 2 Jul 2021 10:52:56 +1000 Subject: [PATCH 225/445] Modals can now be created programatically - INFINITE MODALS - API forms now create a new modal as required --- InvenTree/templates/js/forms.js | 8 ++++- InvenTree/templates/js/modals.js | 53 ++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index d372b10db2..5bee4f57a6 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -237,6 +237,11 @@ function constructForm(url, options) { // Default HTTP method options.method = options.method || 'PATCH'; + // Create a new modal if one does not exists + if (!options.modal) { + options.modal = createNewModal(); + } + // Request OPTIONS endpoint from the API getApiEndpointOptions(url, function(OPTIONS) { @@ -413,6 +418,7 @@ function constructFormBody(fields, options) { insertConfirmButton(options); } + // Display the modal $(modal).modal('show'); updateFieldValues(fields, options); @@ -433,7 +439,6 @@ function constructFormBody(fields, options) { modalShowSubmitButton(modal, true); - $(modal).off('click', '#modal-form-submit'); $(modal).on('click', '#modal-form-submit', function() { submitFormData(fields, options); @@ -1163,6 +1168,7 @@ function constructField(name, parameters, options) { case 'float': case 'decimal': case 'related field': + case 'date': extra = true; break; default: diff --git a/InvenTree/templates/js/modals.js b/InvenTree/templates/js/modals.js index 75e0f3672a..ddce2fe109 100644 --- a/InvenTree/templates/js/modals.js +++ b/InvenTree/templates/js/modals.js @@ -1,5 +1,58 @@ {% load i18n %} + +/* + * Create and display a new modal dialog + */ +function createNewModal(options={}) { + + var id = options.id || 0; + + // Always increment the ID of the modal + id += 1; + + var html = ` + + `; + + $('body').append(html); + + var modal_name = `#modal-form-${id}`; + + // Automatically remove the modal when it is deleted! + $(modal_name).on('hidden.bs.modal', function(e) { + $(modal_name).remove(); + }); + + // Return the "name" of the modal + return modal_name; +} + + function makeOption(text, value, title) { /* Format an option for a select element */ From 3ff19f8c752724cdf6876e05ce3f37696aa25f1b Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 2 Jul 2021 11:06:52 +1000 Subject: [PATCH 226/445] Refactorin' --- InvenTree/templates/js/forms.js | 19 ++++++------------- InvenTree/templates/js/modals.js | 7 ++++++- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 5bee4f57a6..3f0ae6fffb 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -237,11 +237,6 @@ function constructForm(url, options) { // Default HTTP method options.method = options.method || 'PATCH'; - // Create a new modal if one does not exists - if (!options.modal) { - options.modal = createNewModal(); - } - // Request OPTIONS endpoint from the API getApiEndpointOptions(url, function(OPTIONS) { @@ -396,17 +391,15 @@ function constructFormBody(fields, options) { // TODO: Dynamically create the modals, // so that we can have an infinite number of stacks! - options.modal = options.modal || '#modal-form'; - + // Create a new modal if one does not exists + if (!options.modal) { + options.modal = createNewModal(options); + } + var modal = options.modal; modalEnable(modal, true); - - // Set the form title and button labels - modalSetTitle(modal, options.title || '{% trans "Form Title" %}'); - modalSetSubmitText(modal, options.submitText || '{% trans "Submit" %}'); - modalSetCloseText(modal, options.cancelText || '{% trans "Cancel" %}'); - + // Insert generated form content $(modal).find('.modal-form-content').html(html); diff --git a/InvenTree/templates/js/modals.js b/InvenTree/templates/js/modals.js index ddce2fe109..180f3bed95 100644 --- a/InvenTree/templates/js/modals.js +++ b/InvenTree/templates/js/modals.js @@ -31,7 +31,7 @@ function createNewModal(options={}) {
          @@ -48,6 +48,11 @@ function createNewModal(options={}) { $(modal_name).remove(); }); + // Set labels based on supplied options + modalSetTitle(modal_name, options.title || '{% trans "Form Title" %}'); + modalSetSubmitText(modal_name, options.submitText || '{% trans "Submit" %}'); + modalSetCloseText(modal_name, options.cancelText || '{% trans "Cancel" %}'); + // Return the "name" of the modal return modal_name; } From 00e921f505f48357504c9c79bb48cefd787c2123 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 2 Jul 2021 11:13:24 +1000 Subject: [PATCH 227/445] More work on dynamic modal template --- InvenTree/templates/js/forms.js | 4 +--- InvenTree/templates/js/modals.js | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 3f0ae6fffb..cb505c2a11 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -304,8 +304,6 @@ function constructFormBody(fields, options) { var html = ''; - html += `
          `; - // Client must provide set of fields to be displayed, // otherwise *all* fields will be displayed var displayed_fields = options.fields || fields; @@ -684,7 +682,7 @@ function clearFormErrors(options) { // Remove the "has error" class $(options.modal).find('.has-error').removeClass('has-error'); - // Clear the 'non field errors' + // Hide the 'non field errors' $(options.modal).find('#non-field-errors').html(''); } diff --git a/InvenTree/templates/js/modals.js b/InvenTree/templates/js/modals.js index 180f3bed95..319158eaa0 100644 --- a/InvenTree/templates/js/modals.js +++ b/InvenTree/templates/js/modals.js @@ -19,18 +19,28 @@ function createNewModal(options={}) { - + +
          @@ -240,23 +268,35 @@ {% block post_content_panel %} -
          -
          -

          - {% trans "Part Parameters" %} -

          -
          -
          -
          -
          - {% if roles.part.add %} - - {% endif %} +
          +
          +
          +
          +

          {% trans "Parameters" %}

          +
          +
          +
          +
          + {% if roles.part.add %} + + {% endif %} +
          +
          +
          +
          +
          +
          +
          +
          +
          +

          {% trans "Attachments" %}

          +
          +
          + {% include "attachment_table.html" %}
          -
          @@ -269,6 +309,18 @@ {% block js_ready %} {{ block.super }} + $('#edit-notes').click(function() { + constructForm('{% url "api-part-detail" part.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Part Notes" %}', + reload: true, + }); + }); + $(".slidey").change(function() { var field = $(this).attr('fieldname'); @@ -337,4 +389,68 @@ }); }); + loadAttachmentTable( + '{% url "api-part-attachment-list" %}', + { + filters: { + part: {{ part.pk }}, + }, + onEdit: function(pk) { + var url = `/api/part/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + title: '{% trans "Edit Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + }, + onDelete: function(pk) { + var url = `/api/part/attachment/${pk}/`; + + constructForm(url, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } + ); + + enableDragAndDrop( + '#attachment-dropzone', + '{% url "api-part-attachment-list" %}', + { + data: { + part: {{ part.id }}, + }, + label: 'attachment', + success: function(data, status, xhr) { + reloadAttachmentTable(); + } + } + ); + + $("#new-attachment").click(function() { + + constructForm( + '{% url "api-part-attachment-list" %}', + { + method: 'POST', + fields: { + attachment: {}, + comment: {}, + part: { + value: {{ part.pk }}, + hidden: true, + } + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Add Attachment" %}', + } + ) + }); + {% endblock %} diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index b71551747c..6dd7dbd968 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -353,12 +353,16 @@ function constructFormBody(fields, options) { // Override existing query filters (if provided!) fields[field].filters = Object.assign(fields[field].filters || {}, field_options.filters); + // TODO: Refactor the following code with Object.assign (see above) + // Secondary modal options fields[field].secondary = field_options.secondary; // Edit callback fields[field].onEdit = field_options.onEdit; + fields[field].multiline = field_options.multiline; + // Custom help_text if (field_options.help_text) { fields[field].help_text = field_options.help_text; @@ -1483,7 +1487,11 @@ function constructInputOptions(name, classes, type, parameters) { opts.push(`placeholder='${parameters.placeholder}'`); } - return ``; + if (parameters.multiline) { + return ``; + } else { + return ``; + } } From b1af07c8cb717f85a6353d379bd25e1cc99a4c0c Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jul 2021 23:31:10 +1000 Subject: [PATCH 379/445] Remove stale pages --- .../part/templates/part/attachments.html | 86 ------------------- InvenTree/part/templates/part/navbar.html | 12 --- InvenTree/part/templates/part/notes.html | 57 ------------ InvenTree/part/urls.py | 2 - InvenTree/part/views.py | 34 -------- 5 files changed, 191 deletions(-) delete mode 100644 InvenTree/part/templates/part/attachments.html delete mode 100644 InvenTree/part/templates/part/notes.html diff --git a/InvenTree/part/templates/part/attachments.html b/InvenTree/part/templates/part/attachments.html deleted file mode 100644 index 7128980472..0000000000 --- a/InvenTree/part/templates/part/attachments.html +++ /dev/null @@ -1,86 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='attachments' %} -{% endblock %} - -{% block heading %} -{% trans "Part Attachments" %} -{% endblock %} - -{% block details %} - -{% include "attachment_table.html" with attachments=part.part_attachments %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - loadAttachmentTable( - '{% url "api-part-attachment-list" %}', - { - filters: { - part: {{ part.pk }}, - }, - onEdit: function(pk) { - var url = `/api/part/attachment/${pk}/`; - - constructForm(url, { - fields: { - comment: {}, - }, - title: '{% trans "Edit Attachment" %}', - onSuccess: reloadAttachmentTable, - }); - }, - onDelete: function(pk) { - var url = `/api/part/attachment/${pk}/`; - - constructForm(url, { - method: 'DELETE', - confirmMessage: '{% trans "Confirm Delete Operation" %}', - title: '{% trans "Delete Attachment" %}', - onSuccess: reloadAttachmentTable, - }); - } - } - ); - - enableDragAndDrop( - '#attachment-dropzone', - '{% url "api-part-attachment-list" %}', - { - data: { - part: {{ part.id }}, - }, - label: 'attachment', - success: function(data, status, xhr) { - reloadAttachmentTable(); - } - } - ); - - $("#new-attachment").click(function() { - - constructForm( - '{% url "api-part-attachment-list" %}', - { - method: 'POST', - fields: { - attachment: {}, - comment: {}, - part: { - value: {{ part.pk }}, - hidden: true, - } - }, - onSuccess: reloadAttachmentTable, - title: '{% trans "Add Attachment" %}', - } - ) - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/navbar.html b/InvenTree/part/templates/part/navbar.html index afe4fee374..e8617dc677 100644 --- a/InvenTree/part/templates/part/navbar.html +++ b/InvenTree/part/templates/part/navbar.html @@ -109,16 +109,4 @@ {% endif %} -
        • - - - {% trans "Attachments" %} - -
        • -
        • - - - {% trans "Notes" %} - -
        • diff --git a/InvenTree/part/templates/part/notes.html b/InvenTree/part/templates/part/notes.html deleted file mode 100644 index 63e0190d48..0000000000 --- a/InvenTree/part/templates/part/notes.html +++ /dev/null @@ -1,57 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load crispy_forms_tags %} -{% load i18n %} -{% load markdownify %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='notes' %} -{% endblock %} - -{% block heading %} -{% trans "Part Notes" %} -{% if roles.part.change and not editing %} - -{% endif %} -{% endblock %} - -{% block details %} - -{% if editing %} -
          - {% csrf_token %} - - {{ form }} -
          - - - -
          - -{{ form.media }} - -{% else %} - -
          - {% if part.notes %} -
          - {{ part.notes | markdownify }} -
          - {% endif %} -
          - -{% endif %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -{% if editing %} -{% else %} -$("#edit-notes").click(function() { - location.href = "{% url 'part-notes' part.id %}?edit=1"; -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 8843a839a1..1fa7227f5e 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -61,8 +61,6 @@ part_detail_urls = [ url(r'^tests/', views.PartDetail.as_view(template_name='part/part_tests.html'), name='part-test-templates'), url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), url(r'^related-parts/?', views.PartDetail.as_view(template_name='part/related.html'), name='part-related'), - url(r'^attachments/?', views.PartDetail.as_view(template_name='part/attachments.html'), name='part-attachments'), - url(r'^notes/?', views.PartNotes.as_view(), name='part-notes'), url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 561b9be0fb..dcf40bd186 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -747,40 +747,6 @@ class PartImportAjax(FileManagementAjaxView, PartImport): return PartImport.validate(self, self.steps.current, form, **kwargs) -class PartNotes(UpdateView): - """ View for editing the 'notes' field of a Part object. - Presents a live markdown editor. - """ - - context_object_name = 'part' - # form_class = part_forms.EditNotesForm - template_name = 'part/notes.html' - model = Part - - role_required = 'part.change' - - fields = ['notes'] - - def get_success_url(self): - """ Return the success URL for this form """ - - return reverse('part-notes', kwargs={'pk': self.get_object().id}) - - def get_context_data(self, **kwargs): - - part = self.get_object() - - context = super().get_context_data(**kwargs) - - context['editing'] = str2bool(self.request.GET.get('edit', '')) - - ctx = part.get_context_data(self.request) - - context.update(ctx) - - return context - - class PartDetail(InvenTreeRoleMixin, DetailView): """ Detail view for Part object """ From cf23fb6fe8a6cbb3a2523443f8e2620971bb0485 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 12 Jul 2021 23:32:08 +1000 Subject: [PATCH 380/445] PEP fixes --- InvenTree/part/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index dcf40bd186..4acf5fcdb6 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -13,7 +13,7 @@ from django.shortcuts import get_object_or_404 from django.shortcuts import HttpResponseRedirect from django.utils.translation import gettext_lazy as _ from django.urls import reverse, reverse_lazy -from django.views.generic import DetailView, ListView, UpdateView +from django.views.generic import DetailView, ListView from django.forms.models import model_to_dict from django.forms import HiddenInput, CheckboxInput from django.conf import settings From a0b3359d62a6d685c4052e599f6be371b84663e2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 13 Jul 2021 19:58:47 +1000 Subject: [PATCH 381/445] Fix filtering for build orders --- InvenTree/build/api.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/InvenTree/build/api.py b/InvenTree/build/api.py index 069b6e58fe..47edb55545 100644 --- a/InvenTree/build/api.py +++ b/InvenTree/build/api.py @@ -68,10 +68,6 @@ class BuildList(generics.ListCreateAPIView): filters.OrderingFilter, ] - filter_fields = [ - 'sales_order', - ] - ordering_fields = [ 'reference', 'part__name', @@ -114,6 +110,12 @@ class BuildList(generics.ListCreateAPIView): if parent is not None: queryset = queryset.filter(parent=parent) + # Filter by sales_order + sales_order = params.get('sales_order', None) + + if sales_order is not None: + queryset = queryset.filter(sales_order=sales_order) + # Filter by "ancestor" builds ancestor = params.get('ancestor', None) From 39c58e40154eed53687bf5ba045ef92a24ffdd57 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 13 Jul 2021 19:59:11 +1000 Subject: [PATCH 382/445] Move all "SalesOrder" content onto a single page --- .../templates/order/sales_order_detail.html | 152 ++++++++++++++++-- InvenTree/templates/two_column.html | 4 + 2 files changed, 139 insertions(+), 17 deletions(-) diff --git a/InvenTree/order/templates/order/sales_order_detail.html b/InvenTree/order/templates/order/sales_order_detail.html index 4af0e219d6..9da0c88c82 100644 --- a/InvenTree/order/templates/order/sales_order_detail.html +++ b/InvenTree/order/templates/order/sales_order_detail.html @@ -4,38 +4,156 @@ {% load status_codes %} {% load i18n %} {% load static %} +{% load markdownify %} {% block menubar %} {% include "order/so_navbar.html" with tab='details' %} {% endblock %} -{% block heading %} -{% trans "Sales Order Items" %} -{% endblock %} +{% block page_content %} -{% block details %} - - -{% if roles.sales_order.change %} -
          - +
          +
          +

          {% trans "Sales Order Items" %}

          +
          +
          + {% if roles.sales_order.change %} +
          + +
          + {% endif %} + +
          +
          -{% endif %} - +
          +
          +

          {% trans "Build Orders" %}

          +
          +
          +
          +
          +
          - +
          +
          +

          {% trans "Attachments" %}

          +
          +
          + {% include "attachment_table.html" %} +
          +
          + +
          +
          +
          +
          +

          {% trans "Notes" %}

          +
          +
          +
          + +
          +
          +
          +
          +
          + {{ order.notes | markdownify }} +
          +
          {% endblock %} {% block js_ready %} {{ block.super }} -function reloadTable() { - $("#so-lines-table").bootstrapTable("refresh"); -} + $('#edit-notes').click(function() { + constructForm('{% url "api-so-detail" order.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Notes" %}', + reload: true, + }); + }); + + enableDragAndDrop( + '#attachment-dropzone', + '{% url "api-so-attachment-list" %}', + { + data: { + order: {{ order.id }}, + }, + label: 'attachment', + success: function(data, status, xhr) { + location.reload(); + } + } + ); + + loadAttachmentTable( + '{% url "api-so-attachment-list" %}', + { + filters: { + order: {{ order.pk }}, + }, + onEdit: function(pk) { + var url = `/api/order/so/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Edit Attachment" %}', + }); + }, + onDelete: function(pk) { + constructForm(`/api/order/so/attachment/${pk}/`, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } + ); + + $("#new-attachment").click(function() { + + constructForm('{% url "api-so-attachment-list" %}', { + method: 'POST', + fields: { + attachment: {}, + comment: {}, + order: { + value: {{ order.pk }}, + hidden: true + } + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Add Attachment" %}' + }); + }); + + loadBuildTable($("#builds-table"), { + url: "{% url 'api-build-list' %}", + params: { + sales_order: {{ order.id }}, + }, + }); + + function reloadTable() { + $("#so-lines-table").bootstrapTable("refresh"); + } $("#new-so-line").click(function() { diff --git a/InvenTree/templates/two_column.html b/InvenTree/templates/two_column.html index c942bef1fa..bcc85c7269 100644 --- a/InvenTree/templates/two_column.html +++ b/InvenTree/templates/two_column.html @@ -43,6 +43,8 @@
          {% endblock %} +{% block page_content %} + {% block pre_content_panels %} {% endblock %} @@ -71,6 +73,8 @@ {% endblock %} +{% endblock %} + {% block js_ready %} {{ block.super }} From 970f08260cc3dc05c41dfe0eddc32c2cfe3300c7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 13 Jul 2021 20:04:02 +1000 Subject: [PATCH 383/445] Update navbar --- .../order/templates/order/so_navbar.html | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/InvenTree/order/templates/order/so_navbar.html b/InvenTree/order/templates/order/so_navbar.html index 4623febd02..b3b0ac30f5 100644 --- a/InvenTree/order/templates/order/so_navbar.html +++ b/InvenTree/order/templates/order/so_navbar.html @@ -9,29 +9,29 @@ -
        • - - - {% trans "Details" %} +
        • + + + {% trans "Order Items" %}
        • -
        • - +
        • + {% trans "Build Orders" %}
        • -
        • - +
        • + {% trans "Attachments" %}
        • -
        • - +
        • + {% trans "Notes" %} From 9889e314a9e6c386f08987d9788527820472af18 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 13 Jul 2021 20:04:12 +1000 Subject: [PATCH 384/445] Remove unused templates --- .../templates/order/sales_order_notes.html | 56 ------------- .../order/templates/order/so_attachments.html | 83 ------------------- .../order/templates/order/so_builds.html | 33 -------- InvenTree/order/urls.py | 4 - InvenTree/order/views.py | 22 ----- 5 files changed, 198 deletions(-) delete mode 100644 InvenTree/order/templates/order/sales_order_notes.html delete mode 100644 InvenTree/order/templates/order/so_attachments.html delete mode 100644 InvenTree/order/templates/order/so_builds.html diff --git a/InvenTree/order/templates/order/sales_order_notes.html b/InvenTree/order/templates/order/sales_order_notes.html deleted file mode 100644 index 0a2e105b2e..0000000000 --- a/InvenTree/order/templates/order/sales_order_notes.html +++ /dev/null @@ -1,56 +0,0 @@ -{% extends "order/sales_order_base.html" %} - -{% load inventree_extras %} -{% load i18n %} -{% load static %} -{% load markdownify %} -{% load status_codes %} - -{% block menubar %} -{% include 'order/so_navbar.html' with tab='notes' %} -{% endblock %} - -{% block heading %} -{% trans "Sales Order Notes" %} -{% if roles.sales_order.change and not editing %} - -{% endif %} -{% endblock %} - -{% block details %} - -{% if editing %} - -
          - {% csrf_token %} - - {{ form }} -
          - -
          - -{{ form.media }} - -{% else %} -
          -
          - {{ order.notes | markdownify }} -
          -
          - -{% endif %} - -{% endblock %} - -{% block js_ready %} - -{{ block.super }} - -{% if editing %} -{% else %} -$("#edit-notes").click(function() { - location.href = "{% url 'so-notes' order.id %}?edit=1"; -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/so_attachments.html b/InvenTree/order/templates/order/so_attachments.html deleted file mode 100644 index 9c29fe5abe..0000000000 --- a/InvenTree/order/templates/order/so_attachments.html +++ /dev/null @@ -1,83 +0,0 @@ -{% extends "order/sales_order_base.html" %} - -{% load inventree_extras %} -{% load i18n %} -{% load static %} - -{% block menubar %} -{% include 'order/so_navbar.html' with tab='attachments' %} -{% endblock %} - -{% block heading %} -{% trans "Sales Order Attachments" %} -{% endblock %} - -{% block details %} - -{% include "attachment_table.html" with attachments=order.attachments.all %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -enableDragAndDrop( - '#attachment-dropzone', - '{% url "api-so-attachment-list" %}', - { - data: { - order: {{ order.id }}, - }, - label: 'attachment', - success: function(data, status, xhr) { - location.reload(); - } - } -); - -loadAttachmentTable( - '{% url "api-so-attachment-list" %}', - { - filters: { - order: {{ order.pk }}, - }, - onEdit: function(pk) { - var url = `/api/order/so/attachment/${pk}/`; - - constructForm(url, { - fields: { - comment: {}, - }, - onSuccess: reloadAttachmentTable, - title: '{% trans "Edit Attachment" %}', - }); - }, - onDelete: function(pk) { - constructForm(`/api/order/so/attachment/${pk}/`, { - method: 'DELETE', - confirmMessage: '{% trans "Confirm Delete Operation" %}', - title: '{% trans "Delete Attachment" %}', - onSuccess: reloadAttachmentTable, - }); - } - } -); - -$("#new-attachment").click(function() { - - constructForm('{% url "api-so-attachment-list" %}', { - method: 'POST', - fields: { - attachment: {}, - comment: {}, - order: { - value: {{ order.pk }}, - hidden: true - } - }, - onSuccess: reloadAttachmentTable, - title: '{% trans "Add Attachment" %}' - }); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/so_builds.html b/InvenTree/order/templates/order/so_builds.html deleted file mode 100644 index e29a76b64d..0000000000 --- a/InvenTree/order/templates/order/so_builds.html +++ /dev/null @@ -1,33 +0,0 @@ -{% extends "order/sales_order_base.html" %} - -{% load inventree_extras %} -{% load i18n %} -{% load static %} - -{% block menubar %} -{% include 'order/so_navbar.html' with tab='builds' %} -{% endblock %} - -{% block heading %} -{% trans "Build Orders" %} -{% endblock %} - -{% block details %} - - -
          - -{% endblock %} - -{% block js_ready %} - -{{ block.super }} - -loadBuildTable($("#builds-table"), { - url: "{% url 'api-build-list' %}", - params: { - sales_order: {{ order.id }}, - }, -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/urls.py b/InvenTree/order/urls.py index 16be6e77ce..768607a93b 100644 --- a/InvenTree/order/urls.py +++ b/InvenTree/order/urls.py @@ -42,10 +42,6 @@ sales_order_detail_urls = [ url(r'^cancel/', views.SalesOrderCancel.as_view(), name='so-cancel'), url(r'^ship/', views.SalesOrderShip.as_view(), name='so-ship'), - url(r'^builds/', views.SalesOrderDetail.as_view(template_name='order/so_builds.html'), name='so-builds'), - url(r'^attachments/', views.SalesOrderDetail.as_view(template_name='order/so_attachments.html'), name='so-attachments'), - url(r'^notes/', views.SalesOrderNotes.as_view(), name='so-notes'), - url(r'^.*$', views.SalesOrderDetail.as_view(), name='so-detail'), ] diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 2ec06e600e..7267df1094 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -122,28 +122,6 @@ class PurchaseOrderNotes(InvenTreeRoleMixin, UpdateView): return ctx -class SalesOrderNotes(InvenTreeRoleMixin, UpdateView): - """ View for editing the 'notes' field of a SalesORder """ - - context_object_name = 'order' - template_name = 'order/sales_order_notes.html' - model = SalesOrder - role_required = 'sales_order.view' - - fields = ['notes'] - - def get_success_url(self): - return reverse('so-notes', kwargs={'pk': self.get_object().pk}) - - def get_context_data(self, **kwargs): - - ctx = super().get_context_data(**kwargs) - - ctx['editing'] = str2bool(self.request.GET.get('edit', False)) - - return ctx - - class PurchaseOrderCancel(AjaxUpdateView): """ View for cancelling a purchase order """ From 65de52b705fe31ed7d9bc45425663eb1bf225827 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 13 Jul 2021 20:58:05 +1000 Subject: [PATCH 385/445] Add javascript to dynamically switch between views --- InvenTree/InvenTree/static/css/inventree.css | 4 ++ InvenTree/InvenTree/urls.py | 11 ++-- .../templates/order/sales_order_detail.html | 13 ++-- .../order/templates/order/so_navbar.html | 16 ++--- InvenTree/templates/base.html | 17 +++--- InvenTree/templates/js/nav.js | 60 +++++++++++++++++++ 6 files changed, 96 insertions(+), 25 deletions(-) create mode 100644 InvenTree/templates/js/nav.js diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index ac7cf1f4e1..1f01037f28 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -912,6 +912,10 @@ input[type="submit"] { box-shadow: 1px 1px #DDD; } +.panel-hidden { + display: none; +} + .float-right { float: right; } diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index f3ea86e8cc..a3af143f92 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -104,22 +104,23 @@ settings_urls = [ dynamic_javascript_urls = [ url(r'^api.js', DynamicJsView.as_view(template_name='js/api.js'), name='api.js'), url(r'^attachment.js', DynamicJsView.as_view(template_name='js/attachment.js'), name='attachment.js'), - url(r'^forms.js', DynamicJsView.as_view(template_name='js/forms.js'), name='forms.js'), - url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/model_renderers.js'), name='model_renderers.js'), - url(r'^modals.js', DynamicJsView.as_view(template_name='js/modals.js'), name='modals.js'), url(r'^barcode.js', DynamicJsView.as_view(template_name='js/barcode.js'), name='barcode.js'), url(r'^bom.js', DynamicJsView.as_view(template_name='js/bom.js'), name='bom.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'), + url(r'^filters.js', DynamicJsView.as_view(template_name='js/filters.js'), name='filters.js'), + url(r'^forms.js', DynamicJsView.as_view(template_name='js/forms.js'), name='forms.js'), + url(r'^label.js', DynamicJsView.as_view(template_name='js/label.js'), name='label.js'), + url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/model_renderers.js'), name='model_renderers.js'), + url(r'^modals.js', DynamicJsView.as_view(template_name='js/modals.js'), name='modals.js'), + url(r'^nav.js', DynamicJsView.as_view(template_name='js/nav.js'), name='nav.js'), url(r'^order.js', DynamicJsView.as_view(template_name='js/order.js'), name='order.js'), url(r'^part.js', DynamicJsView.as_view(template_name='js/part.js'), name='part.js'), - url(r'^label.js', DynamicJsView.as_view(template_name='js/label.js'), name='label.js'), url(r'^report.js', DynamicJsView.as_view(template_name='js/report.js'), name='report.js'), url(r'^stock.js', DynamicJsView.as_view(template_name='js/stock.js'), name='stock.js'), url(r'^tables.js', DynamicJsView.as_view(template_name='js/tables.js'), name='tables.js'), url(r'^table_filters.js', DynamicJsView.as_view(template_name='js/table_filters.js'), name='table_filters.js'), - url(r'^filters.js', DynamicJsView.as_view(template_name='js/filters.js'), name='filters.js'), ] urlpatterns = [ diff --git a/InvenTree/order/templates/order/sales_order_detail.html b/InvenTree/order/templates/order/sales_order_detail.html index 9da0c88c82..8ba91ee0ab 100644 --- a/InvenTree/order/templates/order/sales_order_detail.html +++ b/InvenTree/order/templates/order/sales_order_detail.html @@ -12,7 +12,7 @@ {% block page_content %} -
          +

          {% trans "Sales Order Items" %}

          @@ -29,7 +29,7 @@
          -
          +

          {% trans "Build Orders" %}

          @@ -38,7 +38,7 @@
          -
          +

          {% trans "Attachments" %}

          @@ -47,7 +47,7 @@
          -
          +
          @@ -611,6 +611,11 @@ function setupCallbacks() { } ); }); + + attachNavCallbacks({ + name: 'sales-order', + default: 'order-items' + }); } {% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/so_navbar.html b/InvenTree/order/templates/order/so_navbar.html index b3b0ac30f5..d7571ab691 100644 --- a/InvenTree/order/templates/order/so_navbar.html +++ b/InvenTree/order/templates/order/so_navbar.html @@ -9,29 +9,29 @@
        • -
        • - +
        • -
        • - +
        • -
        • - +
        • -
        • - +
        • -
        • - - - {% trans "Details" %} +
        • + + + {% trans "Order Items" %}
        • {% if order.status == PurchaseOrderStatus.PENDING and roles.purchase_order.change %} -
        • +
        • {% trans "Upload File" %}
        • {% endif %} -
        • - +
        • + {% trans "Received Items" %}
        • -
        • - +
        • + {% trans "Attachments" %}
        • -
        • - +
        • + {% trans "Notes" %} diff --git a/InvenTree/order/templates/order/po_received_items.html b/InvenTree/order/templates/order/po_received_items.html deleted file mode 100644 index 487dbd1284..0000000000 --- a/InvenTree/order/templates/order/po_received_items.html +++ /dev/null @@ -1,37 +0,0 @@ -{% extends "order/order_base.html" %} - -{% load inventree_extras %} -{% load i18n %} -{% load static %} - -{% block menubar %} -{% include 'order/po_navbar.html' with tab='received' %} -{% endblock %} - -{% block heading %} -{% trans "Received Items" %} -{% endblock %} - -{% block details %} - -{% include "stock_table.html" with read_only=True %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadStockTable($("#stock-table"), { - params: { - purchase_order: {{ order.id }}, - part_detail: true, - supplier_part_detail: true, - location_detail: true, - }, - buttons: [ - '#stock-options', - ], - filterkey: "postock" -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index 2e1ec0c39c..8832974510 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -4,31 +4,71 @@ {% load status_codes %} {% load i18n %} {% load static %} +{% load markdownify %} {% block menubar %} {% include 'order/po_navbar.html' with tab='details' %} {% endblock %} -{% block heading %} -{% trans "Purchase Order Items" %} -{% endblock %} +{% block page_content %} - -{% block details %} - - -
          - {% if order.status == PurchaseOrderStatus.PENDING and roles.purchase_order.change %} - - {% endif %} +
          +
          +

          {% trans "Purchase Order Items" %}

          +
          +
          +
          + {% if order.status == PurchaseOrderStatus.PENDING and roles.purchase_order.change %} + + {% endif %} +
          + + +
          +
          +
          +
          +

          {% trans "Received Items" %}

          +
          +
          + {% include "stock_table.html" with read_only=True %} +
          +
          - -
          +
          +
          +

          {% trans "Purchase Order Attachments" %}

          +
          +
          + {% include "attachment_table.html" %} +
          +
          + +
          +
          +
          +
          +

          {% trans "Order Notes" %}

          +
          +
          +
          + +
          +
          +
          +
          +
          + {{ order.notes | markdownify }} +
          +
          {% endblock %} @@ -36,6 +76,91 @@ {{ block.super }} + $('#edit-notes').click(function() { + constructForm('{% url "api-po-detail" order.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Notes" %}', + reload: true, + }); + }); + + enableDragAndDrop( + '#attachment-dropzone', + '{% url "api-po-attachment-list" %}', + { + data: { + order: {{ order.id }}, + }, + label: 'attachment', + success: function(data, status, xhr) { + location.reload(); + } + } + ); + + loadAttachmentTable( + '{% url "api-po-attachment-list" %}', + { + filters: { + order: {{ order.pk }}, + }, + onEdit: function(pk) { + var url = `/api/order/po/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Edit Attachment" %}', + }); + }, + onDelete: function(pk) { + + constructForm(`/api/order/po/attachment/${pk}/`, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } + ); + + $("#new-attachment").click(function() { + + constructForm('{% url "api-po-attachment-list" %}', { + method: 'POST', + fields: { + attachment: {}, + comment: {}, + order: { + value: {{ order.pk }}, + hidden: true, + }, + }, + reload: true, + title: '{% trans "Add Attachment" %}', + }); + }); + + loadStockTable($("#stock-table"), { + params: { + purchase_order: {{ order.id }}, + part_detail: true, + supplier_part_detail: true, + location_detail: true, + }, + buttons: [ + '#stock-options', + ], + filterkey: "postock" + }); + {% if order.status == PurchaseOrderStatus.PENDING %} $('#new-po-line').click(function() { @@ -301,4 +426,9 @@ $("#po-table").inventreeTable({ ] }); + attachNavCallbacks({ + name: 'purchase-order', + default: 'order-items' + }); + {% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/sales_order_detail.html b/InvenTree/order/templates/order/sales_order_detail.html index 8ba91ee0ab..a61f6a11ce 100644 --- a/InvenTree/order/templates/order/sales_order_detail.html +++ b/InvenTree/order/templates/order/sales_order_detail.html @@ -51,7 +51,7 @@
          -

          {% trans "Notes" %}

          +

          {% trans "Order Notes" %}

          diff --git a/InvenTree/order/templates/order/so_navbar.html b/InvenTree/order/templates/order/so_navbar.html index d7571ab691..710976ed3f 100644 --- a/InvenTree/order/templates/order/so_navbar.html +++ b/InvenTree/order/templates/order/so_navbar.html @@ -9,28 +9,28 @@
        • -
        • {% trans "Order Items" %}
        • -
        • {% trans "Build Orders" %}
        • -
        • {% trans "Attachments" %}
        • -
        • {% trans "Notes" %} diff --git a/InvenTree/order/urls.py b/InvenTree/order/urls.py index 768607a93b..2ce90f1f81 100644 --- a/InvenTree/order/urls.py +++ b/InvenTree/order/urls.py @@ -19,10 +19,6 @@ purchase_order_detail_urls = [ url(r'^upload/', views.PurchaseOrderUpload.as_view(), name='po-upload'), url(r'^export/', views.PurchaseOrderExport.as_view(), name='po-export'), - url(r'^notes/', views.PurchaseOrderNotes.as_view(), name='po-notes'), - - url(r'^received/', views.PurchaseOrderDetail.as_view(template_name='order/po_received_items.html'), name='po-received'), - url(r'^attachments/', views.PurchaseOrderDetail.as_view(template_name='order/po_attachments.html'), name='po-attachments'), url(r'^.*$', views.PurchaseOrderDetail.as_view(), name='po-detail'), ] diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 7267df1094..be1107f17b 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -13,7 +13,7 @@ from django.core.exceptions import ValidationError from django.urls import reverse from django.http import HttpResponseRedirect from django.utils.translation import ugettext_lazy as _ -from django.views.generic import DetailView, ListView, UpdateView +from django.views.generic import DetailView, ListView from django.views.generic.edit import FormMixin from django.forms import HiddenInput, IntegerField @@ -97,31 +97,6 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView): template_name = 'order/sales_order_detail.html' -class PurchaseOrderNotes(InvenTreeRoleMixin, UpdateView): - """ View for updating the 'notes' field of a PurchaseOrder """ - - context_object_name = 'order' - template_name = 'order/order_notes.html' - model = PurchaseOrder - - # Override the default permission roles - role_required = 'purchase_order.view' - - fields = ['notes'] - - def get_success_url(self): - - return reverse('po-notes', kwargs={'pk': self.get_object().id}) - - def get_context_data(self, **kwargs): - - ctx = super().get_context_data(**kwargs) - - ctx['editing'] = str2bool(self.request.GET.get('edit', False)) - - return ctx - - class PurchaseOrderCancel(AjaxUpdateView): """ View for cancelling a purchase order """ diff --git a/InvenTree/templates/js/nav.js b/InvenTree/templates/js/nav.js index a7f4ac8555..ed0e1dcc31 100644 --- a/InvenTree/templates/js/nav.js +++ b/InvenTree/templates/js/nav.js @@ -24,7 +24,7 @@ function attachNavCallbacks(options={}) { var panelClass = options.name || 'unknown'; // Look for a default panel to initialize - var defaultPanel = localStorage.getItem(`selected-panel-${panelClass}`) || options.default; + var defaultPanel = localStorage.getItem(`inventree-selected-panel-${panelClass}`) || options.default; if (defaultPanel) { activatePanel(defaultPanel); @@ -37,7 +37,7 @@ function activatePanel(panelName, options={}) { var panelClass = options.name || 'unknown'; // Save the selected panel - localStorage.setItem(`selected-panel-${panelClass}`, panelName); + localStorage.setItem(`inventree-selected-panel-${panelClass}`, panelName); // First, cause any other panels to "fade out" $('.panel-visible').hide(); @@ -48,13 +48,13 @@ function activatePanel(panelName, options={}) { // Display the panel $(panel).addClass('panel-visible'); - $(panel).fadeIn(50); + $(panel).fadeIn(100); // Un-select all selectors - $('.nav-item').removeClass('active'); + $('.list-group-item').removeClass('active'); // Find the associated selector var select = `#select-${panelName}`; - $(select).parent('.nav-item').addClass('active'); + $(select).parent('.list-group-item').addClass('active'); } \ No newline at end of file From c1c0a262b2e477dfe6182b45e47aa6fdf5ca2a37 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 13 Jul 2021 21:53:48 +1000 Subject: [PATCH 387/445] Refactor Company detail view --- .../templates/company/assigned_stock.html | 38 -- .../templates/company/company_base.html | 27 + .../company/templates/company/detail.html | 467 +++++++++++++++--- .../company/detail_manufacturer_part.html | 119 ----- .../templates/company/detail_stock.html | 49 -- .../company/detail_supplier_part.html | 127 ----- .../company/templates/company/navbar.html | 35 +- .../company/templates/company/notes.html | 47 -- .../templates/company/purchase_orders.html | 56 --- .../templates/company/sales_orders.html | 51 -- InvenTree/company/urls.py | 9 - InvenTree/company/views.py | 24 +- InvenTree/templates/js/nav.js | 31 +- 13 files changed, 478 insertions(+), 602 deletions(-) delete mode 100644 InvenTree/company/templates/company/assigned_stock.html delete mode 100644 InvenTree/company/templates/company/detail_manufacturer_part.html delete mode 100644 InvenTree/company/templates/company/detail_stock.html delete mode 100644 InvenTree/company/templates/company/detail_supplier_part.html delete mode 100644 InvenTree/company/templates/company/notes.html delete mode 100644 InvenTree/company/templates/company/purchase_orders.html delete mode 100644 InvenTree/company/templates/company/sales_orders.html diff --git a/InvenTree/company/templates/company/assigned_stock.html b/InvenTree/company/templates/company/assigned_stock.html deleted file mode 100644 index d64719407b..0000000000 --- a/InvenTree/company/templates/company/assigned_stock.html +++ /dev/null @@ -1,38 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/navbar.html" with tab="assigned" %} -{% endblock %} - -{% block heading %} -{% trans "Assigned Stock" %} -{% endblock %} - -{% block details %} - -
          -
          - -
          -
          - -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadStockTable($("#stock-table"), { - params: { - customer: {{ company.id }}, - part_detail: true, - location_detail: true, - }, - url: "{% url 'api-stock-list' %}", - filterKey: "customerstock", -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/company_base.html b/InvenTree/company/templates/company/company_base.html index 8c6b077137..3b8f1e7734 100644 --- a/InvenTree/company/templates/company/company_base.html +++ b/InvenTree/company/templates/company/company_base.html @@ -71,6 +71,17 @@
          {{ company.website }}{% include "clip.html"%} {% endif %} + + + {% trans "Currency" %} + + {% if company.currency %} + {{ company.currency }} + {% else %} + {% trans "Uses default currency" %} + {% endif %} + + {% if company.address %} @@ -99,6 +110,22 @@ {{ company.contact }}{% include "clip.html"%} {% endif %} + + + + {%trans "Manufacturer" %} + {% include "yesnolabel.html" with value=company.is_manufacturer %} + + + + {% trans "Supplier" %} + {% include 'yesnolabel.html' with value=company.is_supplier %} + + + + {% trans "Customer" %} + {% include 'yesnolabel.html' with value=company.is_customer %} + {% endblock %} diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html index 9c3cbfb84a..48f9d9895b 100644 --- a/InvenTree/company/templates/company/detail.html +++ b/InvenTree/company/templates/company/detail.html @@ -1,79 +1,430 @@ {% extends "company/company_base.html" %} {% load static %} {% load i18n %} +{% load markdownify %} {% block menubar %} {% include 'company/navbar.html' with tab='details' %} {% endblock %} -{% block heading %} -{% trans "Company Details" %} -{% endblock %} +{% block page_content %} -{% block details %} -
          -
          - - - - - - - - - {% if company.description %} - - - - - - {% endif %} - - - - - - - - - - +
          + +
          + +
          + +
          + + + {% endif %} + +
          {% trans "Company Name" %}{{ company.name }}{% include "clip.html"%}
          {% trans "Description" %}{{ company.description }}{% include "clip.html"%}
          {% trans "Website" %} - {% if company.website %}{{ company.website }}{% include "clip.html"%} - {% else %}{% trans "No website specified" %} +
          +
          +

          {% trans "Supplier Parts" %}

          +
          +
          + {% if roles.purchase_order.change %} +
          +
          +
          + {% if roles.purchase_order.add %} + {% endif %} -
          {% trans "Currency" %} - {% if company.currency %}{{ company.currency }} - {% else %}{% trans "Uses default currency" %} - {% endif %} -
          -
          - - - - - - - - - - - - - - - - - - -
          {% trans "Manufacturer" %}{% include "yesnolabel.html" with value=company.is_manufacturer %}
          {% trans "Supplier" %}{% include 'yesnolabel.html' with value=company.is_supplier %}
          {% trans "Customer" %}{% include 'yesnolabel.html' with value=company.is_customer %}
          +
          +
          +
          +

          {% trans "Manufacturer Parts" %}

          +
          +
          + {% if roles.purchase_order.change %} +
          +
          +
          + {% if roles.purchase_order.add %} + + {% endif %} +
          + +
          +
          +
          + +
          +
          +
          + {% endif %} + +
          +
          +
          + +
          +
          +

          {% trans "Supplier Stock" %}

          +
          +
          + {% include "stock_table.html" %} +
          +
          + +
          +
          +

          {% trans "Purchase Orders" %}

          +
          +
          + {% if roles.purchase_order.add %} +
          +
          + +
          + +
          +
          +
          + {% endif %} + + +
          +
          +
          + +
          +
          +

          {% trans "Sales Orders" %}

          +
          +
          + {% if roles.sales_order.add %} +
          +
          + +
          + +
          +
          +
          + {% endif %} + + +
          +
          +
          + +
          +
          +

          {% trans "Assigned Stock" %}

          +
          +
          +
          +
          + +
          +
          + +
          + +
          +
          + +
          +
          +
          +
          +

          {% trans "Company Notes" %}

          +
          +
          +
          + +
          +
          +
          +
          +
          + {{ company.notes | markdownify }}
          {% endblock %} + {% block js_ready %} {{ block.super }} + $('#edit-notes').click(function() { + constructForm('{% url "api-company-detail" company.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Notes" %}', + reload: true, + }); + }); + + loadStockTable($("#assigned-stock-table"), { + params: { + customer: {{ company.id }}, + part_detail: true, + location_detail: true, + }, + url: "{% url 'api-stock-list' %}", + filterKey: "customerstock", + }); + + {% if company.is_customer %} + loadSalesOrderTable("#sales-order-table", { + url: "{% url 'api-so-list' %}", + params: { + customer: {{ company.id }}, + } + }); + + $("#new-sales-order").click(function() { + + createSalesOrder({ + customer: {{ company.pk }}, + }); + }); + {% endif %} + + {% if company.is_supplier %} + loadPurchaseOrderTable("#purchase-order-table", { + url: "{% url 'api-po-list' %}", + params: { + supplier: {{ company.id }}, + } + }); + + function newOrder() { + createPurchaseOrder({ + supplier: {{ company.pk }}, + }); + } + + $("#company-order").click(function() { + newOrder(); + }); + + $("#company-order2").click(function() { + newOrder(); + }); + + {% endif %} + + loadStockTable($('#stock-table'), { + url: "{% url 'api-stock-list' %}", + params: { + company: {{ company.id }}, + part_detail: true, + supplier_part_detail: true, + location_detail: true, + }, + buttons: [ + '#stock-options', + ], + filterKey: "companystock", + }); + + $("#stock-export").click(function() { + launchModalForm("{% url 'stock-export-options' %}", { + submit_text: '{% trans "Export" %}', + success: function(response) { + var url = "{% url 'stock-export' %}"; + + url += "?format=" + response.format; + url += "&supplier={{ company.id }}"; + + location.href = url; + }, + }); + }); + + {% if company.is_manufacturer %} + + $("#manufacturer-part-create").click(function () { + + constructForm('{% url "api-manufacturer-part-list" %}', { + fields: { + part: {}, + manufacturer: { + value: {{ company.pk }}, + }, + MPN: { + icon: 'fa-hashtag', + }, + description: {}, + link: { + icon: 'fa-link', + }, + }, + method: 'POST', + title: '{% trans "Add Manufacturer Part" %}', + onSuccess: function() { + $("#part-table").bootstrapTable("refresh"); + } + }); + }); + + loadManufacturerPartTable( + "#part-table", + "{% url 'api-manufacturer-part-list' %}", + { + params: { + part_detail: true, + manufacturer_detail: true, + manufacturer: {{ company.id }}, + }, + } + ); + + linkButtonsToSelection($("#manufacturer-table"), ['#table-options']); + + $("#multi-part-delete").click(function() { + var selections = $("#part-table").bootstrapTable("getSelections"); + + deleteManufacturerParts(selections, { + onSuccess: function() { + $("#part-table").bootstrapTable("refresh"); + } + }); + }); + + $("#multi-part-order").click(function() { + var selections = $("#part-table").bootstrapTable("getSelections"); + + var parts = []; + + selections.forEach(function(item) { + parts.push(item.part); + }); + + launchModalForm("/order/purchase-order/order-parts/", { + data: { + parts: parts, + }, + }); + }); + + {% endif %} + + {% if company.is_supplier %} + + $("#supplier-part-create").click(function () { + launchModalForm( + "{% url 'supplier-part-create' %}", + { + data: { + supplier: {{ company.id }}, + }, + reload: true, + secondary: [ + { + field: 'part', + label: '{% trans "New Part" %}', + title: '{% trans "Create new Part" %}', + url: "{% url 'part-create' %}" + }, + { + field: 'supplier', + label: "{% trans 'New Supplier' %}", + title: "{% trans 'Create new Supplier' %}", + }, + ] + }); + }); + + loadSupplierPartTable( + "#part-table", + "{% url 'api-supplier-part-list' %}", + { + params: { + part_detail: true, + supplier_detail: true, + manufacturer_detail: true, + supplier: {{ company.id }}, + }, + } + ); + + {% endif %} + + $("#multi-part-delete").click(function() { + var selections = $("#part-table").bootstrapTable("getSelections"); + + var parts = []; + + selections.forEach(function(item) { + parts.push(item.pk); + }); + + var url = "{% url 'supplier-part-delete' %}" + + launchModalForm(url, { + data: { + parts: parts, + }, + reload: true, + }); + }); + + $("#multi-part-order").click(function() { + var selections = $("#part-table").bootstrapTable("getSelections"); + + var parts = []; + + selections.forEach(function(item) { + parts.push(item.part); + }); + + launchModalForm("/order/purchase-order/order-parts/", { + data: { + parts: parts, + }, + }); + }); + + attachNavCallbacks({ + panelClass: 'company', + default: 'company-stock' + }); + {% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/detail_manufacturer_part.html b/InvenTree/company/templates/company/detail_manufacturer_part.html deleted file mode 100644 index 0ff261ec67..0000000000 --- a/InvenTree/company/templates/company/detail_manufacturer_part.html +++ /dev/null @@ -1,119 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include 'company/navbar.html' with tab='manufacturer_parts' %} -{% endblock %} - -{% block heading %} -{% trans "Manufacturer Parts" %} -{% endblock %} - - -{% block details %} - -{% if roles.purchase_order.change %} -
          -
          -
          - {% if roles.purchase_order.add %} - - {% endif %} -
          - -
          -
          -
          - -
          -
          -
          -{% endif %} - -
          - -{% endblock %} -{% block js_ready %} -{{ block.super }} - - $("#manufacturer-part-create").click(function () { - - constructForm('{% url "api-manufacturer-part-list" %}', { - fields: { - part: {}, - manufacturer: { - value: {{ company.pk }}, - }, - MPN: { - icon: 'fa-hashtag', - }, - description: {}, - link: { - icon: 'fa-link', - }, - }, - method: 'POST', - title: '{% trans "Add Manufacturer Part" %}', - onSuccess: function() { - $("#part-table").bootstrapTable("refresh"); - } - }); - }); - - loadManufacturerPartTable( - "#part-table", - "{% url 'api-manufacturer-part-list' %}", - { - params: { - part_detail: true, - manufacturer_detail: true, - manufacturer: {{ company.id }}, - }, - } - ); - - linkButtonsToSelection($("#manufacturer-table"), ['#table-options']); - - $("#multi-part-delete").click(function() { - var selections = $("#part-table").bootstrapTable("getSelections"); - - deleteManufacturerParts(selections, { - onSuccess: function() { - $("#part-table").bootstrapTable("refresh"); - } - }); - }); - - $("#multi-part-order").click(function() { - var selections = $("#part-table").bootstrapTable("getSelections"); - - var parts = []; - - selections.forEach(function(item) { - parts.push(item.part); - }); - - launchModalForm("/order/purchase-order/order-parts/", { - data: { - parts: parts, - }, - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/detail_stock.html b/InvenTree/company/templates/company/detail_stock.html deleted file mode 100644 index 87f88bb550..0000000000 --- a/InvenTree/company/templates/company/detail_stock.html +++ /dev/null @@ -1,49 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/navbar.html" with tab='stock' %} -{% endblock %} - -{% block heading %} -{% trans "Supplier Stock" %} -{% endblock %} - -{% block details %} - -{% include "stock_table.html" %} - -{% endblock %} -{% block js_ready %} -{{ block.super }} - - loadStockTable($('#stock-table'), { - url: "{% url 'api-stock-list' %}", - params: { - company: {{ company.id }}, - part_detail: true, - supplier_part_detail: true, - location_detail: true, - }, - buttons: [ - '#stock-options', - ], - filterKey: "companystock", - }); - - $("#stock-export").click(function() { - launchModalForm("{% url 'stock-export-options' %}", { - submit_text: '{% trans "Export" %}', - success: function(response) { - var url = "{% url 'stock-export' %}"; - - url += "?format=" + response.format; - url += "&supplier={{ company.id }}"; - - location.href = url; - }, - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/detail_supplier_part.html b/InvenTree/company/templates/company/detail_supplier_part.html deleted file mode 100644 index 7cf9b66a11..0000000000 --- a/InvenTree/company/templates/company/detail_supplier_part.html +++ /dev/null @@ -1,127 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include 'company/navbar.html' with tab='supplier_parts' %} -{% endblock %} - -{% block heading %} -{% trans "Supplier Parts" %} -{% endblock %} - - -{% block details %} -{% if roles.purchase_order.change %} -
          -
          -
          - {% if roles.purchase_order.add %} - - {% endif %} -
          - -
          -
          -
          - -
          -
          -
          -{% endif %} - - -
          - -{% endblock %} -{% block js_ready %} -{{ block.super }} - - $("#supplier-part-create").click(function () { - launchModalForm( - "{% url 'supplier-part-create' %}", - { - data: { - supplier: {{ company.id }}, - }, - reload: true, - secondary: [ - { - field: 'part', - label: '{% trans "New Part" %}', - title: '{% trans "Create new Part" %}', - url: "{% url 'part-create' %}" - }, - { - field: 'supplier', - label: "{% trans 'New Supplier' %}", - title: "{% trans 'Create new Supplier' %}", - }, - ] - }); - }); - - loadSupplierPartTable( - "#part-table", - "{% url 'api-supplier-part-list' %}", - { - params: { - part_detail: true, - supplier_detail: true, - manufacturer_detail: true, - supplier: {{ company.id }}, - }, - } - ); - - $("#multi-part-delete").click(function() { - var selections = $("#part-table").bootstrapTable("getSelections"); - - var parts = []; - - selections.forEach(function(item) { - parts.push(item.pk); - }); - - var url = "{% url 'supplier-part-delete' %}" - - launchModalForm(url, { - data: { - parts: parts, - }, - reload: true, - }); - }); - - $("#multi-part-order").click(function() { - var selections = $("#part-table").bootstrapTable("getSelections"); - - var parts = []; - - selections.forEach(function(item) { - parts.push(item.part); - }); - - launchModalForm("/order/purchase-order/order-parts/", { - data: { - parts: parts, - }, - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/navbar.html b/InvenTree/company/templates/company/navbar.html index 715d448b0f..025b1c6b4a 100644 --- a/InvenTree/company/templates/company/navbar.html +++ b/InvenTree/company/templates/company/navbar.html @@ -9,16 +9,9 @@
        • -
        • - - - {% trans "Details" %} - -
        • - {% if company.is_manufacturer %} -
        • - +
        • + {% trans "Manufactured Parts" %} @@ -26,8 +19,8 @@ {% endif %} {% if company.is_supplier or company.is_manufacturer %} -
        • - +
        • + {% trans "Supplied Parts" %} @@ -35,8 +28,8 @@ {% endif %} {% if company.is_manufacturer or company.is_supplier %} -
        • - +
        • + {% trans "Stock" %} @@ -44,8 +37,8 @@ {% endif %} {% if company.is_supplier %} -
        • - +
        • + {% trans "Purchase Orders" %} @@ -53,22 +46,22 @@ {% endif %} {% if company.is_customer %} -
        • - +
        • + {% trans "Sales Orders" %}
        • -
        • - +
        • + {% trans "Assigned Stock" %}
        • {% endif %} -
        • - +
        • + {% trans "Notes" %} diff --git a/InvenTree/company/templates/company/notes.html b/InvenTree/company/templates/company/notes.html deleted file mode 100644 index 6b0e65e2d0..0000000000 --- a/InvenTree/company/templates/company/notes.html +++ /dev/null @@ -1,47 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} -{% load markdownify %} - -{% block menubar %} -{% include 'company/navbar.html' with tab='notes' %} -{% endblock %} - -{% block heading %} -{% trans "Company Notes" %} -{% if not editing %} - -{% endif %} -{% endblock %} - -{% block details %} -{% if editing %} -
          - {% csrf_token %} - - {{ form }} -
          - - -
          - -{{ form.media }} - -{% else %} - -{{ company.notes | markdownify }} -{% endif %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -{% if editing %} -{% else %} -$("#edit-notes").click(function() { - location.href = "{% url 'company-notes' company.id %}?edit=1"; -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/purchase_orders.html b/InvenTree/company/templates/company/purchase_orders.html deleted file mode 100644 index f23d360a8f..0000000000 --- a/InvenTree/company/templates/company/purchase_orders.html +++ /dev/null @@ -1,56 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'company/navbar.html' with tab='po' %} -{% endblock %} - -{% block heading %} -{% trans "Purchase Orders" %} -{% endblock %} - -{% block details %} - -{% if roles.purchase_order.add %} -
          -
          - -
          - -
          -
          -
          -{% endif %} - - -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - loadPurchaseOrderTable("#purchase-order-table", { - url: "{% url 'api-po-list' %}", - params: { - supplier: {{ company.id }}, - } - }); - - function newOrder() { - createPurchaseOrder({ - supplier: {{ company.pk }}, - }); - } - - $("#company-order").click(function() { - newOrder(); - }); - - $("#company-order2").click(function() { - newOrder(); - }); - -{% endblock %} diff --git a/InvenTree/company/templates/company/sales_orders.html b/InvenTree/company/templates/company/sales_orders.html deleted file mode 100644 index c21a9afc21..0000000000 --- a/InvenTree/company/templates/company/sales_orders.html +++ /dev/null @@ -1,51 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} - - -{% block menubar %} -{% include 'company/navbar.html' with tab='so' %} -{% endblock %} - -{% block heading %} -{% trans "Sales Orders" %} -{% endblock %} - -{% block details %} - -{% if roles.sales_order.add %} -
          -
          - -
          - -
          -
          -
          -{% endif %} - - -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - loadSalesOrderTable("#sales-order-table", { - url: "{% url 'api-so-list' %}", - params: { - customer: {{ company.id }}, - } - }); - - $("#new-sales-order").click(function() { - - createSalesOrder({ - customer: {{ company.pk }}, - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index e9e125d9e4..4f844176ee 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -8,15 +8,6 @@ from . import views company_detail_urls = [ - # url(r'orders/?', views.CompanyDetail.as_view(template_name='company/orders.html'), name='company-detail-orders'), - - url(r'^supplier-parts/', views.CompanyDetail.as_view(template_name='company/detail_supplier_part.html'), name='company-detail-supplier-parts'), - url(r'^manufacturer-parts/', views.CompanyDetail.as_view(template_name='company/detail_manufacturer_part.html'), name='company-detail-manufacturer-parts'), - url(r'^stock/', views.CompanyDetail.as_view(template_name='company/detail_stock.html'), name='company-detail-stock'), - url(r'^purchase-orders/', views.CompanyDetail.as_view(template_name='company/purchase_orders.html'), name='company-detail-purchase-orders'), - url(r'^assigned-stock/', views.CompanyDetail.as_view(template_name='company/assigned_stock.html'), name='company-detail-assigned-stock'), - url(r'^sales-orders/', views.CompanyDetail.as_view(template_name='company/sales_orders.html'), name='company-detail-sales-orders'), - url(r'^notes/', views.CompanyNotes.as_view(), name='company-notes'), url(r'^thumb-download/', views.CompanyImageDownloadFromURL.as_view(), name='company-image-download'), diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index 03fe03d411..ab6344e810 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -7,7 +7,7 @@ Django views for interacting with Company app from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ -from django.views.generic import DetailView, ListView, UpdateView +from django.views.generic import DetailView, ListView from django.urls import reverse from django.forms import HiddenInput @@ -113,28 +113,6 @@ class CompanyIndex(InvenTreeRoleMixin, ListView): return queryset -class CompanyNotes(UpdateView): - """ View for editing the 'notes' field of a Company object. - """ - - context_object_name = 'company' - template_name = 'company/notes.html' - model = Company - fields = ['notes'] - permission_required = 'company.view_company' - - def get_success_url(self): - return reverse('company-notes', kwargs={'pk': self.get_object().id}) - - def get_context_data(self, **kwargs): - - ctx = super().get_context_data(**kwargs) - - ctx['editing'] = str2bool(self.request.GET.get('edit', '')) - - return ctx - - class CompanyDetail(DetailView): """ Detail view for Company object """ context_obect_name = 'company' diff --git a/InvenTree/templates/js/nav.js b/InvenTree/templates/js/nav.js index ed0e1dcc31..e8207f9251 100644 --- a/InvenTree/templates/js/nav.js +++ b/InvenTree/templates/js/nav.js @@ -36,15 +36,38 @@ function activatePanel(panelName, options={}) { var panelClass = options.name || 'unknown'; - // Save the selected panel - localStorage.setItem(`inventree-selected-panel-${panelClass}`, panelName); - // First, cause any other panels to "fade out" $('.panel-visible').hide(); $('.panel-visible').removeClass('panel-visible'); - + // Find the target panel var panel = `#panel-${panelName}`; + var select = `#select-${panelName}`; + + // Check that the selected panel (and select) exist + if ($(panel).length && $(select).length) { + // Yep, both are displayed + } else { + // Either the select or the panel are not displayed! + // Iterate through the available 'select' elements until one matches + panelName = null; + + console.log("no match for panel:", panelName); + + $('.nav-toggle').each(function(item) { + var panel_name = $(this).attr('id').replace('select-', ''); + + console.log("checking:", panel_name); + + if ($(`#panel-${panel_name}`).length && (panelName == null)) { + console.log("found match -", panel_name); + panelName = panel_name; + } + }); + } + + // Save the selected panel + localStorage.setItem(`inventree-selected-panel-${panelClass}`, panelName); // Display the panel $(panel).addClass('panel-visible'); From 8dde89e781b9b6009b48fb7489522dc2d9a1de96 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 13 Jul 2021 21:57:49 +1000 Subject: [PATCH 388/445] Table fixes --- .../company/templates/company/detail.html | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html index 48f9d9895b..9bc47e3b63 100644 --- a/InvenTree/company/templates/company/detail.html +++ b/InvenTree/company/templates/company/detail.html @@ -15,7 +15,7 @@
        • {% if roles.purchase_order.change %} -
          +
          {% if roles.purchase_order.add %} @@ -46,7 +46,7 @@
          {% endif %} - +
          @@ -57,7 +57,7 @@
          {% if roles.purchase_order.change %} -
          +
          {% if roles.purchase_order.add %} @@ -87,7 +87,7 @@
          {% endif %} - +
          @@ -107,7 +107,7 @@
          {% if roles.purchase_order.add %} -
          +
          @@ -118,7 +118,7 @@
          {% endif %} - +
          @@ -129,7 +129,7 @@
          {% if roles.sales_order.add %} -
          +
          {% endif %} - +
          @@ -151,13 +151,13 @@

          {% trans "Assigned Stock" %}

          -
          +
          -
          +
          @@ -373,7 +373,7 @@ }); loadSupplierPartTable( - "#part-table", + "#supplier-part-table", "{% url 'api-supplier-part-list' %}", { params: { From 8fed3b3522df92d301b46c41bbf1ec9aeee380c9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 13 Jul 2021 22:03:49 +1000 Subject: [PATCH 389/445] Typo fix --- InvenTree/company/templates/company/detail.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html index 9bc47e3b63..1f2bcf3784 100644 --- a/InvenTree/company/templates/company/detail.html +++ b/InvenTree/company/templates/company/detail.html @@ -423,7 +423,7 @@ }); attachNavCallbacks({ - panelClass: 'company', + name: 'company', default: 'company-stock' }); From 3d9ad24e27621c97235a1a999092422ee0513c5b Mon Sep 17 00:00:00 2001 From: eeintech Date: Tue, 13 Jul 2021 12:55:36 -0400 Subject: [PATCH 390/445] Defined custom SupplierPart object manager and prefetch related models in all queries --- InvenTree/company/api.py | 6 +----- InvenTree/company/models.py | 18 ++++++++++++++++++ InvenTree/order/admin.py | 1 + 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/InvenTree/company/api.py b/InvenTree/company/api.py index 2c05c98d91..76b08ec27e 100644 --- a/InvenTree/company/api.py +++ b/InvenTree/company/api.py @@ -263,11 +263,7 @@ class SupplierPartList(generics.ListCreateAPIView): - POST: Create a new SupplierPart object """ - queryset = SupplierPart.objects.all().prefetch_related( - 'part', - 'supplier', - 'manufacturer_part__manufacturer', - ) + queryset = SupplierPart.objects.all() def get_queryset(self): diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index 3786531311..778e00cde1 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -430,6 +430,22 @@ class ManufacturerPartParameter(models.Model): ) +class SupplierPartManager(models.Manager): + """ Define custom SupplierPart objects manager + + The main purpose of this manager is to improve database hit as the + SupplierPart model involves A LOT of foreign keys lookups + """ + + def get_queryset(self): + # Always prefetch related models + return super().get_queryset().prefetch_related( + 'part', + 'supplier', + 'manufacturer_part__manufacturer', + ) + + class SupplierPart(models.Model): """ Represents a unique part as provided by a Supplier Each SupplierPart is identified by a SKU (Supplier Part Number) @@ -450,6 +466,8 @@ class SupplierPart(models.Model): packaging: packaging that the part is supplied in, e.g. "Reel" """ + objects = SupplierPartManager() + @staticmethod def get_api_url(): return reverse('api-supplier-part-list') diff --git a/InvenTree/order/admin.py b/InvenTree/order/admin.py index 1e7b20e5a1..5d843fc624 100644 --- a/InvenTree/order/admin.py +++ b/InvenTree/order/admin.py @@ -15,6 +15,7 @@ from .models import SalesOrderAllocation class PurchaseOrderLineItemInlineAdmin(admin.StackedInline): model = PurchaseOrderLineItem + extra = 0 class PurchaseOrderAdmin(ImportExportModelAdmin): From 94792596e9c0fe80786789b1fcca0ea924fa10c9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 09:54:55 +1000 Subject: [PATCH 391/445] Update version.py Bumped version number --- InvenTree/InvenTree/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index 12a7093e7a..44c5dd3c59 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -8,7 +8,7 @@ import re import common.models -INVENTREE_SW_VERSION = "0.2.5 pre" +INVENTREE_SW_VERSION = "0.3.0" INVENTREE_API_VERSION = 7 From 06678577547e7f89310a5979941583c10a42b014 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 12:04:48 +1000 Subject: [PATCH 392/445] Refactor part base display --- InvenTree/part/templates/part/detail.html | 216 +------------------ InvenTree/part/templates/part/part_base.html | 58 +++-- 2 files changed, 47 insertions(+), 227 deletions(-) diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 8a78eb85a5..ecfddf66c5 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -18,131 +18,6 @@
          - - - - - - {% if part.IPN %} - - - - - - {% endif %} - {% if part.revision %} - - - - - - {% endif %} - {% if part.trackable %} - - - - - - {% endif %} - - - - - - {% if part.variant_of %} - - - - - - {% endif %} - {% if part.keywords %} - - - - - - {% endif %} - - - - - - {% if part.link %} - - - - - - {% endif %} - {% if part.default_location %} - - - - - - {% endif %} - {% if part.default_supplier %} - - - - - - {% endif %} - {% if part.units %} - - - - - - {% endif %} - {% if part.minimum_stock > 0 %} - - - - - - {% endif %} - {% if part.default_expiry > 0 %} - - - - - - {% endif %} - - - - - - {% if part.creation_user %} - - - - - - {% endif %} - {% if part.responsible %} - - - - - - {% endif %} - - @@ -171,96 +46,7 @@
          {% trans "Part name" %}{{ part.name }}{% include "clip.html"%}
          {% trans "IPN" %}{{ part.IPN }}{% include "clip.html"%}
          {% trans "Revision" %}{{ part.revision }}{% include "clip.html"%}
          {% trans "Latest Serial Number" %} - {% if part.getLatestSerialNumber %} - {{ part.getLatestSerialNumber }}{% include "clip.html"%} - {% else %} - {% trans "No serial numbers recorded" %} - {% endif %} -
          {% trans "Description" %}{{ part.description }}{% include "clip.html"%}
          {% trans "Variant Of" %}{{ part.variant_of.full_name }}{% include "clip.html"%}
          {% trans "Keywords" %}{{ part.keywords }}{% include "clip.html"%}
          {% trans "Category" %} - {% if part.category %} - {{ part.category.pathstring }}{% include "clip.html"%} - {% endif %} -
          {% trans "External Link" %}{{ part.link }}{% include "clip.html"%}
          {% trans "Default Location" %}{{ part.default_location.pathstring }}{% include "clip.html"%}
          {% trans "Default Supplier" %} - {{ part.default_supplier.supplier.name }} | {{ part.default_supplier.SKU }} - {% include "clip.html"%}
          {% trans "Units" %}{{ part.units }}{% include "clip.html"%}
          {% trans "Minimum Stock" %}{{ part.minimum_stock }}
          {% trans "Stock Expiry Time" %}{{ part.default_expiry }} {% trans "days" %}
          {% trans "Creation Date" %}{{ part.creation_date }}
          {% trans "Created By" %}{{ part.creation_user }}
          {% trans "Responsible User" %}{{ part.responsible }}
          - - - - - - - {% if part.virtual %} - - {% else %} - - {% endif %} - - - - - - {% if part.is_template %} - - {% else %} - - {% endif %} - - - - - - {% if part.assembly %} - - {% else %} - - {% endif %} - - - - - - {% if part.component %} - - {% else %} - - {% endif %} - - - - - - {% if part.trackable %} - - {% else %} - - {% endif %} - - - - - - {% if part.purchaseable %} - - {% else %} - - {% endif %} - - - - - - {% if part.salable %} - - {% else %} - - {% endif %} - - - - - - - {% if part.active %} - - {% else %} - - {% endif %} - -
          {% trans "Virtual" %}{% include "slide.html" with state=part.virtual field='virtual' %}{% trans "Part is virtual (not a physical part)" %}{% trans "Part is not a virtual part" %}
          {% trans "Template" %}{% include "slide.html" with state=part.is_template field='is_template' %}{% trans "Part is a template part (variants can be made from this part)" %}{% trans "Part is not a template part" %}
          {% trans "Assembly" %}{% include "slide.html" with state=part.assembly field='assembly' %}{% trans "Part can be assembled from other parts" %}{% trans "Part cannot be assembled from other parts" %}
          {% trans "Component" %}{% include "slide.html" with state=part.component field='component' %}{% trans "Part can be used in assemblies" %}{% trans "Part cannot be used in assemblies" %}
          {% trans "Trackable" %}{% include "slide.html" with state=part.trackable field='trackable' %}{% trans "Part stock is tracked by serial number" %}{% trans "Part stock is not tracked by serial number" %}
          {% trans "Purchaseable" %}{% include "slide.html" with state=part.purchaseable field='purchaseable' %}{% trans "Part can be purchased from external suppliers" %}{% trans "Part can be purchased from external suppliers" %}
          {% trans "Salable" %}{% include "slide.html" with state=part.salable field='salable' %}{% trans "Part can be sold to customers" %}{% trans "Part cannot be sold to customers" %}
          - {% if part.active %} - - {% else %} - - {% endif %} - {% trans "Active" %}{% include "slide.html" with state=part.active field='active' disabled=False %}{% trans "Part is active" %}{% trans "Part is not active" %}
          +
          diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index 391f6d1d35..2fdcbb278b 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -27,7 +27,34 @@
          {% endif %} + {% if part.description %}

          {{ part.description }}

          + {% endif %} +

          +

          + {% if part.virtual %} + + {% endif %} + {% if part.is_template %} + + {% endif %} + {% if part.assembly %} + + {% endif %} + {% if part.component %} + + {% endif %} + {% if part.trackable %} + + {% endif %} + {% if part.purchaseable %} + + {% endif %} + {% if part.salable %} + + {% endif %} +
          +

          - {% if part.IPN %} + {% if part.keywords %} - - - + + + {% endif %} {% if part.link %} @@ -112,7 +139,22 @@ {% endif %} + + + + {% if part.trackable and part.getLatestSerialNumber %} + + + + + + {% endif %}
          {% trans "IPN" %}{{ part.IPN }}{% trans "Keywords" %}{{ part.keywords }}
          {% trans "Creation Date" %} + {{ part.creation_date }} + {% if part.creation_user %} + {{ part.creation_user }} + {% endif %} +
          {% trans "Latest Serial Number" %}{{ part.getLatestSerialNumber }}{% include "clip.html"%}
          @@ -197,14 +239,6 @@ {% endif %} {% endif %} {% endif %} - {% if part.trackable and part.getLatestSerialNumber %} - - - - {% trans "Latest Serial Number" %} - {{ part.getLatestSerialNumber }}{% include "clip.html"%} - - {% endif %}
          From 2d2ad91545477a7186ca6b46c8cbe0a888f96a4d Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 12:52:36 +1000 Subject: [PATCH 393/445] Move "stock" part view --- .../order/purchase_order_detail.html | 3 +- .../templates/order/sales_order_detail.html | 2 +- InvenTree/part/templates/part/detail.html | 160 +++++++++++------- InvenTree/part/templates/part/navbar.html | 76 +++++---- InvenTree/part/templates/part/part_base.html | 25 +-- InvenTree/part/templates/part/stock.html | 77 --------- InvenTree/part/urls.py | 1 - .../stock/templates/stock/item_base.html | 4 +- 8 files changed, 150 insertions(+), 198 deletions(-) delete mode 100644 InvenTree/part/templates/part/stock.html diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index 8832974510..8c9feab452 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -7,8 +7,7 @@ {% load markdownify %} {% block menubar %} -{% include 'order/po_navbar.html' with tab='details' %} - +{% include 'order/po_navbar.html' %} {% endblock %} {% block page_content %} diff --git a/InvenTree/order/templates/order/sales_order_detail.html b/InvenTree/order/templates/order/sales_order_detail.html index a61f6a11ce..8ada362092 100644 --- a/InvenTree/order/templates/order/sales_order_detail.html +++ b/InvenTree/order/templates/order/sales_order_detail.html @@ -7,7 +7,7 @@ {% load markdownify %} {% block menubar %} -{% include "order/so_navbar.html" with tab='details' %} +{% include "order/so_navbar.html" %} {% endblock %} {% block page_content %} diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index ecfddf66c5..c24690c868 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -5,84 +5,70 @@ {% block menubar %} -{% include 'part/navbar.html' with tab='details' %} +{% include 'part/navbar.html' %} {% endblock %} -{% block heading %} -{% trans "Part Details" %} -{% endblock %} +{% block page_content %} -{% block details %} +
          +
          +

          {% trans "Part Stock" %}

          +
          +
          + {% if part.is_template %} +
          + {% blocktrans with full_name=part.full_name%}Showing stock for all variants of {{full_name}}{% endblocktrans %} +
          + {% endif %} + {% include "stock_table.html" %} +
          +
          -
          -
          - - - - - - - - - - - - -
          - {% trans "Notes" %} - +
          +
          +
          +
          +

          {% trans "Notes" %}

          +
          +
          -
          - {% if part.notes %} -
          - {{ part.notes | markdownify }} -
          - {% endif %} -
          +
          +
          -
          - +
          + {{ part.notes | markdownify }}
          -{% endblock %} - -{% block post_content_panel %} - -
          -
          -
          -
          -

          {% trans "Parameters" %}

          -
          -
          -
          -
          - {% if roles.part.add %} - - {% endif %} -
          -
          -
          -
          -
          +
          +
          +

          {% trans "Parameters" %}

          -
          -
          -
          -

          {% trans "Attachments" %}

          -
          -
          - {% include "attachment_table.html" %} +
          +
          +
          + {% if roles.part.add %} + + {% endif %}
          +
          +
          +
          + +
          +
          +

          {% trans "Attachments" %}

          +
          +
          + {% include "attachment_table.html" %}
          @@ -95,6 +81,53 @@ {% block js_ready %} {{ block.super }} + $('#add-stock-item').click(function () { + createNewStockItem({ + reload: true, + data: { + part: {{ part.id }}, + } + }); + }); + + loadStockTable($("#stock-table"), { + params: { + part: {{ part.id }}, + location_detail: true, + part_detail: true, + supplier_part_detail: true, + }, + groupByField: 'location', + buttons: [ + '#stock-options', + ], + url: "{% url 'api-stock-list' %}", + }); + + $("#stock-export").click(function() { + launchModalForm("{% url 'stock-export-options' %}", { + submit_text: "{% trans 'Export' %}", + success: function(response) { + var url = "{% url 'stock-export' %}"; + + url += "?format=" + response.format; + url += "&cascade=" + response.cascade; + url += "&part={{ part.id }}"; + + location.href = url; + }, + }); + }); + + $('#item-create').click(function () { + createNewStockItem({ + reload: true, + data: { + part: {{ part.id }}, + } + }); + }); + $('#edit-notes').click(function() { constructForm('{% url "api-part-detail" part.pk %}', { fields: { @@ -239,4 +272,9 @@ ) }); + attachNavCallbacks({ + name: 'part', + default: 'part-stock' + }); + {% endblock %} diff --git a/InvenTree/part/templates/part/navbar.html b/InvenTree/part/templates/part/navbar.html index e8617dc677..d634229500 100644 --- a/InvenTree/part/templates/part/navbar.html +++ b/InvenTree/part/templates/part/navbar.html @@ -11,46 +11,44 @@ -
        • - - - - {% trans "Details" %} - +
        • + + + {% trans "Parameters" %}
        • {% if part.is_template %} -
        • - +
        • + {% trans "Variants" %}
        • {% endif %} -
        • - +
        • + {% trans "Stock" %}
        • {% if part.component or part.salable %} -
        • - +
        • + {% trans "Allocations" %}
        • {% endif %} {% if part.assembly %} -
        • - +
        • + {% trans "Bill of Materials" %}
        • {% if roles.build.view %} -
        • - +
        • + {% trans "Build Orders" %} @@ -58,55 +56,73 @@ {% endif %} {% endif %} {% if part.component %} -
        • - +
        • + {% trans "Used In" %}
        • {% endif %} -
        • - +
        • + {% trans "Prices" %}
        • {% if part.purchaseable and roles.purchase_order.view %} -
        • - +
        • + {% trans "Suppliers" %}
        • -
        • - +
        • + + + {% trans "Manufacturers" %} + +
        • +
        • + {% trans "Purchase Orders" %}
        • {% endif %} {% if roles.sales_order.view %} -
        • - +
        • + {% trans "Sales Orders" %}
        • {% endif %} {% if part.trackable %} -
        • - +
        • + {% trans "Test Templates" %}
        • {% endif %} {% if show_related %} -
        • - +
        • + {% trans "Related Parts" %}
        • {% endif %} +
        • + + + {% trans "Attachments" %} + +
        • +
        • + + + {% trans "Notes" %} + +
        • diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index 2fdcbb278b..e7ec892628 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -245,30 +245,7 @@
          -{% block pre_content_panel %} - -{% endblock %} - -
          - - -
          -

          - {% block heading %} - - {% endblock %} -

          -
          - -
          - {% block details %} - - {% endblock %} -
          - -
          -{% block post_content_panel %} - +{% block page_content %} {% endblock %} {% endblock %} diff --git a/InvenTree/part/templates/part/stock.html b/InvenTree/part/templates/part/stock.html deleted file mode 100644 index ea745708dd..0000000000 --- a/InvenTree/part/templates/part/stock.html +++ /dev/null @@ -1,77 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='stock' %} -{% endblock %} - -{% block heading %} -{% trans "Part Stock" %} -{% endblock %} - -{% block details %} -{% if part.is_template %} -
          - {% blocktrans with full_name=part.full_name%}Showing stock for all variants of {{full_name}}{% endblocktrans %} -
          -{% endif %} - -{% include "stock_table.html" %} - -{% endblock %} - -{% block js_load %} -{{ block.super }} -{% endblock %} -{% block js_ready %} -{{ block.super }} - - $('#add-stock-item').click(function () { - createNewStockItem({ - reload: true, - data: { - part: {{ part.id }}, - } - }); - }); - - loadStockTable($("#stock-table"), { - params: { - part: {{ part.id }}, - location_detail: true, - part_detail: true, - supplier_part_detail: true, - }, - groupByField: 'location', - buttons: [ - '#stock-options', - ], - url: "{% url 'api-stock-list' %}", - }); - - $("#stock-export").click(function() { - launchModalForm("{% url 'stock-export-options' %}", { - submit_text: "{% trans 'Export' %}", - success: function(response) { - var url = "{% url 'stock-export' %}"; - - url += "?format=" + response.format; - url += "&cascade=" + response.cascade; - url += "&part={{ part.id }}"; - - location.href = url; - }, - }); - }); - - $('#item-create').click(function () { - createNewStockItem({ - reload: true, - data: { - part: {{ part.id }}, - } - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 1fa7227f5e..8248d7575a 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -49,7 +49,6 @@ part_detail_urls = [ url(r'^bom-duplicate/?', views.BomDuplicate.as_view(), name='duplicate-bom'), url(r'^variants/?', views.PartDetail.as_view(template_name='part/variants.html'), name='part-variants'), - url(r'^stock/?', views.PartDetail.as_view(template_name='part/stock.html'), name='part-stock'), url(r'^allocation/?', views.PartDetail.as_view(template_name='part/allocation.html'), name='part-allocation'), url(r'^bom/?', views.PartDetail.as_view(template_name='part/bom.html'), name='part-bom'), url(r'^build/?', views.PartDetail.as_view(template_name='part/build.html'), name='part-build'), diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index 979c54ba28..ea57b981d8 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -235,7 +235,7 @@ {% trans "Base Part" %} {% if roles.part.view %} - + {% endif %} {{ item.part.full_name }} {% if roles.part.view %} @@ -561,7 +561,7 @@ $("#stock-delete").click(function () { launchModalForm( "{% url 'stock-item-delete' item.id %}", { - redirect: "{% url 'part-stock' item.part.id %}" + redirect: "{% url 'part-detail' item.part.id %}" } ); }); From 1a30a5bc16728db9f1155118e74654aff6001b19 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 12:56:17 +1000 Subject: [PATCH 394/445] Merge "test template" page --- InvenTree/part/templates/part/detail.html | 84 ++++++++++++++++ InvenTree/part/templates/part/part_tests.html | 96 ------------------- 2 files changed, 84 insertions(+), 96 deletions(-) delete mode 100644 InvenTree/part/templates/part/part_tests.html diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index c24690c868..1f217a872c 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -24,6 +24,26 @@
          +
          +
          +

          {% trans "Part Test Templates" %}

          +
          +
          +
          +
          +
          + +
          +
          + +
          +
          +
          + +
          +
          +
          +
          @@ -81,6 +101,70 @@ {% block js_ready %} {{ block.super }} + loadPartTestTemplateTable( + $("#test-template-table"), + { + part: {{ part.pk }}, + params: { + part: {{ part.pk }}, + } + } + ); + + function reloadTable() { + $("#test-template-table").bootstrapTable("refresh"); + } + + $("#add-test-template").click(function() { + + constructForm('{% url "api-part-test-template-list" %}', { + method: 'POST', + fields: { + test_name: {}, + description: {}, + required: {}, + requires_value: {}, + requires_attachment: {}, + part: { + value: {{ part.pk }}, + hidden: true, + } + }, + title: '{% trans "Add Test Result Template" %}', + onSuccess: reloadTable + }); + }); + + $("#test-template-table").on('click', '.button-test-edit', function() { + var pk = $(this).attr('pk'); + + var url = `/api/part/test-template/${pk}/`; + + constructForm(url, { + fields: { + test_name: {}, + description: {}, + required: {}, + requires_value: {}, + requires_attachment: {}, + }, + title: '{% trans "Edit Test Result Template" %}', + onSuccess: reloadTable, + }); + }); + + $("#test-template-table").on('click', '.button-test-delete', function() { + var pk = $(this).attr('pk'); + + var url = `/api/part/test-template/${pk}/`; + + constructForm(url, { + method: 'DELETE', + title: '{% trans "Delete Test Result Template" %}', + onSuccess: reloadTable, + }); + }); + $('#add-stock-item').click(function () { createNewStockItem({ reload: true, diff --git a/InvenTree/part/templates/part/part_tests.html b/InvenTree/part/templates/part/part_tests.html deleted file mode 100644 index 3c131aa1d4..0000000000 --- a/InvenTree/part/templates/part/part_tests.html +++ /dev/null @@ -1,96 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='tests' %} -{% endblock %} - -{% block heading %} -{% trans "Part Test Templates" %} -{% endblock %} - -{% block details %} -
          -
          -
          - -
          -
          - -
          -
          -
          - -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadPartTestTemplateTable( - $("#test-template-table"), - { - part: {{ part.pk }}, - params: { - part: {{ part.pk }}, - } - } -); - -function reloadTable() { - $("#test-template-table").bootstrapTable("refresh"); -} - -$("#add-test-template").click(function() { - - constructForm('{% url "api-part-test-template-list" %}', { - method: 'POST', - fields: { - test_name: {}, - description: {}, - required: {}, - requires_value: {}, - requires_attachment: {}, - part: { - value: {{ part.pk }}, - hidden: true, - } - }, - title: '{% trans "Add Test Result Template" %}', - onSuccess: reloadTable - }); -}); - -$("#test-template-table").on('click', '.button-test-edit', function() { - var pk = $(this).attr('pk'); - - var url = `/api/part/test-template/${pk}/`; - - constructForm(url, { - fields: { - test_name: {}, - description: {}, - required: {}, - requires_value: {}, - requires_attachment: {}, - }, - title: '{% trans "Edit Test Result Template" %}', - onSuccess: reloadTable, - }); -}); - -$("#test-template-table").on('click', '.button-test-delete', function() { - var pk = $(this).attr('pk'); - - var url = `/api/part/test-template/${pk}/`; - - constructForm(url, { - method: 'DELETE', - title: '{% trans "Delete Test Result Template" %}', - onSuccess: reloadTable, - }); -}); - -{% endblock %} \ No newline at end of file From 3786454e4c164035923600ea659e2477a10deec5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 12:56:26 +1000 Subject: [PATCH 395/445] Remove URL --- InvenTree/part/urls.py | 1 - 1 file changed, 1 deletion(-) diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 8248d7575a..8aa254e126 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -57,7 +57,6 @@ part_detail_urls = [ url(r'^suppliers/?', views.PartDetail.as_view(template_name='part/supplier.html'), name='part-suppliers'), url(r'^orders/?', views.PartDetail.as_view(template_name='part/orders.html'), name='part-orders'), url(r'^sales-orders/', views.PartDetail.as_view(template_name='part/sales_orders.html'), name='part-sales-orders'), - url(r'^tests/', views.PartDetail.as_view(template_name='part/part_tests.html'), name='part-test-templates'), url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), url(r'^related-parts/?', views.PartDetail.as_view(template_name='part/related.html'), name='part-related'), From 352a58b37328491d6482dbe86650a5613bdebc30 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 13:41:26 +1000 Subject: [PATCH 396/445] Can select nav based on URL query parameter --- InvenTree/InvenTree/static/css/inventree.css | 2 +- .../examples/bootstrap-2.3.2/css/bootstrap.css | 2 +- InvenTree/templates/js/api.js | 8 ++++++++ InvenTree/templates/js/nav.js | 11 +++++++++-- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index 1f01037f28..b538aaad04 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -781,7 +781,7 @@ input[type="submit"] { } .sidenav .list-group-item.active { - background-color: #ddd; + background-color: #bbab8b; border-color: #ccc; } diff --git a/InvenTree/InvenTree/static/treegrid/examples/bootstrap-2.3.2/css/bootstrap.css b/InvenTree/InvenTree/static/treegrid/examples/bootstrap-2.3.2/css/bootstrap.css index 5b7fe7e856..c3de0d956c 100644 --- a/InvenTree/InvenTree/static/treegrid/examples/bootstrap-2.3.2/css/bootstrap.css +++ b/InvenTree/InvenTree/static/treegrid/examples/bootstrap-2.3.2/css/bootstrap.css @@ -4678,7 +4678,7 @@ input[type="submit"].btn.btn-mini { .navbar .btn-navbar:active, .navbar .btn-navbar.active { - background-color: #cccccc \9; + background-color: #ba8; } .navbar .btn-navbar .icon-bar { diff --git a/InvenTree/templates/js/api.js b/InvenTree/templates/js/api.js index 93fa5a41e4..8169671836 100644 --- a/InvenTree/templates/js/api.js +++ b/InvenTree/templates/js/api.js @@ -3,6 +3,14 @@ var jQuery = window.$; +$.urlParam = function(name){ + var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href); + if (results==null) { + return null; + } + return decodeURI(results[1]) || 0; +} + // using jQuery function getCookie(name) { var cookieValue = null; diff --git a/InvenTree/templates/js/nav.js b/InvenTree/templates/js/nav.js index e8207f9251..7dc562b8ef 100644 --- a/InvenTree/templates/js/nav.js +++ b/InvenTree/templates/js/nav.js @@ -23,8 +23,12 @@ function attachNavCallbacks(options={}) { var panelClass = options.name || 'unknown'; - // Look for a default panel to initialize - var defaultPanel = localStorage.getItem(`inventree-selected-panel-${panelClass}`) || options.default; + /* Look for a default panel to initialize + * First preference = URL parameter e.g. ?display=part-stock + * Second preference = localStorage + * Third preference = default + */ + var defaultPanel = $.urlParam('display') || localStorage.getItem(`inventree-selected-panel-${panelClass}`) || options.default; if (defaultPanel) { activatePanel(defaultPanel); @@ -63,6 +67,9 @@ function activatePanel(panelName, options={}) { console.log("found match -", panel_name); panelName = panel_name; } + + panel = `#panel-${panelName}`; + select = `#select-${panelName}`; }); } From 984e16d5aff6e575159311889bb50c292bffe00a Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 16:07:46 +1000 Subject: [PATCH 397/445] Return all part parameters to the main part edit form - refactor purchaseorder view - refactor salesorder view --- InvenTree/InvenTree/static/css/inventree.css | 2 +- InvenTree/part/api.py | 2 +- InvenTree/part/templates/part/detail.html | 65 ++++++++++++++ InvenTree/part/templates/part/orders.html | 51 ----------- InvenTree/part/templates/part/part_base.html | 75 +--------------- .../part/templates/part/sales_orders.html | 41 --------- InvenTree/part/test_views.py | 15 ---- InvenTree/part/urls.py | 3 - InvenTree/part/views.py | 34 ------- InvenTree/templates/js/nav.js | 5 -- InvenTree/templates/js/part.js | 88 +++++++++++++++++++ 11 files changed, 156 insertions(+), 225 deletions(-) delete mode 100644 InvenTree/part/templates/part/orders.html delete mode 100644 InvenTree/part/templates/part/sales_orders.html diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index b538aaad04..1c8d529a92 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -781,7 +781,7 @@ input[type="submit"] { } .sidenav .list-group-item.active { - background-color: #bbab8b; + background-color: #b3a997; border-color: #ccc; } diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 599c4bba5d..9abee816fa 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -1104,7 +1104,7 @@ part_api_urls = [ url(r'^(?P\d+)/?', PartThumbsUpdate.as_view(), name='api-part-thumbs-update'), ])), - url(r'^(?P\d+)/?', PartDetail.as_view(), name='api-part-detail'), + url(r'^(?P\d+)/', PartDetail.as_view(), name='api-part-detail'), url(r'^.*$', PartList.as_view(), name='api-part-list'), ] diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 1f217a872c..5b377708f6 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -44,6 +44,48 @@
          +
          +
          +

          {% trans "Purchase Orders" %}

          +
          +
          +
          +
          + +
          + +
          +
          +
          + + +
          +
          +
          + +
          +
          +

          {% trans "Sales Orders" %}

          +
          +
          +
          +
          + {% if 0 %} + + {% endif %} +
          + +
          +
          +
          + + +
          +
          +
          +
          @@ -101,6 +143,29 @@ {% block js_ready %} {{ block.super }} + loadPurchaseOrderTable($("#purchase-order-table"), { + url: "{% url 'api-po-list' %}", + params: { + part: {{ part.id }}, + }, + }); + + $("#part-order2").click(function() { + launchModalForm("{% url 'order-parts' %}", { + data: { + part: {{ part.id }}, + }, + reload: true, + }); + }); + + loadSalesOrderTable($("#sales-order-table"), { + url: "{% url 'api-so-list' %}", + params: { + part: {{ part.id }}, + }, + }); + loadPartTestTemplateTable( $("#test-template-table"), { diff --git a/InvenTree/part/templates/part/orders.html b/InvenTree/part/templates/part/orders.html deleted file mode 100644 index 24a1cdbf3c..0000000000 --- a/InvenTree/part/templates/part/orders.html +++ /dev/null @@ -1,51 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='orders' %} -{% endblock %} - -{% block heading %} -{% trans "Purchase Orders" %} -{% endblock %} - -{% block details %} - -
          -
          - -
          - -
          -
          -
          - - -
          - - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadPurchaseOrderTable($("#purchase-order-table"), { - url: "{% url 'api-po-list' %}", - params: { - part: {{ part.id }}, - }, -}); - -$("#part-order2").click(function() { - launchModalForm("{% url 'order-parts' %}", { - data: { - part: {{ part.id }}, - }, - reload: true, - }); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index e7ec892628..efbd7d2b0b 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -421,80 +421,7 @@ $("#part-edit").click(function() { - constructForm('{% url "api-part-detail" part.id %}', { - focus: 'name', - fields: { - category: { - secondary: { - label: '{% trans "New Category" %}', - title: '{% trans "Create New Part Category" %}', - api_url: '{% url "api-part-category-list" %}', - method: 'POST', - fields: { - name: {}, - description: {}, - parent: { - secondary: { - title: '{% trans "New Parent" %}', - api_url: '{% url "api-part-category-list" %}', - method: 'POST', - fields: { - name: {}, - description: {}, - parent: {}, - } - } - }, - } - }, - }, - name: { - placeholder: 'part name', - }, - IPN: {}, - description: {}, - revision: {}, - keywords: { - icon: 'fa-key', - }, - variant_of: {}, - link: { - icon: 'fa-link', - }, - default_location: { - secondary: { - label: '{% trans "New Location" %}', - title: '{% trans "Create new stock location" %}', - - }, - }, - default_supplier: { - filters: { - part: {{ part.pk }}, - part_detail: true, - manufacturer_detail: true, - supplier_detail: true, - }, - secondary: { - label: '{% trans "New Supplier Part" %}', - title: '{% trans "Create new supplier part" %}', - } - }, - units: {}, - minimum_stock: {}, - }, - title: '{% trans "Edit Part" %}', - reload: true, - }); - - return; - - launchModalForm( - "{% url 'part-edit' part.id %}", - { - reload: true, - } - ); + editPart({{ part.pk }}); }); {% endif %} diff --git a/InvenTree/part/templates/part/sales_orders.html b/InvenTree/part/templates/part/sales_orders.html deleted file mode 100644 index fa8d5dfd8a..0000000000 --- a/InvenTree/part/templates/part/sales_orders.html +++ /dev/null @@ -1,41 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='sales-orders' %} -{% endblock %} - -{% block heading %} -{% trans "Sales Orders" %} -{% endblock %} - -{% block details %} - -
          -
          - {% if 0 %} - - {% endif %} -
          - -
          -
          -
          - - -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadSalesOrderTable($("#sales-order-table"), { - url: "{% url 'api-so-list' %}", - params: { - part: {{ part.id }}, - }, -}); - -{% endblock %} diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 3b6b245231..9779aac544 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -158,21 +158,6 @@ class PartDetailTest(PartViewTestCase): class PartTests(PartViewTestCase): """ Tests for Part forms """ - def test_part_edit(self): - - response = self.client.get(reverse('part-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') - - keys = response.context.keys() - data = str(response.content) - - self.assertEqual(response.status_code, 200) - - self.assertIn('part', keys) - self.assertIn('csrf_token', keys) - - self.assertIn('html_form', data) - self.assertIn('"title":', data) - def test_part_create(self): """ Launch form to create a new part """ response = self.client.get(reverse('part-create'), {'category': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 8aa254e126..7ea4ca4eff 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -36,7 +36,6 @@ part_parameter_urls = [ ] part_detail_urls = [ - url(r'^edit/?', views.PartEdit.as_view(), name='part-edit'), url(r'^delete/?', views.PartDelete.as_view(), name='part-delete'), url(r'^bom-export/?', views.BomExport.as_view(), name='bom-export'), url(r'^bom-download/?', views.BomDownload.as_view(), name='bom-download'), @@ -55,8 +54,6 @@ part_detail_urls = [ url(r'^used/?', views.PartDetail.as_view(template_name='part/used_in.html'), name='part-used-in'), url(r'^prices/', views.PartPricingView.as_view(template_name='part/prices.html'), name='part-prices'), url(r'^suppliers/?', views.PartDetail.as_view(template_name='part/supplier.html'), name='part-suppliers'), - url(r'^orders/?', views.PartDetail.as_view(template_name='part/orders.html'), name='part-orders'), - url(r'^sales-orders/', views.PartDetail.as_view(template_name='part/sales_orders.html'), name='part-sales-orders'), url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), url(r'^related-parts/?', views.PartDetail.as_view(template_name='part/related.html'), name='part-related'), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 4acf5fcdb6..1ebd37a469 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -1084,40 +1084,6 @@ class PartImageSelect(AjaxUpdateView): return self.renderJsonResponse(request, form, data) -class PartEdit(AjaxUpdateView): - """ View for editing Part object """ - - model = Part - form_class = part_forms.EditPartForm - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Edit Part Properties') - context_object_name = 'part' - - def get_form(self): - """ Create form for Part editing. - Overrides default get_form() method to limit the choices - for the 'default_supplier' field to SupplierParts that reference this part - """ - - form = super(AjaxUpdateView, self).get_form() - - # Hide the "default expiry" field if the feature is not enabled - if not inventree_settings.stock_expiry_enabled(): - form.fields['default_expiry'].widget = HiddenInput() - - part = self.get_object() - - form.fields['default_supplier'].queryset = SupplierPart.objects.filter(part=part) - - # Check if IPN can be edited - ipn_edit_enable = InvenTreeSetting.get_setting('PART_ALLOW_EDIT_IPN') - if not ipn_edit_enable and not self.request.user.is_superuser: - # Admin can still change IPN - form.fields['IPN'].disabled = True - - return form - - class BomDuplicate(AjaxUpdateView): """ View for duplicating BOM from a parent item. diff --git a/InvenTree/templates/js/nav.js b/InvenTree/templates/js/nav.js index 7dc562b8ef..f33571d584 100644 --- a/InvenTree/templates/js/nav.js +++ b/InvenTree/templates/js/nav.js @@ -56,15 +56,10 @@ function activatePanel(panelName, options={}) { // Iterate through the available 'select' elements until one matches panelName = null; - console.log("no match for panel:", panelName); - $('.nav-toggle').each(function(item) { var panel_name = $(this).attr('id').replace('select-', ''); - console.log("checking:", panel_name); - if ($(`#panel-${panel_name}`).length && (panelName == null)) { - console.log("found match -", panel_name); panelName = panel_name; } diff --git a/InvenTree/templates/js/part.js b/InvenTree/templates/js/part.js index e106098ad4..7f034682de 100644 --- a/InvenTree/templates/js/part.js +++ b/InvenTree/templates/js/part.js @@ -13,6 +13,94 @@ function yesNoLabel(value) { } } + +function editPart(pk, options={}) { + + var url = `/api/part/${pk}/`; + + var fields = { + category: { + /* + secondary: { + label: '{% trans "New Category" %}', + title: '{% trans "Create New Part Category" %}', + api_url: '{% url "api-part-category-list" %}', + method: 'POST', + fields: { + name: {}, + description: {}, + parent: { + secondary: { + title: '{% trans "New Parent" %}', + api_url: '{% url "api-part-category-list" %}', + method: 'POST', + fields: { + name: {}, + description: {}, + parent: {}, + } + } + }, + } + }, + */ + }, + name: { + placeholder: 'part name', + }, + IPN: {}, + description: {}, + revision: {}, + keywords: { + icon: 'fa-key', + }, + variant_of: {}, + link: { + icon: 'fa-link', + }, + default_location: { + /* + secondary: { + label: '{% trans "New Location" %}', + title: '{% trans "Create new stock location" %}', + }, + */ + }, + default_supplier: { + filters: { + part: pk, + part_detail: true, + manufacturer_detail: true, + supplier_detail: true, + }, + /* + secondary: { + label: '{% trans "New Supplier Part" %}', + title: '{% trans "Create new supplier part" %}', + } + */ + }, + units: {}, + minimum_stock: {}, + virtual: {}, + is_template: {}, + assembly: {}, + component: {}, + trackable: {}, + purchaseable: {}, + salable: {}, + active: {}, + }; + + constructForm(url, { + fields: fields, + title: '{% trans "Edit Part" %}', + reload: true, + }); + +} + + function toggleStar(options) { /* Toggle the 'starred' status of a part. * Performs AJAX queries and updates the display on the button. From 84149d34a691e483ac475c7593c9de7ce092c2ce Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 16:12:27 +1000 Subject: [PATCH 398/445] Refactor part-supplier view --- .../company/manufacturer_part_base.html | 2 +- .../templates/company/supplier_part_base.html | 2 +- .../company/supplier_part_detail.html | 2 +- InvenTree/part/templates/part/detail.html | 150 +++++++++++++++ InvenTree/part/templates/part/supplier.html | 171 ------------------ InvenTree/part/urls.py | 1 - 6 files changed, 153 insertions(+), 175 deletions(-) delete mode 100644 InvenTree/part/templates/part/supplier.html diff --git a/InvenTree/company/templates/company/manufacturer_part_base.html b/InvenTree/company/templates/company/manufacturer_part_base.html index ed1612ea76..f68bf99122 100644 --- a/InvenTree/company/templates/company/manufacturer_part_base.html +++ b/InvenTree/company/templates/company/manufacturer_part_base.html @@ -62,7 +62,7 @@ src="{% static 'img/blank_image.png' %}" {% trans "Internal Part" %} {% if part.part %} -
          {{ part.part.full_name }}{% include "clip.html"%} + {{ part.part.full_name }}{% include "clip.html"%} {% endif %} diff --git a/InvenTree/company/templates/company/supplier_part_base.html b/InvenTree/company/templates/company/supplier_part_base.html index bf6d914f19..8b6a5d94cd 100644 --- a/InvenTree/company/templates/company/supplier_part_base.html +++ b/InvenTree/company/templates/company/supplier_part_base.html @@ -61,7 +61,7 @@ src="{% static 'img/blank_image.png' %}" {% trans "Internal Part" %} {% if part.part %} - {{ part.part.full_name }}{% include "clip.html"%} + {{ part.part.full_name }}{% include "clip.html"%} {% endif %} diff --git a/InvenTree/company/templates/company/supplier_part_detail.html b/InvenTree/company/templates/company/supplier_part_detail.html index fb73ca06f4..6ccfc43e3f 100644 --- a/InvenTree/company/templates/company/supplier_part_detail.html +++ b/InvenTree/company/templates/company/supplier_part_detail.html @@ -18,7 +18,7 @@ {% trans "Internal Part" %} {% if part.part %} - {{ part.part.full_name }} + {{ part.part.full_name }} {% endif %} diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 5b377708f6..3eedc54798 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -134,6 +134,54 @@
          +
          +
          +

          {% trans "Part Suppliers" %}

          +
          +
          +
          +
          + +
          + + +
          +
          +
          + + +
          +
          +
          + +
          +
          +

          {% trans "Part Manufacturers" %}

          +
          +
          +
          +
          +
          + +
          + + +
          +
          +
          +
          +
          +
          +
          + {% endblock %} {% block js_load %} @@ -426,4 +474,106 @@ default: 'part-stock' }); + $('#supplier-create').click(function () { + launchModalForm( + "{% url 'supplier-part-create' %}", + { + reload: true, + data: { + part: {{ part.id }} + }, + secondary: [ + { + field: 'supplier', + label: '{% trans "New Supplier" %}', + title: '{% trans "Create new supplier" %}', + }, + { + field: 'manufacturer', + label: '{% trans "New Manufacturer" %}', + title: '{% trans "Create new manufacturer" %}', + } + ] + }); + }); + + $("#supplier-part-delete").click(function() { + + var selections = $("#supplier-table").bootstrapTable("getSelections"); + + var parts = []; + + selections.forEach(function(item) { + parts.push(item.pk); + }); + + launchModalForm("{% url 'supplier-part-delete' %}", { + data: { + parts: parts, + }, + reload: true, + }); + }); + + loadSupplierPartTable( + "#supplier-table", + "{% url 'api-supplier-part-list' %}", + { + params: { + part: {{ part.id }}, + part_detail: false, + supplier_detail: true, + manufacturer_detail: true, + }, + } + ); + + linkButtonsToSelection($("#supplier-table"), ['#supplier-part-options']); + + loadManufacturerPartTable( + '#manufacturer-table', + "{% url 'api-manufacturer-part-list' %}", + { + params: { + part: {{ part.id }}, + part_detail: true, + manufacturer_detail: true, + }, + } + ); + + linkButtonsToSelection($("#manufacturer-table"), ['#manufacturer-part-options']); + + $("#manufacturer-part-delete").click(function() { + + var selections = $("#manufacturer-table").bootstrapTable("getSelections"); + + deleteManufacturerParts(selections, { + onSuccess: function() { + $("#manufacturer-table").bootstrapTable("refresh"); + } + }); + }); + + $('#manufacturer-create').click(function () { + + constructForm('{% url "api-manufacturer-part-list" %}', { + fields: { + part: { + value: {{ part.pk }}, + hidden: true, + }, + manufacturer: {}, + MPN: {}, + description: {}, + link: {}, + }, + method: 'POST', + title: '{% trans "Add Manufacturer Part" %}', + onSuccess: function() { + $("#manufacturer-table").bootstrapTable("refresh"); + } + }); + }); + {% endblock %} diff --git a/InvenTree/part/templates/part/supplier.html b/InvenTree/part/templates/part/supplier.html deleted file mode 100644 index 8ae73cd07c..0000000000 --- a/InvenTree/part/templates/part/supplier.html +++ /dev/null @@ -1,171 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='suppliers' %} -{% endblock %} - - -{% block heading %} -{% trans "Part Suppliers" %} -{% endblock %} - -{% block details %} -
          -
          - -
          - - -
          -
          -
          - - -
          - -{% endblock %} - -{% block post_content_panel %} - -
          -
          -

          - {% trans "Part Manufacturers" %} -

          -
          - -
          -
          -
          - -
          - - -
          -
          -
          -
          -
          -
          - -{% endblock %} - -{% block js_load %} -{{ block.super }} -{% endblock %} -{% block js_ready %} - {{ block.super }} - - $('#supplier-create').click(function () { - launchModalForm( - "{% url 'supplier-part-create' %}", - { - reload: true, - data: { - part: {{ part.id }} - }, - secondary: [ - { - field: 'supplier', - label: '{% trans "New Supplier" %}', - title: '{% trans "Create new supplier" %}', - }, - { - field: 'manufacturer', - label: '{% trans "New Manufacturer" %}', - title: '{% trans "Create new manufacturer" %}', - } - ] - }); - }); - - $("#supplier-part-delete").click(function() { - - var selections = $("#supplier-table").bootstrapTable("getSelections"); - - var parts = []; - - selections.forEach(function(item) { - parts.push(item.pk); - }); - - launchModalForm("{% url 'supplier-part-delete' %}", { - data: { - parts: parts, - }, - reload: true, - }); - }); - - loadSupplierPartTable( - "#supplier-table", - "{% url 'api-supplier-part-list' %}", - { - params: { - part: {{ part.id }}, - part_detail: false, - supplier_detail: true, - manufacturer_detail: true, - }, - } - ); - - linkButtonsToSelection($("#supplier-table"), ['#supplier-part-options']); - - loadManufacturerPartTable( - '#manufacturer-table', - "{% url 'api-manufacturer-part-list' %}", - { - params: { - part: {{ part.id }}, - part_detail: true, - manufacturer_detail: true, - }, - } - ); - - linkButtonsToSelection($("#manufacturer-table"), ['#manufacturer-part-options']); - - $("#manufacturer-part-delete").click(function() { - - var selections = $("#manufacturer-table").bootstrapTable("getSelections"); - - deleteManufacturerParts(selections, { - onSuccess: function() { - $("#manufacturer-table").bootstrapTable("refresh"); - } - }); - }); - - $('#manufacturer-create').click(function () { - - constructForm('{% url "api-manufacturer-part-list" %}', { - fields: { - part: { - value: {{ part.pk }}, - hidden: true, - }, - manufacturer: {}, - MPN: {}, - description: {}, - link: {}, - }, - method: 'POST', - title: '{% trans "Add Manufacturer Part" %}', - onSuccess: function() { - $("#manufacturer-table").bootstrapTable("refresh"); - } - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 7ea4ca4eff..1ab9a44c4b 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -53,7 +53,6 @@ part_detail_urls = [ url(r'^build/?', views.PartDetail.as_view(template_name='part/build.html'), name='part-build'), url(r'^used/?', views.PartDetail.as_view(template_name='part/used_in.html'), name='part-used-in'), url(r'^prices/', views.PartPricingView.as_view(template_name='part/prices.html'), name='part-prices'), - url(r'^suppliers/?', views.PartDetail.as_view(template_name='part/supplier.html'), name='part-suppliers'), url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), url(r'^related-parts/?', views.PartDetail.as_view(template_name='part/related.html'), name='part-related'), From 985bd392341b7a481bce855fe512b166ec6ca2aa Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 16:14:48 +1000 Subject: [PATCH 399/445] Fix links --- .../company/templates/company/manufacturer_part_base.html | 4 ++-- .../company/templates/company/manufacturer_part_detail.html | 4 ++-- InvenTree/company/templates/company/supplier_part_base.html | 6 +++--- .../company/templates/company/supplier_part_detail.html | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/InvenTree/company/templates/company/manufacturer_part_base.html b/InvenTree/company/templates/company/manufacturer_part_base.html index f68bf99122..c54401b172 100644 --- a/InvenTree/company/templates/company/manufacturer_part_base.html +++ b/InvenTree/company/templates/company/manufacturer_part_base.html @@ -83,7 +83,7 @@ src="{% static 'img/blank_image.png' %}" {% trans "Manufacturer" %} - {{ part.manufacturer.name }}{% include "clip.html"%} + {{ part.manufacturer.name }}{% include "clip.html"%} {% trans "MPN" %} @@ -136,7 +136,7 @@ $('#delete-part').click(function() { constructForm('{% url "api-manufacturer-part-detail" part.pk %}', { method: 'DELETE', title: '{% trans "Delete Manufacturer Part" %}', - redirect: "{% url 'company-detail-manufacturer-parts' part.manufacturer.id %}", + redirect: "{% url 'company-detail' part.manufacturer.id %}", }); }); diff --git a/InvenTree/company/templates/company/manufacturer_part_detail.html b/InvenTree/company/templates/company/manufacturer_part_detail.html index 3bc789e6b9..e25fb9dca3 100644 --- a/InvenTree/company/templates/company/manufacturer_part_detail.html +++ b/InvenTree/company/templates/company/manufacturer_part_detail.html @@ -18,11 +18,11 @@ {% trans "Internal Part" %} {% if part.part %} - {{ part.part.full_name }} + {{ part.part.full_name }} {% endif %} - {% trans "Manufacturer" %}{{ part.manufacturer.name }} + {% trans "Manufacturer" %}{{ part.manufacturer.name }} {% trans "MPN" %}{{ part.MPN }} {% if part.link %} {% trans "External Link" %}{{ part.link }} diff --git a/InvenTree/company/templates/company/supplier_part_base.html b/InvenTree/company/templates/company/supplier_part_base.html index 8b6a5d94cd..900e0750cc 100644 --- a/InvenTree/company/templates/company/supplier_part_base.html +++ b/InvenTree/company/templates/company/supplier_part_base.html @@ -82,7 +82,7 @@ src="{% static 'img/blank_image.png' %}" {% trans "Supplier" %} - {{ part.supplier.name }}{% include "clip.html"%} + {{ part.supplier.name }}{% include "clip.html"%} {% trans "SKU" %} @@ -92,7 +92,7 @@ src="{% static 'img/blank_image.png' %}" {% trans "Manufacturer" %} - + {{ part.manufacturer_part.manufacturer.name }}{% include "clip.html"%} {% endif %} @@ -153,7 +153,7 @@ $('#delete-part').click(function() { launchModalForm( "{% url 'supplier-part-delete' %}?part={{ part.id }}", { - redirect: "{% url 'company-detail-supplier-parts' part.supplier.id %}" + redirect: "{% url 'company-detail' part.supplier.id %}" } ); }); diff --git a/InvenTree/company/templates/company/supplier_part_detail.html b/InvenTree/company/templates/company/supplier_part_detail.html index 6ccfc43e3f..708885043a 100644 --- a/InvenTree/company/templates/company/supplier_part_detail.html +++ b/InvenTree/company/templates/company/supplier_part_detail.html @@ -22,7 +22,7 @@ {% endif %} - {% trans "Supplier" %}{{ part.supplier.name }} + {% trans "Supplier" %}{{ part.supplier.name }} {% trans "SKU" %}{{ part.SKU }} {% if part.link %} {% trans "External Link" %}{{ part.link }} From 8607d702c4c7b439aae29fc9764200ea7ec13362 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 16:17:41 +1000 Subject: [PATCH 400/445] Refactor variants page --- InvenTree/part/templates/part/detail.html | 36 ++++++++++++++ InvenTree/part/templates/part/navbar.html | 2 +- InvenTree/part/templates/part/part_base.html | 2 +- InvenTree/part/templates/part/variants.html | 49 -------------------- InvenTree/part/urls.py | 1 - 5 files changed, 38 insertions(+), 52 deletions(-) delete mode 100644 InvenTree/part/templates/part/variants.html diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 3eedc54798..1c1dc4569f 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -107,6 +107,31 @@
          +
          +
          +

          {% trans "Part Variants" %}

          +
          +
          +
          +
          +
          + {% if part.is_template and part.active %} + + {% endif %} +
          +
          + +
          +
          +
          + + +
          +
          +
          +

          {% trans "Parameters" %}

          @@ -191,6 +216,17 @@ {% block js_ready %} {{ block.super }} + loadPartVariantTable($('#variants-table'), {{ part.pk }}); + + $('#new-variant').click(function() { + launchModalForm( + "{% url 'make-part-variant' part.id %}", + { + follow: true, + } + ); + }); + loadPurchaseOrderTable($("#purchase-order-table"), { url: "{% url 'api-po-list' %}", params: { diff --git a/InvenTree/part/templates/part/navbar.html b/InvenTree/part/templates/part/navbar.html index d634229500..dbd9423a02 100644 --- a/InvenTree/part/templates/part/navbar.html +++ b/InvenTree/part/templates/part/navbar.html @@ -19,7 +19,7 @@ {% if part.is_template %}
        • - + {% trans "Variants" %} diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index efbd7d2b0b..2437662cba 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -167,7 +167,7 @@ {% endif %} {% if part.variant_of %}
          - {% object_link 'part-variants' part.variant_of.id part.variant_of.full_name as link %} + {% object_link 'part-detail' part.variant_of.id part.variant_of.full_name as link %} {% blocktrans %}This part is a variant of {{link}}{% endblocktrans %}
          {% endif %} diff --git a/InvenTree/part/templates/part/variants.html b/InvenTree/part/templates/part/variants.html deleted file mode 100644 index 11a548ba49..0000000000 --- a/InvenTree/part/templates/part/variants.html +++ /dev/null @@ -1,49 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include "part/navbar.html" with tab='variants' %} -{% endblock %} - -{% block heading %} -{% trans "Part Variants" %} -{% endblock %} - -{% block details %} -
          -
          -
          - {% if part.is_template and part.active %} - - {% endif %} -
          -
          - -
          -
          -
          - - -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - loadPartVariantTable($('#variants-table'), {{ part.pk }}); - - $('#new-variant').click(function() { - launchModalForm( - "{% url 'make-part-variant' part.id %}", - { - follow: true, - } - ); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 1ab9a44c4b..b483c1e7a3 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -47,7 +47,6 @@ part_detail_urls = [ url(r'^bom-upload/?', views.BomUpload.as_view(), name='upload-bom'), url(r'^bom-duplicate/?', views.BomDuplicate.as_view(), name='duplicate-bom'), - url(r'^variants/?', views.PartDetail.as_view(template_name='part/variants.html'), name='part-variants'), url(r'^allocation/?', views.PartDetail.as_view(template_name='part/allocation.html'), name='part-allocation'), url(r'^bom/?', views.PartDetail.as_view(template_name='part/bom.html'), name='part-bom'), url(r'^build/?', views.PartDetail.as_view(template_name='part/build.html'), name='part-build'), From c8c7f78ce903a5957ef3b6e6fdcb507a25cf3fb6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 16:28:26 +1000 Subject: [PATCH 401/445] Refactor "related parts" view --- InvenTree/part/templates/part/detail.html | 66 ++++++++++++++++++ InvenTree/part/templates/part/related.html | 80 ---------------------- InvenTree/part/urls.py | 1 - 3 files changed, 66 insertions(+), 81 deletions(-) delete mode 100644 InvenTree/part/templates/part/related.html diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 1c1dc4569f..8910766972 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -159,6 +159,52 @@
        • + +

          {% trans "Part Suppliers" %}

          @@ -216,6 +262,26 @@ {% block js_ready %} {{ block.super }} + $('#table-related-part').inventreeTable({ + }); + + $("#add-related-part").click(function() { + launchModalForm("{% url 'part-related-create' %}", { + data: { + part: {{ part.id }}, + }, + reload: true, + }); + }); + + $('.delete-related-part').click(function() { + var button = $(this); + + launchModalForm(button.attr('url'), { + reload: true, + }); + }); + loadPartVariantTable($('#variants-table'), {{ part.pk }}); $('#new-variant').click(function() { diff --git a/InvenTree/part/templates/part/related.html b/InvenTree/part/templates/part/related.html deleted file mode 100644 index 77c2e1bc9f..0000000000 --- a/InvenTree/part/templates/part/related.html +++ /dev/null @@ -1,80 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='related' %} -{% endblock %} - -{% block heading %} -{% trans "Related Parts" %} -{% endblock %} - -{% block details %} - -
          -
          - {% if roles.part.change %} - - - {% endif %} -
          -
          - - - - - - - - - {% for item in part.get_related_parts %} - {% with part_related=item.0 part=item.1 %} - - - - {% endwith %} - {% endfor %} - - - - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - $('#table-related-part').inventreeTable({ - }); - - $("#add-related-part").click(function() { - launchModalForm("{% url 'part-related-create' %}", { - data: { - part: {{ part.id }}, - }, - reload: true, - }); - }); - - $('.delete-related-part').click(function() { - var button = $(this); - - launchModalForm(button.attr('url'), { - reload: true, - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index b483c1e7a3..3d50e64261 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -53,7 +53,6 @@ part_detail_urls = [ url(r'^used/?', views.PartDetail.as_view(template_name='part/used_in.html'), name='part-used-in'), url(r'^prices/', views.PartPricingView.as_view(template_name='part/prices.html'), name='part-prices'), url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), - url(r'^related-parts/?', views.PartDetail.as_view(template_name='part/related.html'), name='part-related'), url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'), From 57851b0eaf88029fc0eb044a43fdf4e1d11bf10f Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 16:36:20 +1000 Subject: [PATCH 402/445] Refactor build orders display --- .../build/templates/build/build_base.html | 2 +- InvenTree/build/templates/build/detail.html | 2 +- InvenTree/part/templates/part/build.html | 48 ------------------- InvenTree/part/templates/part/detail.html | 36 ++++++++++++++ InvenTree/part/urls.py | 1 - 5 files changed, 38 insertions(+), 51 deletions(-) delete mode 100644 InvenTree/part/templates/part/build.html diff --git a/InvenTree/build/templates/build/build_base.html b/InvenTree/build/templates/build/build_base.html index ece6de36bb..7100e82838 100644 --- a/InvenTree/build/templates/build/build_base.html +++ b/InvenTree/build/templates/build/build_base.html @@ -126,7 +126,7 @@ src="{% static 'img/blank_image.png' %}" {% trans "Part" %} - {{ build.part.full_name }} + {{ build.part.full_name }} diff --git a/InvenTree/build/templates/build/detail.html b/InvenTree/build/templates/build/detail.html index 1b4c577b07..63c04f7590 100644 --- a/InvenTree/build/templates/build/detail.html +++ b/InvenTree/build/templates/build/detail.html @@ -24,7 +24,7 @@ {% trans "Part" %} - {{ build.part.full_name }}{% include "clip.html"%} + {{ build.part.full_name }}{% include "clip.html"%} diff --git a/InvenTree/part/templates/part/build.html b/InvenTree/part/templates/part/build.html deleted file mode 100644 index 29f32c770a..0000000000 --- a/InvenTree/part/templates/part/build.html +++ /dev/null @@ -1,48 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='build' %} -{% endblock %} - -{% block heading %} -{% trans "Part Builds" %} -{% endblock %} - -{% block details %} -
          -
          - {% if part.active %} - {% if roles.build.add %} - - {% endif %} - {% endif %} -
          - -
          -
          -
          - - -
          - - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - $("#start-build").click(function() { - newBuildOrder({ - part: {{ part.pk }}, - }); - }); - - loadBuildTable($("#build-table"), { - url: "{% url 'api-build-list' %}", - params: { - part: {{ part.id }}, - } - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 8910766972..afef20d714 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -229,6 +229,29 @@
          +
          +
          +

          {% trans "Part Builds" %}

          +
          +
          +
          +
          + {% if part.active %} + {% if roles.build.add %} + + {% endif %} + {% endif %} +
          + +
          +
          +
          + + +
          +
          +
          +

          {% trans "Part Manufacturers" %}

          @@ -262,6 +285,19 @@ {% block js_ready %} {{ block.super }} + $("#start-build").click(function() { + newBuildOrder({ + part: {{ part.pk }}, + }); + }); + + loadBuildTable($("#build-table"), { + url: "{% url 'api-build-list' %}", + params: { + part: {{ part.id }}, + } + }); + $('#table-related-part').inventreeTable({ }); diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 3d50e64261..3cf96604e4 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -49,7 +49,6 @@ part_detail_urls = [ url(r'^allocation/?', views.PartDetail.as_view(template_name='part/allocation.html'), name='part-allocation'), url(r'^bom/?', views.PartDetail.as_view(template_name='part/bom.html'), name='part-bom'), - url(r'^build/?', views.PartDetail.as_view(template_name='part/build.html'), name='part-build'), url(r'^used/?', views.PartDetail.as_view(template_name='part/used_in.html'), name='part-used-in'), url(r'^prices/', views.PartPricingView.as_view(template_name='part/prices.html'), name='part-prices'), url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), From e7c7bdcd00fcc3f73b28a20ca1b008c296d3a2a3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 16:42:28 +1000 Subject: [PATCH 403/445] Refactor BOM page --- InvenTree/part/templates/part/bom.html | 144 +--------------------- InvenTree/part/templates/part/detail.html | 127 +++++++++++++++++++ InvenTree/part/templates/part/navbar.html | 2 +- InvenTree/part/views.py | 2 +- 4 files changed, 133 insertions(+), 142 deletions(-) diff --git a/InvenTree/part/templates/part/bom.html b/InvenTree/part/templates/part/bom.html index 048b98fc01..4376c23ab9 100644 --- a/InvenTree/part/templates/part/bom.html +++ b/InvenTree/part/templates/part/bom.html @@ -1,16 +1,5 @@ -{% extends "part/part_base.html" %} -{% load static %} {% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='bom' %} -{% endblock %} - -{% block heading %} -{% trans "Bill of Materials" %} -{% endblock %} - -{% block details %} +{% load inventree_extras %} {% if roles.part.change != True and editing_enabled %}
          @@ -32,7 +21,7 @@
          {% endif %} -
          +
          {% if editing_enabled %}
          - +
          -{% endif %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - // Load the BOM table data - loadBomTable($("#bom-table"), { - editable: {{ editing_enabled }}, - bom_url: "{% url 'api-bom-list' %}", - part_url: "{% url 'api-part-list' %}", - parent_id: {{ part.id }} , - sub_part_detail: true, - }); - - linkButtonsToSelection($("#bom-table"), - [ - "#bom-item-delete", - ] - ); - - {% if editing_enabled %} - $("#editing-finished").click(function() { - location.href = "{% url 'part-bom' part.id %}"; - }); - - $('#bom-item-delete').click(function() { - - // Get a list of the selected BOM items - var rows = $("#bom-table").bootstrapTable('getSelections'); - - // TODO - In the future, display (in the dialog) which items are going to be deleted - - showQuestionDialog( - '{% trans "Delete selected BOM items?" %}', - '{% trans "All selected BOM items will be deleted" %}', - { - accept: function() { - - // Keep track of each DELETE request - var requests = []; - - rows.forEach(function(row) { - requests.push( - inventreeDelete( - `/api/bom/${row.pk}/`, - ) - ); - }); - - // Wait for *all* the requests to complete - $.when.apply($, requests).then(function() { - location.reload(); - }); - } - } - ); - }); - - $('#bom-upload').click(function() { - location.href = "{% url 'upload-bom' part.id %}"; - }); - - $('#bom-duplicate').click(function() { - launchModalForm( - "{% url 'duplicate-bom' part.id %}", - { - success: function() { - $('#bom-table').bootstrapTable('refresh'); - } - } - ); - }); - - $("#bom-item-new").click(function () { - launchModalForm( - "{% url 'bom-item-create' %}?parent={{ part.id }}", - { - success: function() { - $("#bom-table").bootstrapTable('refresh'); - }, - secondary: [ - { - field: 'sub_part', - label: '{% trans "New Part" %}', - title: '{% trans "Create New Part" %}', - url: "{% url 'part-create' %}", - }, - ] - } - ); - }); - - {% else %} - - $("#validate-bom").click(function() { - launchModalForm( - "{% url 'bom-validate' part.id %}", - { - reload: true, - } - ); - }); - - $("#edit-bom").click(function () { - location.href = "{% url 'part-bom' part.id %}?edit=1"; - }); - - $("#download-bom").click(function () { - launchModalForm("{% url 'bom-export' part.id %}", - { - success: function(response) { - location.href = response.url; - }, - } - ); - }); - - {% endif %} - - $("#print-bom-report").click(function() { - printBomReports([{{ part.pk }}]); - }); - -{% endblock %} +{% endif %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index afef20d714..3def22cf03 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -229,6 +229,15 @@
          +
          +
          +

          {% trans "Bill of Materials" %}

          +
          +
          + {% include "part/bom.html" with part=part %} +
          +
          +

          {% trans "Part Builds" %}

          @@ -285,6 +294,124 @@ {% block js_ready %} {{ block.super }} + // Load the BOM table data + loadBomTable($("#bom-table"), { + editable: {{ editing_enabled }}, + bom_url: "{% url 'api-bom-list' %}", + part_url: "{% url 'api-part-list' %}", + parent_id: {{ part.id }} , + sub_part_detail: true, + }); + + linkButtonsToSelection($("#bom-table"), + [ + "#bom-item-delete", + ] + ); + + {% if editing_enabled %} + $("#editing-finished").click(function() { + location.href = "{% url 'part-detail' part.id %}?display=bom"; + }); + + $('#bom-item-delete').click(function() { + + // Get a list of the selected BOM items + var rows = $("#bom-table").bootstrapTable('getSelections'); + + // TODO - In the future, display (in the dialog) which items are going to be deleted + + showQuestionDialog( + '{% trans "Delete selected BOM items?" %}', + '{% trans "All selected BOM items will be deleted" %}', + { + accept: function() { + + // Keep track of each DELETE request + var requests = []; + + rows.forEach(function(row) { + requests.push( + inventreeDelete( + `/api/bom/${row.pk}/`, + ) + ); + }); + + // Wait for *all* the requests to complete + $.when.apply($, requests).then(function() { + location.reload(); + }); + } + } + ); + }); + + $('#bom-upload').click(function() { + location.href = "{% url 'upload-bom' part.id %}"; + }); + + $('#bom-duplicate').click(function() { + launchModalForm( + "{% url 'duplicate-bom' part.id %}", + { + success: function() { + $('#bom-table').bootstrapTable('refresh'); + } + } + ); + }); + + $("#bom-item-new").click(function () { + launchModalForm( + "{% url 'bom-item-create' %}?parent={{ part.id }}", + { + success: function() { + $("#bom-table").bootstrapTable('refresh'); + }, + secondary: [ + { + field: 'sub_part', + label: '{% trans "New Part" %}', + title: '{% trans "Create New Part" %}', + url: "{% url 'part-create' %}", + }, + ] + } + ); + }); + + {% else %} + + $("#validate-bom").click(function() { + launchModalForm( + "{% url 'bom-validate' part.id %}", + { + reload: true, + } + ); + }); + + $("#edit-bom").click(function () { + location.href = "{% url 'part-detail' part.id %}?display=bom&edit=1"; + }); + + $("#download-bom").click(function () { + launchModalForm("{% url 'bom-export' part.id %}", + { + success: function(response) { + location.href = response.url; + }, + } + ); + }); + + {% endif %} + + $("#print-bom-report").click(function() { + printBomReports([{{ part.pk }}]); + }); + $("#start-build").click(function() { newBuildOrder({ part: {{ part.pk }}, diff --git a/InvenTree/part/templates/part/navbar.html b/InvenTree/part/templates/part/navbar.html index dbd9423a02..e9d11207ed 100644 --- a/InvenTree/part/templates/part/navbar.html +++ b/InvenTree/part/templates/part/navbar.html @@ -41,7 +41,7 @@ {% endif %} {% if part.assembly %}
        • - + {% trans "Bill of Materials" %} diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 1ebd37a469..bf8c32ba78 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -1441,7 +1441,7 @@ class BomUpload(InvenTreeRoleMixin, FileManagementFormView): # BomItem already exists pass - return HttpResponseRedirect(reverse('part-bom', kwargs={'pk': self.kwargs['pk']})) + return HttpResponseRedirect(reverse('part-detail', kwargs={'pk': self.kwargs['pk']})) class PartExport(AjaxView): From e38d740bbc4ab59e4e5be1cd34affdbce378c932 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 16:44:46 +1000 Subject: [PATCH 404/445] Refactor "used in" page --- InvenTree/part/templates/part/detail.html | 26 +++++++++++++++ InvenTree/part/templates/part/used_in.html | 39 ---------------------- InvenTree/part/urls.py | 2 -- 3 files changed, 26 insertions(+), 41 deletions(-) delete mode 100644 InvenTree/part/templates/part/used_in.html diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 3def22cf03..6949879aa4 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -238,6 +238,22 @@
        • +
          +
          +

          {% trans "Assemblies" %}

          +
          +
          +
          +
          + +
          +
          + + +
          +
          +
          +

          {% trans "Part Builds" %}

          @@ -294,6 +310,16 @@ {% block js_ready %} {{ block.super }} + loadPartTable('#used-table', + '{% url "api-part-list" %}', + { + params: { + uses: {{ part.pk }}, + }, + filterTarget: '#filter-list-usedin', + } + ); + // Load the BOM table data loadBomTable($("#bom-table"), { editable: {{ editing_enabled }}, diff --git a/InvenTree/part/templates/part/used_in.html b/InvenTree/part/templates/part/used_in.html deleted file mode 100644 index e7d8863d42..0000000000 --- a/InvenTree/part/templates/part/used_in.html +++ /dev/null @@ -1,39 +0,0 @@ -{% extends "part/part_base.html" %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='used' %} -{% endblock %} - -{% block heading %} -{% trans "Assemblies" %} -{% endblock %} - -{% block details %} - -
          -
          - -
          -
          - - -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - loadPartTable('#used-table', - '{% url "api-part-list" %}', - { - params: { - uses: {{ part.pk }}, - }, - filterTarget: '#filter-list-usedin', - } - ); - - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 3cf96604e4..ded9e0b3c4 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -48,8 +48,6 @@ part_detail_urls = [ url(r'^bom-duplicate/?', views.BomDuplicate.as_view(), name='duplicate-bom'), url(r'^allocation/?', views.PartDetail.as_view(template_name='part/allocation.html'), name='part-allocation'), - url(r'^bom/?', views.PartDetail.as_view(template_name='part/bom.html'), name='part-bom'), - url(r'^used/?', views.PartDetail.as_view(template_name='part/used_in.html'), name='part-used-in'), url(r'^prices/', views.PartPricingView.as_view(template_name='part/prices.html'), name='part-prices'), url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), From df8900811650d9ec38ce4f271e7a75273d20862a Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 16:53:14 +1000 Subject: [PATCH 405/445] Refactor allocation page(s) - Also perform null check on notes before displaying --- InvenTree/build/templates/build/notes.html | 2 + .../company/templates/company/detail.html | 2 + .../order/purchase_order_detail.html | 2 + .../templates/order/sales_order_detail.html | 2 + InvenTree/part/templates/part/allocation.html | 50 ------------------- InvenTree/part/templates/part/detail.html | 28 +++++++++++ InvenTree/part/templates/part/navbar.html | 8 --- InvenTree/part/urls.py | 1 - 8 files changed, 36 insertions(+), 59 deletions(-) delete mode 100644 InvenTree/part/templates/part/allocation.html diff --git a/InvenTree/build/templates/build/notes.html b/InvenTree/build/templates/build/notes.html index 8eff2eff10..2bdbf07970 100644 --- a/InvenTree/build/templates/build/notes.html +++ b/InvenTree/build/templates/build/notes.html @@ -31,8 +31,10 @@ {% else %} +{% if build.notes %} {{ build.notes | markdownify }} {% endif %} +{% endif %} {% endblock %} diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html index 1f2bcf3784..105e0f82ae 100644 --- a/InvenTree/company/templates/company/detail.html +++ b/InvenTree/company/templates/company/detail.html @@ -179,7 +179,9 @@
          + {% if company.notes %} {{ company.notes | markdownify }} + {% endif %}
          diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index 8c9feab452..cbff1b2d1c 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -65,7 +65,9 @@
          + {% if order.notes %} {{ order.notes | markdownify }} + {% endif %}
          diff --git a/InvenTree/order/templates/order/sales_order_detail.html b/InvenTree/order/templates/order/sales_order_detail.html index 8ada362092..277c1f4278 100644 --- a/InvenTree/order/templates/order/sales_order_detail.html +++ b/InvenTree/order/templates/order/sales_order_detail.html @@ -64,7 +64,9 @@
          + {% if order.notes %} {{ order.notes | markdownify }} + {% endif %}
          diff --git a/InvenTree/part/templates/part/allocation.html b/InvenTree/part/templates/part/allocation.html deleted file mode 100644 index e78456ea3a..0000000000 --- a/InvenTree/part/templates/part/allocation.html +++ /dev/null @@ -1,50 +0,0 @@ -{% extends "part/part_base.html" %} -{% load status_codes %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include "part/navbar.html" with tab="allocation" %} -{% endblock %} - -{% block heading %} -{% trans "Build Order Allocations" %} -{% endblock %} - -{% block details %} - -
          - -{% endblock %} - -{% block pre_content_panel %} - -
          -
          -

          {% trans "Sales Order Allocations" %}

          -
          - -
          -
          -
          -
          - -{% endblock %} - - -{% block js_ready %} -{{ block.super }} - - loadSalesOrderAllocationTable("#sales-order-table", { - params: { - part: {{ part.id }}, - } - }); - - loadBuildOrderAllocationTable("#build-order-table", { - params: { - part: {{ part.id }}, - } - }); - -{% endblock %} diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 6949879aa4..b44bd25acc 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -84,6 +84,13 @@
          + +
          +

          {% trans "Sales Order Allocations" %}

          +
          +
          +
          +
          @@ -103,7 +110,9 @@
          + {% if part.notes %} {{ part.notes | markdownify }} + {% endif %}
          @@ -275,6 +284,13 @@
          + +
          +

          {% trans "Build Order Allocations" %}

          +
          +
          +
          +
          @@ -310,6 +326,18 @@ {% block js_ready %} {{ block.super }} + loadBuildOrderAllocationTable("#build-order-allocation-table", { + params: { + part: {{ part.id }}, + } + }); + + loadSalesOrderAllocationTable("#sales-order-allocation-table", { + params: { + part: {{ part.id }}, + } + }); + loadPartTable('#used-table', '{% url "api-part-list" %}', { diff --git a/InvenTree/part/templates/part/navbar.html b/InvenTree/part/templates/part/navbar.html index e9d11207ed..4f0e92a80d 100644 --- a/InvenTree/part/templates/part/navbar.html +++ b/InvenTree/part/templates/part/navbar.html @@ -31,14 +31,6 @@ {% trans "Stock" %} - {% if part.component or part.salable %} -
        • - - - {% trans "Allocations" %} - -
        • - {% endif %} {% if part.assembly %}
        • diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index ded9e0b3c4..a2489de058 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -47,7 +47,6 @@ part_detail_urls = [ url(r'^bom-upload/?', views.BomUpload.as_view(), name='upload-bom'), url(r'^bom-duplicate/?', views.BomDuplicate.as_view(), name='duplicate-bom'), - url(r'^allocation/?', views.PartDetail.as_view(template_name='part/allocation.html'), name='part-allocation'), url(r'^prices/', views.PartPricingView.as_view(template_name='part/prices.html'), name='part-prices'), url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), From d5bf108fef39b9e49e88e6496a09e644216710e2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 16:54:49 +1000 Subject: [PATCH 406/445] Remove unused template file --- InvenTree/part/templates/part/track.html | 14 -------------- InvenTree/part/urls.py | 1 - 2 files changed, 15 deletions(-) delete mode 100644 InvenTree/part/templates/part/track.html diff --git a/InvenTree/part/templates/part/track.html b/InvenTree/part/templates/part/track.html deleted file mode 100644 index 8e89419a11..0000000000 --- a/InvenTree/part/templates/part/track.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='track' %} -{% endblock %} - -{% block heading %} -{% trans "Part Tracking" %} -{% endblock %} - -{% block details %} -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index a2489de058..0640807e51 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -48,7 +48,6 @@ part_detail_urls = [ url(r'^bom-duplicate/?', views.BomDuplicate.as_view(), name='duplicate-bom'), url(r'^prices/', views.PartPricingView.as_view(template_name='part/prices.html'), name='part-prices'), - url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'), From 72337dab49e12e7be1c246a2854c991046760e87 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 17:26:06 +1000 Subject: [PATCH 407/445] Refactor PartCategory views --- InvenTree/part/templates/part/category.html | 133 ++++++++++++------ .../part/templates/part/category_navbar.html | 24 ++-- .../templates/part/category_parametric.html | 37 ----- .../templates/part/category_partlist.html | 16 --- InvenTree/part/templates/part/detail.html | 15 +- .../part/templates/part/subcategory.html | 51 ------- InvenTree/part/urls.py | 3 - InvenTree/part/views.py | 14 +- 8 files changed, 106 insertions(+), 187 deletions(-) delete mode 100644 InvenTree/part/templates/part/category_parametric.html delete mode 100644 InvenTree/part/templates/part/category_partlist.html delete mode 100644 InvenTree/part/templates/part/subcategory.html diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html index cf7348be76..224d855aa3 100644 --- a/InvenTree/part/templates/part/category.html +++ b/InvenTree/part/templates/part/category.html @@ -3,7 +3,7 @@ {% load i18n %} {% block menubar %} -{% include 'part/category_navbar.html' with tab='parts' %} +{% include 'part/category_navbar.html' %} {% endblock %} {% block content %} @@ -115,63 +115,81 @@
        • -{% block category_content %} +{% block page_content %} -
          -
          - - {% if roles.part.add %} - - {% endif %} +
          +
          +

          {% trans "Parts" %}

          +
          +
          - - - -
          - + + {% if roles.part.add %} + + {% endif %} +
          + + +
          + + + +
          + +
          +
          + +
          +
          -
          +
          -

          - {% block heading %} - {% trans "Parts" %} - {% endblock %} -

          +

          {% trans "Part Parameters" %}

          -
          - {% block details %} - -
          - {% endblock %} +
          + +
          +
          +
          + +
          +
          +

          {% trans "Subcategories" %}

          +
          +
          +
          +
          + +
          + +
          +
          +
          + +
          +
          {% endblock %} - -{% block category_tables %} -{% endblock category_tables %} - {% endblock %} {% block js_load %} {{ block.super }} @@ -180,6 +198,26 @@ {% block js_ready %} {{ block.super }} + loadPartCategoryTable($('#subcategory-table'), { + params: { + {% if category %} + parent: {{ category.pk }} + {% else %} + parent: 'null' + {% endif %} + } + }); + + {% if category %} + loadParametricPartTable( + "#parametric-part-table", + { + headers: {{ headers|safe }}, + data: {{ parameters|safe }}, + } + ); + {% endif %} + enableNavbar({ label: 'category', toggleId: '#category-menu-toggle', @@ -328,4 +366,9 @@ $('#view-list').hide(); } + attachNavCallbacks({ + name: 'partcategory', + default: 'part-stock' + }); + {% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/category_navbar.html b/InvenTree/part/templates/part/category_navbar.html index bd61300531..8e5e085f93 100644 --- a/InvenTree/part/templates/part/category_navbar.html +++ b/InvenTree/part/templates/part/category_navbar.html @@ -11,31 +11,23 @@ -
        • - {% if category %} - - {% else %} - - {% endif %} +
        • + {% trans "Subcategories" %}
        • -
        • - {% if category %} - - {% else %} - - {% endif %} +
        • + {% trans "Parts" %}
        • {% if show_import and user.is_staff and roles.part.add %} -
        • - +
        • + {% trans "Import Parts" %} @@ -43,8 +35,8 @@ {% endif %} {% if category %} -
        • - +
        • + {% trans "Parameters" %} diff --git a/InvenTree/part/templates/part/category_parametric.html b/InvenTree/part/templates/part/category_parametric.html deleted file mode 100644 index 881a292986..0000000000 --- a/InvenTree/part/templates/part/category_parametric.html +++ /dev/null @@ -1,37 +0,0 @@ -{% extends "part/category.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/category_navbar.html' with tab='parameters' %} -{% endblock %} - -{% block heading %} -{% trans "Part Parameters" %} -{% endblock %} - -{% block details %} - - -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - /* Hide Button Toolbar */ - window.onload = function hideButtonToolbar() { - var toolbar = document.getElementById("button-toolbar"); - toolbar.style.display = "none"; - }; - - loadParametricPartTable( - "#parametric-part-table", - { - headers: {{ headers|safe }}, - data: {{ parameters|safe }}, - } - ); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/category_partlist.html b/InvenTree/part/templates/part/category_partlist.html deleted file mode 100644 index e78254c541..0000000000 --- a/InvenTree/part/templates/part/category_partlist.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "part/category.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/category_navbar.html' with tab='parts' %} -{% endblock %} - -{% block heading %} -{% trans "Parts" %} -{% endblock %} - -{% block details %} - -
          -{% endblock %} diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index b44bd25acc..2cb430ccf8 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -3,7 +3,6 @@ {% load i18n %} {% load markdownify %} - {% block menubar %} {% include 'part/navbar.html' %} {% endblock %} @@ -116,6 +115,10 @@
        • +
          + +
          +

          {% trans "Part Variants" %}

          @@ -788,11 +791,6 @@ ) }); - attachNavCallbacks({ - name: 'part', - default: 'part-stock' - }); - $('#supplier-create').click(function () { launchModalForm( "{% url 'supplier-part-create' %}", @@ -895,4 +893,9 @@ }); }); + attachNavCallbacks({ + name: 'part', + default: 'part-stock' + }); + {% endblock %} diff --git a/InvenTree/part/templates/part/subcategory.html b/InvenTree/part/templates/part/subcategory.html deleted file mode 100644 index e9e0d27468..0000000000 --- a/InvenTree/part/templates/part/subcategory.html +++ /dev/null @@ -1,51 +0,0 @@ -{% extends "part/category.html" %} - -{% load i18n %} -{% load inventree_extras %} -{% load static %} - -{% block menubar %} -{% include 'part/category_navbar.html' with tab='subcategories' %} -{% endblock %} - -{% block category_content %} - -
          - -
          -

          {% trans "Subcategories" %}

          -
          - -
          -
          - -
          - -
          -
          -
          - -
          - -
          -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - enableNavbar({ - label: 'category', - toggleId: '#category-menu-toggle', - }); - - loadPartCategoryTable($('#subcategory-table'), { - params: { - {% if category %} - parent: {{ category.pk }} - {% else %} - parent: 'null' - {% endif %} - } - }); - -{% endblock %} diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 0640807e51..e59ea88a05 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -78,9 +78,6 @@ category_urls = [ url(r'^delete/', views.CategoryDelete.as_view(), name='category-delete'), url(r'^parameters/', include(category_parameter_urls)), - url(r'^subcategory/', views.CategoryDetail.as_view(template_name='part/subcategory.html'), name='category-subcategory'), - url(r'^parametric/', views.CategoryParametric.as_view(), name='category-parametric'), - # Anything else url(r'^.*$', views.CategoryDetail.as_view(), name='category-detail'), ])) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index bf8c32ba78..cbaa7f3d72 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -1818,7 +1818,7 @@ class CategoryDetail(InvenTreeRoleMixin, DetailView): model = PartCategory context_object_name = 'category' queryset = PartCategory.objects.all().prefetch_related('children') - template_name = 'part/category_partlist.html' + template_name = 'part/category.html' def get_context_data(self, **kwargs): @@ -1829,18 +1829,6 @@ class CategoryDetail(InvenTreeRoleMixin, DetailView): except KeyError: context['part_count'] = 0 - return context - - -class CategoryParametric(CategoryDetail): - """ Parametric view for PartCategory """ - - template_name = 'part/category_parametric.html' - - def get_context_data(self, **kwargs): - - context = super(CategoryParametric, self).get_context_data(**kwargs).copy() - # Get current category category = kwargs.get('object', None) From 52da678636257cbdaf5ee0f9c2e5af7318f9e4a3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 21:24:33 +1000 Subject: [PATCH 408/445] Refactor SupplierPart page --- .../company/manufacturer_part_create.html | 17 - .../templates/company/supplier_part.html | 352 ++++++++++++++++++ .../templates/company/supplier_part_base.html | 161 -------- .../company/supplier_part_detail.html | 48 --- .../company/supplier_part_navbar.html | 12 +- .../company/supplier_part_orders.html | 35 -- .../company/supplier_part_pricing.html | 124 ------ .../company/supplier_part_stock.html | 58 --- InvenTree/company/urls.py | 7 +- InvenTree/part/templates/part/category.html | 4 +- 10 files changed, 361 insertions(+), 457 deletions(-) delete mode 100644 InvenTree/company/templates/company/manufacturer_part_create.html create mode 100644 InvenTree/company/templates/company/supplier_part.html delete mode 100644 InvenTree/company/templates/company/supplier_part_base.html delete mode 100644 InvenTree/company/templates/company/supplier_part_detail.html delete mode 100644 InvenTree/company/templates/company/supplier_part_orders.html delete mode 100644 InvenTree/company/templates/company/supplier_part_pricing.html delete mode 100644 InvenTree/company/templates/company/supplier_part_stock.html diff --git a/InvenTree/company/templates/company/manufacturer_part_create.html b/InvenTree/company/templates/company/manufacturer_part_create.html deleted file mode 100644 index 21c23f9075..0000000000 --- a/InvenTree/company/templates/company/manufacturer_part_create.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "modal_form.html" %} - -{% load i18n %} - -{% block pre_form_content %} -{{ block.super }} - -{% if part %} -
          - {% include "hover_image.html" with image=part.image %} - {{ part.full_name}} -
          - {{ part.description }} -
          -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part.html b/InvenTree/company/templates/company/supplier_part.html new file mode 100644 index 0000000000..c3c2f89aa7 --- /dev/null +++ b/InvenTree/company/templates/company/supplier_part.html @@ -0,0 +1,352 @@ +{% extends "two_column.html" %} +{% load static %} +{% load i18n %} +{% load inventree_extras %} + +{% block page_title %} +{% inventree_title %} | {% trans "Supplier Part" %} +{% endblock %} + +{% block menubar %} +{% include "company/supplier_part_navbar.html" %} +{% endblock %} + +{% block thumbnail %} + +{% endblock %} + +{% block page_data %} +

          {% trans "Supplier Part" %}

          +
          +

          + {{ part.part.full_name }} + {% if user.is_staff and perms.company.change_company %} + + + + {% endif %} +

          +

          {{ part.supplier.name }} - {{ part.SKU }}

          + +{% if roles.purchase_order.change %} +
          +
          + {% if roles.purchase_order.add %} + + {% endif %} + + {% if roles.purchase_order.delete %} + + {% endif %} +
          +
          +{% endif %} + +{% endblock %} + +{% block page_details %} + +

          {% trans "Supplier Part Details" %}

          + + + + + + + + {% if part.description %} + + + + + + {% endif %} + {% if part.link %} + + + + + + {% endif %} + + + + + + + + + + {% if part.manufacturer_part.manufacturer %} + + + + + + {% endif %} + {% if part.manufacturer_part.MPN %} + + + + + + {% endif %} + {% if part.packaging %} + + + + + + {% endif %} + {% if part.note %} + + + + + + {% endif %} +
          {% trans "Internal Part" %} + {% if part.part %} + {{ part.part.full_name }}{% include "clip.html"%} + {% endif %} +
          {% trans "Description" %}{{ part.description }}{% include "clip.html"%}
          {% trans "External Link" %}{{ part.link }}{% include "clip.html"%}
          {% trans "Supplier" %}{{ part.supplier.name }}{% include "clip.html"%}
          {% trans "SKU" %}{{ part.SKU }}{% include "clip.html"%}
          {% trans "Manufacturer" %} + {{ part.manufacturer_part.manufacturer.name }}{% include "clip.html"%}
          {% trans "MPN" %}{{ part.manufacturer_part.MPN }}{% include "clip.html"%}
          {% trans "Packaging" %}{{ part.packaging }}{% include "clip.html"%}
          {% trans "Note" %}{{ part.note }}{% include "clip.html"%}
          +{% endblock %} + +{% block page_content %} + +
          +
          +

          {% trans "Supplier Part Stock" %}

          +
          +
          + {% include "stock_table.html" %} +
          +
          + +
          +
          +

          {% trans "Supplier Part Orders" %}

          +
          +
          + {% if roles.purchase_order.add %} +
          +
          + +
          +
          + {% endif %} + +
          +
          +
          + +
          +
          +

          {% trans "Pricing Information" %}

          +
          +
          + {% if roles.purchase_order.add %} +
          + +
          + {% endif %} + + +
          +
          +
          + +{% endblock %} + +{% block js_ready %} +{{ block.super }} + +function reloadPriceBreaks() { + $("#price-break-table").bootstrapTable("refresh"); +} + +$('#price-break-table').inventreeTable({ + name: 'buypricebreaks', + formatNoMatches: function() { return "{% trans "No price break information found" %}"; }, + queryParams: { + part: {{ part.id }}, + }, + url: "{% url 'api-part-supplier-price-list' %}", + onPostBody: function() { + var table = $('#price-break-table'); + + table.find('.button-price-break-delete').click(function() { + var pk = $(this).attr('pk'); + + constructForm(`/api/company/price-break/${pk}/`, { + method: 'DELETE', + onSuccess: reloadPriceBreaks, + title: '{% trans "Delete Price Break" %}', + }); + }); + + table.find('.button-price-break-edit').click(function() { + var pk = $(this).attr('pk'); + + constructForm(`/api/company/price-break/${pk}/`, { + fields: { + quantity: {}, + price: {}, + price_currency: {}, + }, + onSuccess: reloadPriceBreaks, + title: '{% trans "Edit Price Break" %}', + }); + }); + }, + columns: [ + { + field: 'pk', + title: 'ID', + visible: false, + switchable: false, + }, + { + field: 'quantity', + title: '{% trans "Quantity" %}', + sortable: true, + }, + { + field: 'price', + title: '{% trans "Price" %}', + sortable: true, + formatter: function(value, row, index) { + var html = value; + + html += `
          ` + + html += makeIconButton('fa-edit icon-blue', 'button-price-break-edit', row.pk, '{% trans "Edit price break" %}'); + html += makeIconButton('fa-trash-alt icon-red', 'button-price-break-delete', row.pk, '{% trans "Delete price break" %}'); + + html += `
          `; + + return html; + } + }, + ] +}); + +$('#new-price-break').click(function() { + + constructForm( + '{% url "api-part-supplier-price-list" %}', + { + method: 'POST', + fields: { + quantity: {}, + part: { + value: {{ part.pk }}, + hidden: true, + }, + price: {}, + price_currency: { + }, + }, + title: '{% trans "Add Price Break" %}', + onSuccess: reloadPriceBreaks, + } + ); +}); + +loadPurchaseOrderTable($("#purchase-order-table"), { + url: "{% url 'api-po-list' %}?supplier_part={{ part.id }}", +}); + +loadStockTable($("#stock-table"), { + params: { + supplier_part: {{ part.id }}, + location_detail: true, + part_detail: false, + }, + groupByField: 'location', + buttons: ['#stock-options'], + url: "{% url 'api-stock-list' %}", +}); + +$("#stock-export").click(function() { + launchModalForm("{% url 'stock-export-options' %}", { + submit_text: '{% trans "Export" %}', + success: function(response) { + var url = "{% url 'stock-export' %}"; + + url += "?format=" + response.format; + url += "&cascade=" + response.cascade; + url += "&supplier_part={{ part.id }}"; + + location.href = url; + }, + }); +}); + +$("#item-create").click(function() { + createNewStockItem({ + data: { + part: {{ part.part.id }}, + supplier_part: {{ part.id }}, + }, + reload: true, + }); +}); + + +enableNavbar({ + label: 'supplier-part', + toggleId: '#supplier-part-menu-toggle' +}) + +$('#order-part, #order-part2').click(function() { + launchModalForm( + "{% url 'order-parts' %}", + { + data: { + part: {{ part.part.id }}, + }, + reload: true, + }, + ); +}); + +$('#edit-part').click(function () { + launchModalForm( + "{% url 'supplier-part-edit' part.id %}", + { + reload: true + } + ); +}); + +$('#delete-part').click(function() { + launchModalForm( + "{% url 'supplier-part-delete' %}?part={{ part.id }}", + { + redirect: "{% url 'company-detail' part.supplier.id %}" + } + ); +}); + +attachNavCallbacks({ + name: 'supplierpart', + default: 'stock' +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part_base.html b/InvenTree/company/templates/company/supplier_part_base.html deleted file mode 100644 index 900e0750cc..0000000000 --- a/InvenTree/company/templates/company/supplier_part_base.html +++ /dev/null @@ -1,161 +0,0 @@ -{% extends "two_column.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block page_title %} -{% inventree_title %} | {% trans "Supplier Part" %} -{% endblock %} - -{% block thumbnail %} - -{% endblock %} - -{% block page_data %} -

          {% trans "Supplier Part" %}

          -
          -

          - {{ part.part.full_name }} - {% if user.is_staff and perms.company.change_company %} - - - - {% endif %} -

          -

          {{ part.supplier.name }} - {{ part.SKU }}

          - -{% if roles.purchase_order.change %} -
          -
          - {% if roles.purchase_order.add %} - - {% endif %} - - {% if roles.purchase_order.delete %} - - {% endif %} -
          -
          -{% endif %} - -{% endblock %} - -{% block page_details %} - -

          {% trans "Supplier Part Details" %}

          - - - - - - - - {% if part.description %} - - - - - - {% endif %} - {% if part.link %} - - - - - - {% endif %} - - - - - - - - - - {% if part.manufacturer_part.manufacturer %} - - - - - - {% endif %} - {% if part.manufacturer_part.MPN %} - - - - - - {% endif %} - {% if part.packaging %} - - - - - - {% endif %} - {% if part.note %} - - - - - - {% endif %} -
          {% trans "Internal Part" %} - {% if part.part %} - {{ part.part.full_name }}{% include "clip.html"%} - {% endif %} -
          {% trans "Description" %}{{ part.description }}{% include "clip.html"%}
          {% trans "External Link" %}{{ part.link }}{% include "clip.html"%}
          {% trans "Supplier" %}{{ part.supplier.name }}{% include "clip.html"%}
          {% trans "SKU" %}{{ part.SKU }}{% include "clip.html"%}
          {% trans "Manufacturer" %} - {{ part.manufacturer_part.manufacturer.name }}{% include "clip.html"%}
          {% trans "MPN" %}{{ part.manufacturer_part.MPN }}{% include "clip.html"%}
          {% trans "Packaging" %}{{ part.packaging }}{% include "clip.html"%}
          {% trans "Note" %}{{ part.note }}{% include "clip.html"%}
          -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -enableNavbar({ - label: 'supplier-part', - toggleId: '#supplier-part-menu-toggle' -}) - -$('#order-part, #order-part2').click(function() { - launchModalForm( - "{% url 'order-parts' %}", - { - data: { - part: {{ part.part.id }}, - }, - reload: true, - }, - ); -}); - -$('#edit-part').click(function () { - launchModalForm( - "{% url 'supplier-part-edit' part.id %}", - { - reload: true - } - ); -}); - -$('#delete-part').click(function() { - launchModalForm( - "{% url 'supplier-part-delete' %}?part={{ part.id }}", - { - redirect: "{% url 'company-detail' part.supplier.id %}" - } - ); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part_detail.html b/InvenTree/company/templates/company/supplier_part_detail.html deleted file mode 100644 index 708885043a..0000000000 --- a/InvenTree/company/templates/company/supplier_part_detail.html +++ /dev/null @@ -1,48 +0,0 @@ -{% extends "company/supplier_part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/supplier_part_navbar.html" with tab='details' %} -{% endblock %} - -{% block heading %} -{% trans "Supplier Part Details" %} -{% endblock %} - - -{% block details %} - - - - - - - - -{% if part.link %} - -{% endif %} -{% if part.description %} - -{% endif %} -{% if part.manufacturer %} - - -{% endif %} -{% if part.note %} - -{% endif %} -
          {% trans "Internal Part" %} - {% if part.part %} - {{ part.part.full_name }} - {% endif %} -
          {% trans "Supplier" %}{{ part.supplier.name }}
          {% trans "SKU" %}{{ part.SKU }}
          {% trans "External Link" %}{{ part.link }}
          {% trans "Description" %}{{ part.description }}{% include "clip.html"%}
          {% trans "Manufacturer" %}{{ part.manufacturer }}{% include "clip.html"%}
          {% trans "MPN" %}{{ part.MPN }}{% include "clip.html"%}
          {% trans "Note" %}{{ part.note }}{% include "clip.html"%}
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part_navbar.html b/InvenTree/company/templates/company/supplier_part_navbar.html index e52c1798ba..4f7783701a 100644 --- a/InvenTree/company/templates/company/supplier_part_navbar.html +++ b/InvenTree/company/templates/company/supplier_part_navbar.html @@ -9,22 +9,22 @@ -
        • - +
        • + {% trans "Stock" %}
        • -
        • - +
        • + {% trans "Orders" %}
        • -
        • - +
        • + {% trans "Pricing" %} diff --git a/InvenTree/company/templates/company/supplier_part_orders.html b/InvenTree/company/templates/company/supplier_part_orders.html deleted file mode 100644 index 05e425fc97..0000000000 --- a/InvenTree/company/templates/company/supplier_part_orders.html +++ /dev/null @@ -1,35 +0,0 @@ -{% extends "company/supplier_part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/supplier_part_navbar.html" with tab='orders' %} -{% endblock %} - -{% block heading %} -{% trans "Supplier Part Orders" %} -{% endblock %} - -{% block details %} -{% if roles.purchase_order.add %} -
          -
          - -
          -
          -{% endif %} - - -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadPurchaseOrderTable($("#purchase-order-table"), { - url: "{% url 'api-po-list' %}?supplier_part={{ part.id }}", -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part_pricing.html b/InvenTree/company/templates/company/supplier_part_pricing.html deleted file mode 100644 index a476b53a13..0000000000 --- a/InvenTree/company/templates/company/supplier_part_pricing.html +++ /dev/null @@ -1,124 +0,0 @@ -{% extends "company/supplier_part_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include "company/supplier_part_navbar.html" with tab='pricing' %} -{% endblock %} - -{% block heading %} -{% trans "Pricing Information" %} -{% endblock %} - -{% block details %} - -{% if roles.purchase_order.add %} -
          - -
          -{% endif %} - - -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -function reloadPriceBreaks() { - $("#price-break-table").bootstrapTable("refresh"); -} - -$('#price-break-table').inventreeTable({ - name: 'buypricebreaks', - formatNoMatches: function() { return "{% trans "No price break information found" %}"; }, - queryParams: { - part: {{ part.id }}, - }, - url: "{% url 'api-part-supplier-price-list' %}", - onPostBody: function() { - var table = $('#price-break-table'); - - table.find('.button-price-break-delete').click(function() { - var pk = $(this).attr('pk'); - - constructForm(`/api/company/price-break/${pk}/`, { - method: 'DELETE', - onSuccess: reloadPriceBreaks, - title: '{% trans "Delete Price Break" %}', - }); - }); - - table.find('.button-price-break-edit').click(function() { - var pk = $(this).attr('pk'); - - constructForm(`/api/company/price-break/${pk}/`, { - fields: { - quantity: {}, - price: {}, - price_currency: {}, - }, - onSuccess: reloadPriceBreaks, - title: '{% trans "Edit Price Break" %}', - }); - }); - }, - columns: [ - { - field: 'pk', - title: 'ID', - visible: false, - switchable: false, - }, - { - field: 'quantity', - title: '{% trans "Quantity" %}', - sortable: true, - }, - { - field: 'price', - title: '{% trans "Price" %}', - sortable: true, - formatter: function(value, row, index) { - var html = value; - - html += `
          ` - - html += makeIconButton('fa-edit icon-blue', 'button-price-break-edit', row.pk, '{% trans "Edit price break" %}'); - html += makeIconButton('fa-trash-alt icon-red', 'button-price-break-delete', row.pk, '{% trans "Delete price break" %}'); - - html += `
          `; - - return html; - } - }, - ] -}); - -$('#new-price-break').click(function() { - - constructForm( - '{% url "api-part-supplier-price-list" %}', - { - method: 'POST', - fields: { - quantity: {}, - part: { - value: {{ part.pk }}, - hidden: true, - }, - price: {}, - price_currency: { - }, - }, - title: '{% trans "Add Price Break" %}', - onSuccess: reloadPriceBreaks, - } - ); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part_stock.html b/InvenTree/company/templates/company/supplier_part_stock.html deleted file mode 100644 index 1187b95bca..0000000000 --- a/InvenTree/company/templates/company/supplier_part_stock.html +++ /dev/null @@ -1,58 +0,0 @@ -{% extends "company/supplier_part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/supplier_part_navbar.html" with tab='stock' %} -{% endblock %} - -{% block heading %} -{% trans "Supplier Part Stock" %} -{% endblock %} - -{% block details %} -{% include "stock_table.html" %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - loadStockTable($("#stock-table"), { - params: { - supplier_part: {{ part.id }}, - location_detail: true, - part_detail: false, - }, - groupByField: 'location', - buttons: ['#stock-options'], - url: "{% url 'api-stock-list' %}", - }); - - $("#stock-export").click(function() { - launchModalForm("{% url 'stock-export-options' %}", { - submit_text: '{% trans "Export" %}', - success: function(response) { - var url = "{% url 'stock-export' %}"; - - url += "?format=" + response.format; - url += "&cascade=" + response.cascade; - url += "&supplier_part={{ part.id }}"; - - location.href = url; - }, - }); - }); - - $("#item-create").click(function() { - createNewStockItem({ - data: { - part: {{ part.part.id }}, - supplier_part: {{ part.id }}, - }, - reload: true, - }); - }); - - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index 4f844176ee..817ee27988 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -39,12 +39,7 @@ manufacturer_part_urls = [ supplier_part_detail_urls = [ url(r'^edit/?', views.SupplierPartEdit.as_view(), name='supplier-part-edit'), - url(r'^manufacturers/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_manufacturers.html'), name='supplier-part-manufacturers'), - url(r'^pricing/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_pricing.html'), name='supplier-part-pricing'), - url(r'^orders/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_orders.html'), name='supplier-part-orders'), - url(r'^stock/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_stock.html'), name='supplier-part-stock'), - - url('^.*$', views.SupplierPartDetail.as_view(template_name='company/supplier_part_pricing.html'), name='supplier-part-detail'), + url('^.*$', views.SupplierPartDetail.as_view(template_name='company/supplier_part.html'), name='supplier-part-detail'), ] supplier_part_urls = [ diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html index 224d855aa3..0aee97a5e3 100644 --- a/InvenTree/part/templates/part/category.html +++ b/InvenTree/part/templates/part/category.html @@ -244,11 +244,11 @@ "{% url 'category-create' %}", { follow: true, - {% if category %} data: { + {% if category %} category: {{ category.id }} + {% endif %} }, - {% endif %} secondary: [ { field: 'default_location', From 676cca89a1745058986dcc6f3dc3868e95a230b8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 21:32:46 +1000 Subject: [PATCH 409/445] Refactor ManufacturerPart pages --- .../templates/company/manufacturer_part.html | 330 ++++++++++++++++++ .../company/manufacturer_part_base.html | 143 -------- .../company/manufacturer_part_detail.html | 38 -- .../company/manufacturer_part_navbar.html | 13 +- .../company/manufacturer_part_suppliers.html | 187 ---------- InvenTree/company/urls.py | 3 +- 6 files changed, 341 insertions(+), 373 deletions(-) create mode 100644 InvenTree/company/templates/company/manufacturer_part.html delete mode 100644 InvenTree/company/templates/company/manufacturer_part_base.html delete mode 100644 InvenTree/company/templates/company/manufacturer_part_detail.html delete mode 100644 InvenTree/company/templates/company/manufacturer_part_suppliers.html diff --git a/InvenTree/company/templates/company/manufacturer_part.html b/InvenTree/company/templates/company/manufacturer_part.html new file mode 100644 index 0000000000..da5ea36173 --- /dev/null +++ b/InvenTree/company/templates/company/manufacturer_part.html @@ -0,0 +1,330 @@ +{% extends "two_column.html" %} +{% load static %} +{% load i18n %} + +{% block page_title %} +InvenTree | {% trans "Manufacturer Part" %} +{% endblock %} + +{% block menubar %} +{% include "company/manufacturer_part_navbar.html" %} +{% endblock %} + +{% block thumbnail %} + +{% endblock %} + +{% block page_data %} +

          {% trans "Manufacturer Part" %}

          +
          +

          + {{ part.part.full_name }} + {% if user.is_staff and perms.company.change_company %} + + + + {% endif %} +

          +

          {{ part.manufacturer.name }} - {{ part.MPN }}

          + +{% if roles.purchase_order.change %} +
          +
          + {% comment "for later" %} + {% if roles.purchase_order.add %} + + {% endif %} + {% endcomment %} + + {% if roles.purchase_order.delete %} + + {% endif %} +
          +
          +{% endif %} + +{% endblock %} + +{% block page_details %} + +

          {% trans "Manufacturer Part Details" %}

          + + + + + + + + {% if part.description %} + + + + + + {% endif %} + {% if part.link %} + + + + + + {% endif %} + + + + + + + + + +
          {% trans "Internal Part" %} + {% if part.part %} + {{ part.part.full_name }}{% include "clip.html"%} + {% endif %} +
          {% trans "Description" %}{{ part.description }}{% include "clip.html"%}
          {% trans "External Link" %}{{ part.link }}{% include "clip.html"%}
          {% trans "Manufacturer" %}{{ part.manufacturer.name }}{% include "clip.html"%}
          {% trans "MPN" %}{{ part.MPN }}{% include "clip.html"%}
          +{% endblock %} + +{% block page_content %} + +
          +
          +

          {% trans "Suppliers" %}

          +
          +
          +
          +
          + +
          + + +
          +
          +
          + + +
          +
          +
          + +
          +
          +

          {% trans "Parameters" %}

          +
          +
          +
          +
          + +
          + + +
          +
          +
          + +
          +
          +
          + +{% endblock %} + + +{% block js_ready %} +{{ block.super }} + +enableNavbar({ + label: 'manufacturer-part', + toggleId: '#manufacturer-part-menu-toggle' +}); + +function reloadParameters() { + $("#parameter-table").bootstrapTable("refresh"); +} + +$('#parameter-create').click(function() { + + constructForm('{% url "api-manufacturer-part-parameter-list" %}', { + method: 'POST', + fields: { + name: {}, + value: {}, + units: {}, + manufacturer_part: { + value: {{ part.pk }}, + hidden: true, + } + }, + title: '{% trans "Add Parameter" %}', + onSuccess: reloadParameters + }); +}); + +$('#supplier-create').click(function () { + launchModalForm( + "{% url 'supplier-part-create' %}", + { + reload: true, + data: { + manufacturer_part: {{ part.id }} + }, + secondary: [ + { + field: 'supplier', + label: '{% trans "New Supplier" %}', + title: '{% trans "Create new supplier" %}', + }, + ] + }); +}); + +$("#supplier-part-delete").click(function() { + + var selections = $("#supplier-table").bootstrapTable("getSelections"); + + var parts = []; + + selections.forEach(function(item) { + parts.push(item.pk); + }); + + launchModalForm("{% url 'supplier-part-delete' %}", { + data: { + parts: parts, + }, + reload: true, + }); +}); + +$("#multi-parameter-delete").click(function() { + + var selections = $("#parameter-table").bootstrapTable("getSelections"); + + var text = ` +
          +

          {% trans "Selected parameters will be deleted" %}:

          +
            `; + + selections.forEach(function(item) { + text += `
          • ${item.name} - ${item.value}
          • `; + }); + + text += ` +
          +
          `; + + showQuestionDialog( + '{% trans "Delete Parameters" %}', + text, + { + accept_text: '{% trans "Delete" %}', + accept: function() { + // Delete each parameter via the API + var requests = []; + + selections.forEach(function(item) { + var url = `/api/company/part/manufacturer/parameter/${item.pk}/`; + + requests.push(inventreeDelete(url)); + }); + + $.when.apply($, requests).then(function() { + $('#parameter-table').bootstrapTable('refresh'); + }); + } + } + ); +}); + +loadSupplierPartTable( + "#supplier-table", + "{% url 'api-supplier-part-list' %}", + { + params: { + part: {{ part.part.id }}, + manufacturer_part: {{ part.id }}, + part_detail: false, + supplier_detail: true, + manufacturer_detail: false, + }, + } +); + +loadManufacturerPartParameterTable( + "#parameter-table", + "{% url 'api-manufacturer-part-parameter-list' %}", + { + params: { + manufacturer_part: {{ part.id }}, + } + } +); + +linkButtonsToSelection($("#supplier-table"), ['#supplier-part-options']); + +linkButtonsToSelection($("#parameter-table"), ['#parameter-options']); + +$('#order-part, #order-part2').click(function() { + launchModalForm( + "{% url 'order-parts' %}", + { + data: { + part: {{ part.part.id }}, + }, + reload: true, + }, + ); +}); + +$('#edit-part').click(function () { + + constructForm('{% url "api-manufacturer-part-detail" part.pk %}', { + fields: { + part: {}, + manufacturer: {}, + MPN: { + icon: 'fa-hashtag', + }, + description: {}, + link: { + icon: 'fa-link', + }, + }, + title: '{% trans "Edit Manufacturer Part" %}', + reload: true, + }); +}); + +$('#delete-part').click(function() { + + constructForm('{% url "api-manufacturer-part-detail" part.pk %}', { + method: 'DELETE', + title: '{% trans "Delete Manufacturer Part" %}', + redirect: "{% url 'company-detail' part.manufacturer.id %}", + }); +}); + +attachNavCallbacks({ + name: 'manufacturerpart', + default: 'parameters' +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/manufacturer_part_base.html b/InvenTree/company/templates/company/manufacturer_part_base.html deleted file mode 100644 index c54401b172..0000000000 --- a/InvenTree/company/templates/company/manufacturer_part_base.html +++ /dev/null @@ -1,143 +0,0 @@ -{% extends "two_column.html" %} -{% load static %} -{% load i18n %} - -{% block page_title %} -InvenTree | {% trans "Manufacturer Part" %} -{% endblock %} - -{% block thumbnail %} - -{% endblock %} - -{% block page_data %} -

          {% trans "Manufacturer Part" %}

          -
          -

          - {{ part.part.full_name }} - {% if user.is_staff and perms.company.change_company %} - - - - {% endif %} -

          -

          {{ part.manufacturer.name }} - {{ part.MPN }}

          - -{% if roles.purchase_order.change %} -
          -
          - {% comment "for later" %} - {% if roles.purchase_order.add %} - - {% endif %} - {% endcomment %} - - {% if roles.purchase_order.delete %} - - {% endif %} -
          -
          -{% endif %} - -{% endblock %} - -{% block page_details %} - -

          {% trans "Manufacturer Part Details" %}

          - - - - - - - - {% if part.description %} - - - - - - {% endif %} - {% if part.link %} - - - - - - {% endif %} - - - - - - - - - -
          {% trans "Internal Part" %} - {% if part.part %} - {{ part.part.full_name }}{% include "clip.html"%} - {% endif %} -
          {% trans "Description" %}{{ part.description }}{% include "clip.html"%}
          {% trans "External Link" %}{{ part.link }}{% include "clip.html"%}
          {% trans "Manufacturer" %}{{ part.manufacturer.name }}{% include "clip.html"%}
          {% trans "MPN" %}{{ part.MPN }}{% include "clip.html"%}
          -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -enableNavbar({ - label: 'manufacturer-part', - toggleId: '#manufacturer-part-menu-toggle' -}) - -$('#order-part, #order-part2').click(function() { - launchModalForm( - "{% url 'order-parts' %}", - { - data: { - part: {{ part.part.id }}, - }, - reload: true, - }, - ); -}); - -$('#edit-part').click(function () { - - constructForm('{% url "api-manufacturer-part-detail" part.pk %}', { - fields: { - part: {}, - manufacturer: {}, - MPN: { - icon: 'fa-hashtag', - }, - description: {}, - link: { - icon: 'fa-link', - }, - }, - title: '{% trans "Edit Manufacturer Part" %}', - reload: true, - }); -}); - -$('#delete-part').click(function() { - - constructForm('{% url "api-manufacturer-part-detail" part.pk %}', { - method: 'DELETE', - title: '{% trans "Delete Manufacturer Part" %}', - redirect: "{% url 'company-detail' part.manufacturer.id %}", - }); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/manufacturer_part_detail.html b/InvenTree/company/templates/company/manufacturer_part_detail.html deleted file mode 100644 index e25fb9dca3..0000000000 --- a/InvenTree/company/templates/company/manufacturer_part_detail.html +++ /dev/null @@ -1,38 +0,0 @@ -{% extends "company/manufacturer_part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/manufacturer_part_navbar.html" with tab='details' %} -{% endblock %} - -{% block heading %} -{% trans "Manufacturer Part Details" %} -{% endblock %} - - -{% block details %} - - - - - - - - -{% if part.link %} - -{% endif %} -
          {% trans "Internal Part" %} - {% if part.part %} - {{ part.part.full_name }} - {% endif %} -
          {% trans "Manufacturer" %}{{ part.manufacturer.name }}
          {% trans "MPN" %}{{ part.MPN }}
          {% trans "External Link" %}{{ part.link }}
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/manufacturer_part_navbar.html b/InvenTree/company/templates/company/manufacturer_part_navbar.html index 3eae30afaf..893374858f 100644 --- a/InvenTree/company/templates/company/manufacturer_part_navbar.html +++ b/InvenTree/company/templates/company/manufacturer_part_navbar.html @@ -8,8 +8,15 @@
        • -
        • - +
        • + + + {% trans "Parameters" %} + +
        • + +
        • + {% trans "Suppliers" %} @@ -22,7 +29,7 @@ {% trans "Stock" %}
        • - +
        • diff --git a/InvenTree/company/templates/company/manufacturer_part_suppliers.html b/InvenTree/company/templates/company/manufacturer_part_suppliers.html deleted file mode 100644 index f706ca90ba..0000000000 --- a/InvenTree/company/templates/company/manufacturer_part_suppliers.html +++ /dev/null @@ -1,187 +0,0 @@ -{% extends "company/manufacturer_part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/manufacturer_part_navbar.html" with tab='suppliers' %} -{% endblock %} - -{% block heading %} -{% trans "Suppliers" %} -{% endblock %} - -{% block details %} - - - -
          - -{% endblock %} - -{% block post_content_panels %} - -
          -
          -

          {% trans "Parameters" %}

          -
          -
          -
          -
          - -
          - - -
          -
          -
          - -
          -
          -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -function reloadParameters() { - $("#parameter-table").bootstrapTable("refresh"); -} - -$('#parameter-create').click(function() { - - constructForm('{% url "api-manufacturer-part-parameter-list" %}', { - method: 'POST', - fields: { - name: {}, - value: {}, - units: {}, - manufacturer_part: { - value: {{ part.pk }}, - hidden: true, - } - }, - title: '{% trans "Add Parameter" %}', - onSuccess: reloadParameters - }); -}); - -$('#supplier-create').click(function () { - launchModalForm( - "{% url 'supplier-part-create' %}", - { - reload: true, - data: { - manufacturer_part: {{ part.id }} - }, - secondary: [ - { - field: 'supplier', - label: '{% trans "New Supplier" %}', - title: '{% trans "Create new supplier" %}', - }, - ] - }); -}); - -$("#supplier-part-delete").click(function() { - - var selections = $("#supplier-table").bootstrapTable("getSelections"); - - var parts = []; - - selections.forEach(function(item) { - parts.push(item.pk); - }); - - launchModalForm("{% url 'supplier-part-delete' %}", { - data: { - parts: parts, - }, - reload: true, - }); -}); - -$("#multi-parameter-delete").click(function() { - - var selections = $("#parameter-table").bootstrapTable("getSelections"); - - var text = ` -
          -

          {% trans "Selected parameters will be deleted" %}:

          -
            `; - - selections.forEach(function(item) { - text += `
          • ${item.name} - ${item.value}
          • `; - }); - - text += ` -
          -
          `; - - showQuestionDialog( - '{% trans "Delete Parameters" %}', - text, - { - accept_text: '{% trans "Delete" %}', - accept: function() { - // Delete each parameter via the API - var requests = []; - - selections.forEach(function(item) { - var url = `/api/company/part/manufacturer/parameter/${item.pk}/`; - - requests.push(inventreeDelete(url)); - }); - - $.when.apply($, requests).then(function() { - $('#parameter-table').bootstrapTable('refresh'); - }); - } - } - ); -}); - -loadSupplierPartTable( - "#supplier-table", - "{% url 'api-supplier-part-list' %}", - { - params: { - part: {{ part.part.id }}, - manufacturer_part: {{ part.id }}, - part_detail: false, - supplier_detail: true, - manufacturer_detail: false, - }, - } -); - -loadManufacturerPartParameterTable( - "#parameter-table", - "{% url 'api-manufacturer-part-parameter-list' %}", - { - params: { - manufacturer_part: {{ part.id }}, - } - } -); - -linkButtonsToSelection($("#supplier-table"), ['#supplier-part-options']) -linkButtonsToSelection($("#parameter-table"), ['#parameter-options']) -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index 817ee27988..7d2b6fb609 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -31,8 +31,7 @@ company_urls = [ manufacturer_part_urls = [ url(r'^(?P\d+)/', include([ - url(r'^suppliers/', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part_suppliers.html'), name='manufacturer-part-suppliers'), - url('^.*$', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part_suppliers.html'), name='manufacturer-part-detail'), + url('^.*$', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part.html'), name='manufacturer-part-detail'), ])), ] From b1640fcc2308c42fa625d0a07f2fdd95736bd80b Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 21:38:05 +1000 Subject: [PATCH 410/445] Refactor StockLocation pages --- InvenTree/stock/templates/stock/location.html | 66 ++++++++++++++++- .../templates/stock/location_navbar.html | 14 +--- .../stock/templates/stock/sublocation.html | 74 ------------------- InvenTree/stock/urls.py | 4 +- 4 files changed, 68 insertions(+), 90 deletions(-) delete mode 100644 InvenTree/stock/templates/stock/sublocation.html diff --git a/InvenTree/stock/templates/stock/location.html b/InvenTree/stock/templates/stock/location.html index d70d9a44be..229ad9cfd1 100644 --- a/InvenTree/stock/templates/stock/location.html +++ b/InvenTree/stock/templates/stock/location.html @@ -4,7 +4,7 @@ {% load i18n %} {% block menubar %} -{% include "stock/location_navbar.html" with tab="stock" %} +{% include "stock/location_navbar.html" %} {% endblock %} {% block content %} @@ -143,13 +143,39 @@ {% block location_content %} -
          +

          {% trans "Stock Items" %}

          {% include "stock_table.html" %}
          +
          +
          +

          {% trans "Sublocations" %}

          +
          +
          +
          +
          + + +
          + +
          +
          +
          + +
          +
          +
          + {% endblock %}
          @@ -164,6 +190,36 @@ toggleId: '#location-menu-toggle' }); + loadStockLocationTable($('#sublocation-table'), { + params: { + {% if location %} + parent: {{ location.pk }}, + {% else %} + parent: 'null', + {% endif %} + } + }); + + linkButtonsToSelection( + $('#sublocation-table'), + [ + '#location-print-options', + ] + ); + + $('#multi-location-print-label').click(function() { + + var selections = $('#sublocation-table').bootstrapTable('getSelections'); + + var locations = []; + + selections.forEach(function(loc) { + locations.push(loc.pk); + }); + + printStockLocationLabels(locations); + }); + {% if location %} $("#barcode-check-in").click(function() { barcodeCheckIn({{ location.id }}); @@ -301,4 +357,10 @@ }, url: "{% url 'api-stock-list' %}", }); + + attachNavCallbacks({ + name: 'stocklocation', + default: 'stock' + }); + {% endblock %} diff --git a/InvenTree/stock/templates/stock/location_navbar.html b/InvenTree/stock/templates/stock/location_navbar.html index a4974d0d37..d03761e460 100644 --- a/InvenTree/stock/templates/stock/location_navbar.html +++ b/InvenTree/stock/templates/stock/location_navbar.html @@ -8,23 +8,15 @@
        • -
        • - {% if location %} - - {% else %} - - {% endif %} +
        • + {% trans "Sublocations" %}
        • - {% if location %} - - {% else %} - - {% endif %} + {% trans "Stock Items" %} diff --git a/InvenTree/stock/templates/stock/sublocation.html b/InvenTree/stock/templates/stock/sublocation.html deleted file mode 100644 index be9390df3b..0000000000 --- a/InvenTree/stock/templates/stock/sublocation.html +++ /dev/null @@ -1,74 +0,0 @@ -{% extends "stock/location.html" %} - -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include "stock/location_navbar.html" with tab="sublocations" %} -{% endblock %} - - -{% block location_content %} - -
          -
          -

          {% trans "Sublocations" %}

          -
          - -
          -
          - - -
          - -
          -
          -
          - -
          -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadStockLocationTable($('#sublocation-table'), { - params: { - {% if location %} - parent: {{ location.pk }}, - {% else %} - parent: 'null', - {% endif %} - } -}); - -linkButtonsToSelection( - $('#sublocation-table'), - [ - '#location-print-options', - ] -); - -$('#multi-location-print-label').click(function() { - - var selections = $('#sublocation-table').bootstrapTable('getSelections'); - - var locations = []; - - selections.forEach(function(loc) { - locations.push(loc.pk); - }); - - printStockLocationLabels(locations); -}) - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index 67101c1f3b..adae836d92 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -14,9 +14,7 @@ location_urls = [ url(r'^edit/?', views.StockLocationEdit.as_view(), name='stock-location-edit'), url(r'^delete/?', views.StockLocationDelete.as_view(), name='stock-location-delete'), url(r'^qr_code/?', views.StockLocationQRCode.as_view(), name='stock-location-qr'), - - url(r'sublocation/', views.StockLocationDetail.as_view(template_name='stock/sublocation.html'), name='stock-location-sublocation'), - + # Anything else url('^.*$', views.StockLocationDetail.as_view(), name='stock-location-detail'), ])), From 533a3aa3680c82817faef443719aab1ab578e243 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 22:19:13 +1000 Subject: [PATCH 411/445] Refactor StockItem pages --- InvenTree/stock/templates/stock/item.html | 360 ++++++++++++++++-- .../templates/stock/item_attachments.html | 86 ----- .../stock/templates/stock/item_base.html | 6 + .../stock/templates/stock/item_childs.html | 45 --- .../stock/templates/stock/item_installed.html | 53 --- .../stock/templates/stock/item_notes.html | 51 --- .../stock/templates/stock/item_tests.html | 150 -------- InvenTree/stock/templates/stock/navbar.html | 24 +- InvenTree/stock/urls.py | 6 - InvenTree/templates/stock_table.html | 4 +- 10 files changed, 358 insertions(+), 427 deletions(-) delete mode 100644 InvenTree/stock/templates/stock/item_attachments.html delete mode 100644 InvenTree/stock/templates/stock/item_childs.html delete mode 100644 InvenTree/stock/templates/stock/item_installed.html delete mode 100644 InvenTree/stock/templates/stock/item_notes.html delete mode 100644 InvenTree/stock/templates/stock/item_tests.html diff --git a/InvenTree/stock/templates/stock/item.html b/InvenTree/stock/templates/stock/item.html index 7564e7864e..8a00c1c5e6 100644 --- a/InvenTree/stock/templates/stock/item.html +++ b/InvenTree/stock/templates/stock/item.html @@ -3,44 +3,360 @@ {% load static %} {% load inventree_extras %} {% load i18n %} +{% load markdownify %} {% block menubar %} -{% include "stock/navbar.html" with tab="tracking" %} +{% include "stock/navbar.html" %} {% endblock %} -{% block heading %} -{% trans "Stock Tracking Information" %} -{% endblock %} +{% block page_content %} -{% block details %} +
          +
          +

          {% trans "Stock Tracking Information" %}

          +
          +
          + {% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %} + {% if owner_control.value == "True" %} + {% authorized_owners item.owner as owners %} + {% endif %} + + {% if owner_control.value == "False" or owner_control.value == "True" and user in owners %} + {% if roles.stock.change and not item.is_building %} +
          +
          + +
          +
          + {% endif %} + {% endif %} + +
          +
          +
          -{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %} -{% if owner_control.value == "True" %} - {% authorized_owners item.owner as owners %} -{% endif %} +
          +
          +

          {% trans "Child Stock Items" %}

          +
          +
          + {% if item.child_count > 0 %} + {% include "stock_table.html" with prefix="childs-" %} + {% else %} +
          + {% trans "This stock item does not have any child items" %} +
          + {% endif %} +
          +
          -
          +
          +
          +

          {% trans "Test Data" %}

          +
          +
          +
          +
          +
          + {% if user.is_staff %} + + {% endif %} + + +
          +
          + +
          +
          +
          + +
          +
          +
          - -{% if owner_control.value == "False" or owner_control.value == "True" and user in owners %} - {% if roles.stock.change and not item.is_building %} -
          -
          - +
          +
          +

          {% trans "Attachments" %}

          +
          +
          + {% include "attachment_table.html" %} +
          +
          + +
          +
          +
          +
          +

          {% trans "Stock Item Notes" %}

          +
          +
          +
          + +
          +
          - {% endif %} -{% endif %} - -
          +
          + {% if item.notes %} + {{ item.notes | markdownify }} + {% endif %} +
          +
          + +
          +
          +

          {% trans "Installed Stock Items" %}

          +
          +
          +
          +
          +
          {% endblock %} {% block js_ready %} {{ block.super }} + loadInstalledInTable( + $('#installed-table'), + { + stock_item: {{ item.pk }}, + part: {{ item.part.pk }}, + quantity: {{ item.quantity }}, + } + ); + + $('#multi-item-uninstall').click(function() { + + var selections = $('#installed-table').bootstrapTable('getSelections'); + + var items = []; + + selections.forEach(function(item) { + items.push(item.pk); + }); + + launchModalForm( + "{% url 'stock-item-uninstall' %}", + { + data: { + 'items[]': items, + }, + reload: true, + } + ); + }); + + $('#edit-notes').click(function() { + constructForm('{% url "api-stock-detail" item.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Notes" %}', + reload: true, + }); + }); + + enableDragAndDrop( + '#attachment-dropzone', + "{% url 'api-stock-attachment-list' %}", + { + data: { + stock_item: {{ item.id }}, + }, + label: 'attachment', + success: function(data, status, xhr) { + reloadAttachmentTable(); + } + } + ); + + loadAttachmentTable( + '{% url "api-stock-attachment-list" %}', + { + filters: { + stock_item: {{ item.pk }}, + }, + onEdit: function(pk) { + var url = `/api/stock/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + title: '{% trans "Edit Attachment" %}', + onSuccess: reloadAttachmentTable + }); + }, + onDelete: function(pk) { + var url = `/api/stock/attachment/${pk}/`; + + constructForm(url, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } + ); + + $("#new-attachment").click(function() { + + constructForm( + '{% url "api-stock-attachment-list" %}', + { + method: 'POST', + fields: { + attachment: {}, + comment: {}, + stock_item: { + value: {{ item.pk }}, + hidden: true, + }, + }, + reload: true, + title: '{% trans "Add Attachment" %}', + } + ); + }); + + loadStockTestResultsTable( + $("#test-result-table"), { + part: {{ item.part.id }}, + stock_item: {{ item.id }}, + } + ); + + function reloadTable() { + $("#test-result-table").bootstrapTable("refresh"); + } + + {% if item.has_test_reports %} + $("#test-report").click(function() { + printTestReports([{{ item.pk }}]); + }); + {% endif %} + + {% if user.is_staff %} + $("#delete-test-results").click(function() { + launchModalForm( + "{% url 'stock-item-delete-test-data' item.id %}", + { + success: reloadTable, + } + ); + }); + {% endif %} + + $("#add-test-result").click(function() { + + constructForm('{% url "api-stock-test-result-list" %}', { + method: 'POST', + fields: { + test: {}, + result: {}, + value: {}, + attachment: {}, + notes: {}, + stock_item: { + value: {{ item.pk }}, + hidden: true, + } + }, + title: '{% trans "Add Test Result" %}', + onSuccess: reloadTable, + }); + }); + + $("#test-result-table").on('click', '.button-test-add', function() { + var button = $(this); + + var test_name = button.attr('pk'); + + constructForm('{% url "api-stock-test-result-list" %}', { + method: 'POST', + fields: { + test: { + value: test_name, + }, + result: {}, + value: {}, + attachment: {}, + notes: {}, + stock_item: { + value: {{ item.pk }}, + hidden: true, + } + }, + title: '{% trans "Add Test Result" %}', + onSuccess: reloadTable, + }); + }); + + $("#test-result-table").on('click', '.button-test-edit', function() { + var button = $(this); + + var pk = button.attr('pk'); + + var url = `/api/stock/test/${pk}/`; + + constructForm(url, { + fields: { + test: {}, + result: {}, + value: {}, + attachment: {}, + notes: {}, + }, + title: '{% trans "Edit Test Result" %}', + onSuccess: reloadTable, + }); + }); + + $("#test-result-table").on('click', '.button-test-delete', function() { + var button = $(this); + + var pk = button.attr('pk'); + + var url = `/api/stock/test/${pk}/`; + + constructForm(url, { + method: 'DELETE', + title: '{% trans "Delete Test Result" %}', + onSuccess: reloadTable, + }); + }); + + {% if item.child_count > 0 %} + loadStockTable($("#childs-stock-table"), { + params: { + location_detail: true, + part_detail: false, + ancestor: {{ item.id }}, + }, + name: 'item-childs', + groupByField: 'location', + buttons: [ + '#stock-options', + ], + url: "{% url 'api-stock-list' %}", + }); + {% endif %} + $("#new-entry").click(function() { launchModalForm( "{% url 'stock-tracking-create' item.id %}", diff --git a/InvenTree/stock/templates/stock/item_attachments.html b/InvenTree/stock/templates/stock/item_attachments.html deleted file mode 100644 index 5f9cfdee19..0000000000 --- a/InvenTree/stock/templates/stock/item_attachments.html +++ /dev/null @@ -1,86 +0,0 @@ -{% extends "stock/item_base.html" %} - -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "stock/navbar.html" with tab='attachments' %} -{% endblock %} - -{% block heading %} -{% trans "Stock Item Attachments" %} -{% endblock %} - -{% block details %} -{% include "attachment_table.html" with attachments=item.attachments.all %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -enableDragAndDrop( - '#attachment-dropzone', - "{% url 'api-stock-attachment-list' %}", - { - data: { - stock_item: {{ item.id }}, - }, - label: 'attachment', - success: function(data, status, xhr) { - reloadAttachmentTable(); - } - } - ); - -loadAttachmentTable( - '{% url "api-stock-attachment-list" %}', - { - filters: { - stock_item: {{ item.pk }}, - }, - onEdit: function(pk) { - var url = `/api/stock/attachment/${pk}/`; - - constructForm(url, { - fields: { - comment: {}, - }, - title: '{% trans "Edit Attachment" %}', - onSuccess: reloadAttachmentTable - }); - }, - onDelete: function(pk) { - var url = `/api/stock/attachment/${pk}/`; - - constructForm(url, { - method: 'DELETE', - confirmMessage: '{% trans "Confirm Delete Operation" %}', - title: '{% trans "Delete Attachment" %}', - onSuccess: reloadAttachmentTable, - }); - } - } -); - -$("#new-attachment").click(function() { - - constructForm( - '{% url "api-stock-attachment-list" %}', - { - method: 'POST', - fields: { - attachment: {}, - comment: {}, - stock_item: { - value: {{ item.pk }}, - hidden: true, - }, - }, - reload: true, - title: '{% trans "Add Attachment" %}', - } - ); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index ea57b981d8..547806e256 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -428,6 +428,7 @@ {% endif %} + {% endblock %} {% block js_ready %} @@ -610,4 +611,9 @@ $("#stock-return-from-customer").click(function() { {% endif %} +attachNavCallbacks({ + name: 'stockitem', + default: 'history' +}); + {% endblock %} diff --git a/InvenTree/stock/templates/stock/item_childs.html b/InvenTree/stock/templates/stock/item_childs.html deleted file mode 100644 index f5d80e5ad1..0000000000 --- a/InvenTree/stock/templates/stock/item_childs.html +++ /dev/null @@ -1,45 +0,0 @@ -{% extends "stock/item_base.html" %} - -{% load static %} -{% load i18n %} - - -{% block menubar %} -{% include "stock/navbar.html" with tab='children' %} -{% endblock %} - -{% block heading %} -{% trans "Child Stock Items" %} -{% endblock %} - -{% block details %} -{% if item.child_count > 0 %} -{% include "stock_table.html" %} -{% else %} -
          - {% trans "This stock item does not have any child items" %} -
          -{% endif %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -{% if item.child_count > 0 %} -loadStockTable($("#stock-table"), { - params: { - location_detail: true, - part_detail: false, - ancestor: {{ item.id }}, - }, - name: 'item-childs', - groupByField: 'location', - buttons: [ - '#stock-options', - ], - url: "{% url 'api-stock-list' %}", -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/item_installed.html b/InvenTree/stock/templates/stock/item_installed.html deleted file mode 100644 index 8902fe00ef..0000000000 --- a/InvenTree/stock/templates/stock/item_installed.html +++ /dev/null @@ -1,53 +0,0 @@ -{% extends "stock/item_base.html" %} - -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "stock/navbar.html" with tab='installed' %} -{% endblock %} - -{% block heading %} -{% trans "Installed Stock Items" %} -{% endblock %} - -{% block details %} -
          - -{% endblock %} - -{% block js_ready %} - -{{ block.super }} - -loadInstalledInTable( - $('#installed-table'), - { - stock_item: {{ item.pk }}, - part: {{ item.part.pk }}, - quantity: {{ item.quantity }}, - } -); - -$('#multi-item-uninstall').click(function() { - - var selections = $('#installed-table').bootstrapTable('getSelections'); - - var items = []; - - selections.forEach(function(item) { - items.push(item.pk); - }); - - launchModalForm( - "{% url 'stock-item-uninstall' %}", - { - data: { - 'items[]': items, - }, - reload: true, - } - ); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/item_notes.html b/InvenTree/stock/templates/stock/item_notes.html deleted file mode 100644 index 788f7fb3bd..0000000000 --- a/InvenTree/stock/templates/stock/item_notes.html +++ /dev/null @@ -1,51 +0,0 @@ -{% extends "stock/item_base.html" %} - -{% load static %} -{% load inventree_extras %} -{% load i18n %} -{% load markdownify %} - -{% block menubar %} -{% include "stock/navbar.html" with tab="notes" %} -{% endblock %} - -{% block heading %} -{% trans "Stock Item Notes" %} -{% if roles.stock.change and not editing %} - -{% endif %} -{% endblock %} - -{% block details %} -{% if editing %} -
          - {% csrf_token %} - - {{ form }} -
          - -
          - -{{ form.media }} - -{% else %} -{% if item.notes %} -{{ item.notes | markdownify }} -{% endif %} - -{% endif %} - -{% endblock %} - -{% block js_ready %} - -{{ block.super }} - -{% if editing %} -{% else %} -$("#edit-notes").click(function() { - location.href = "{% url 'stock-item-notes' item.id %}?edit=1"; -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/item_tests.html b/InvenTree/stock/templates/stock/item_tests.html deleted file mode 100644 index d7d26fcbba..0000000000 --- a/InvenTree/stock/templates/stock/item_tests.html +++ /dev/null @@ -1,150 +0,0 @@ -{% extends "stock/item_base.html" %} - -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "stock/navbar.html" with tab='tests' %} -{% endblock %} - -{% block heading %} -{% trans "Test Data" %} -{% endblock %} - -{% block details %} -
          -
          -
          - {% if user.is_staff %} - - {% endif %} - - -
          -
          - -
          -
          -
          - -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadStockTestResultsTable( - $("#test-result-table"), { - part: {{ item.part.id }}, - stock_item: {{ item.id }}, - } -); - -function reloadTable() { - $("#test-result-table").bootstrapTable("refresh"); -} - -{% if item.has_test_reports %} -$("#test-report").click(function() { - printTestReports([{{ item.pk }}]); -}); -{% endif %} - -{% if user.is_staff %} -$("#delete-test-results").click(function() { - launchModalForm( - "{% url 'stock-item-delete-test-data' item.id %}", - { - success: reloadTable, - } - ); -}); -{% endif %} - -$("#add-test-result").click(function() { - - constructForm('{% url "api-stock-test-result-list" %}', { - method: 'POST', - fields: { - test: {}, - result: {}, - value: {}, - attachment: {}, - notes: {}, - stock_item: { - value: {{ item.pk }}, - hidden: true, - } - }, - title: '{% trans "Add Test Result" %}', - onSuccess: reloadTable, - }); -}); - -$("#test-result-table").on('click', '.button-test-add', function() { - var button = $(this); - - var test_name = button.attr('pk'); - - constructForm('{% url "api-stock-test-result-list" %}', { - method: 'POST', - fields: { - test: { - value: test_name, - }, - result: {}, - value: {}, - attachment: {}, - notes: {}, - stock_item: { - value: {{ item.pk }}, - hidden: true, - } - }, - title: '{% trans "Add Test Result" %}', - onSuccess: reloadTable, - }); -}); - -$("#test-result-table").on('click', '.button-test-edit', function() { - var button = $(this); - - var pk = button.attr('pk'); - - var url = `/api/stock/test/${pk}/`; - - constructForm(url, { - fields: { - test: {}, - result: {}, - value: {}, - attachment: {}, - notes: {}, - }, - title: '{% trans "Edit Test Result" %}', - onSuccess: reloadTable, - }); -}); - -$("#test-result-table").on('click', '.button-test-delete', function() { - var button = $(this); - - var pk = button.attr('pk'); - - var url = `/api/stock/test/${pk}/`; - - constructForm(url, { - method: 'DELETE', - title: '{% trans "Delete Test Result" %}', - onSuccess: reloadTable, - }); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/navbar.html b/InvenTree/stock/templates/stock/navbar.html index 7c7d197a1a..90c0075ba0 100644 --- a/InvenTree/stock/templates/stock/navbar.html +++ b/InvenTree/stock/templates/stock/navbar.html @@ -8,24 +8,24 @@
        • -
        • - +
        • + {% trans "History" %}
        • {% if item.part.trackable %} -
        • - +
        • + {% trans "Test Data" %}
        • {% if item.part.assembly %} -
        • - +
        • + {% trans "Installed Items" %} @@ -35,8 +35,8 @@ {% endif %} {% if item.child_count > 0 %} -
        • - +
        • + {% trans "Children" %} @@ -44,15 +44,15 @@ {% endif %} -
        • - +
        • + {% trans "Attachments" %}
        • -
        • - +
        • + {% trans "Notes" %} diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index adae836d92..bcf180b700 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -34,12 +34,6 @@ stock_item_detail_urls = [ url(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'), - url(r'^test/', views.StockItemDetail.as_view(template_name='stock/item_tests.html'), name='stock-item-test-results'), - url(r'^children/', views.StockItemDetail.as_view(template_name='stock/item_childs.html'), name='stock-item-children'), - url(r'^attachments/', views.StockItemDetail.as_view(template_name='stock/item_attachments.html'), name='stock-item-attachments'), - url(r'^installed/', views.StockItemDetail.as_view(template_name='stock/item_installed.html'), name='stock-item-installed'), - url(r'^notes/', views.StockItemNotes.as_view(), name='stock-item-notes'), - url('^.*$', views.StockItemDetail.as_view(), name='stock-item-detail'), ] diff --git a/InvenTree/templates/stock_table.html b/InvenTree/templates/stock_table.html index d917bac72a..583f4db893 100644 --- a/InvenTree/templates/stock_table.html +++ b/InvenTree/templates/stock_table.html @@ -8,7 +8,7 @@ {% authorized_owners location.owner as owners %} {% endif %} -
          +
          - +
          From 0fc558068fad936f3a80b9e8ad74c9b11d2aa8bf Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 22:40:14 +1000 Subject: [PATCH 412/445] Refactor BuildOrder pages --- InvenTree/build/templates/build/allocate.html | 101 ---- .../build/templates/build/attachments.html | 84 --- .../build/templates/build/build_base.html | 6 + .../build/templates/build/build_children.html | 40 -- .../build/templates/build/build_output.html | 103 ---- InvenTree/build/templates/build/detail.html | 558 ++++++++++++++---- InvenTree/build/templates/build/navbar.html | 25 +- InvenTree/build/templates/build/notes.html | 51 -- InvenTree/build/urls.py | 15 +- InvenTree/build/views.py | 56 +- InvenTree/templates/js/nav.js | 1 - 11 files changed, 458 insertions(+), 582 deletions(-) delete mode 100644 InvenTree/build/templates/build/allocate.html delete mode 100644 InvenTree/build/templates/build/attachments.html delete mode 100644 InvenTree/build/templates/build/build_children.html delete mode 100644 InvenTree/build/templates/build/build_output.html delete mode 100644 InvenTree/build/templates/build/notes.html diff --git a/InvenTree/build/templates/build/allocate.html b/InvenTree/build/templates/build/allocate.html deleted file mode 100644 index de07614c8e..0000000000 --- a/InvenTree/build/templates/build/allocate.html +++ /dev/null @@ -1,101 +0,0 @@ -{% extends "build/build_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block page_title %} -{% inventree_title %} | {% trans "Allocate Parts" %} -{% endblock %} - -{% block menubar %} -{% include "build/navbar.html" with tab='allocate' %} -{% endblock %} - -{% block heading %} -{% trans "Allocate Stock to Build" %} -{% endblock %} - -{% block details %} -{% if build.has_untracked_bom_items %} -{% if build.active %} -
          - - - -
          -{% if build.areUntrackedPartsFullyAllocated %} -
          - {% trans "Untracked stock has been fully allocated for this Build Order" %} -
          -{% else %} -
          - {% trans "Untracked stock has not been fully allocated for this Build Order" %} -
          -{% endif %} -{% endif %} -
          -{% else %} -
          - {% trans "This Build Order does not have any associated untracked BOM items" %} -
          -{% endif %} -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - var buildInfo = { - pk: {{ build.pk }}, - quantity: {{ build.quantity }}, - completed: {{ build.completed }}, - part: {{ build.part.pk }}, - }; - - {% if build.has_untracked_bom_items %} - // Load allocation table for un-tracked parts - loadBuildOutputAllocationTable(buildInfo, null); - {% endif %} - - function reloadTable() { - $('#allocation-table-untracked').bootstrapTable('refresh'); - } - - {% if build.active %} - $("#btn-auto-allocate").on('click', function() { - launchModalForm( - "{% url 'build-auto-allocate' build.id %}", - { - success: reloadTable, - } - ); - }); - - $('#btn-unallocate').on('click', function() { - launchModalForm( - "{% url 'build-unallocate' build.id %}", - { - success: reloadTable, - } - ); - }); - - $("#btn-order-parts").click(function() { - launchModalForm("/order/purchase-order/order-parts/", { - data: { - build: {{ build.id }}, - }, - }); - }); - - {% endif %} - -{% endblock %} - \ No newline at end of file diff --git a/InvenTree/build/templates/build/attachments.html b/InvenTree/build/templates/build/attachments.html deleted file mode 100644 index e969756b81..0000000000 --- a/InvenTree/build/templates/build/attachments.html +++ /dev/null @@ -1,84 +0,0 @@ -{% extends "build/build_base.html" %} - -{% load static %} -{% load i18n %} -{% load markdownify %} - -{% block menubar %} -{% include "build/navbar.html" with tab='attachments' %} -{% endblock %} - -{% block heading %} -{% trans "Attachments" %} -{% endblock %} - -{% block details %} -{% include "attachment_table.html" with attachments=build.attachments.all %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -enableDragAndDrop( - '#attachment-dropzone', - '{% url "api-build-attachment-list" %}', - { - data: { - build: {{ build.id }}, - }, - label: 'attachment', - success: function(data, status, xhr) { - location.reload(); - } - } -); - -// Callback for creating a new attachment -$('#new-attachment').click(function() { - - constructForm('{% url "api-build-attachment-list" %}', { - fields: { - attachment: {}, - comment: {}, - build: { - value: {{ build.pk }}, - hidden: true, - } - }, - method: 'POST', - onSuccess: reloadAttachmentTable, - title: '{% trans "Add Attachment" %}', - }); -}); - -loadAttachmentTable( - '{% url "api-build-attachment-list" %}', - { - filters: { - build: {{ build.pk }}, - }, - onEdit: function(pk) { - var url = `/api/build/attachment/${pk}/`; - - constructForm(url, { - fields: { - comment: {}, - }, - onSuccess: reloadAttachmentTable, - title: '{% trans "Edit Attachment" %}', - }); - }, - onDelete: function(pk) { - - constructForm(`/api/build/attachment/${pk}/`, { - method: 'DELETE', - confirmMessage: '{% trans "Confirm Delete Operation" %}', - title: '{% trans "Delete Attachment" %}', - onSuccess: reloadAttachmentTable, - }); - } - } -); - -{% endblock %} diff --git a/InvenTree/build/templates/build/build_base.html b/InvenTree/build/templates/build/build_base.html index 7100e82838..5770777d28 100644 --- a/InvenTree/build/templates/build/build_base.html +++ b/InvenTree/build/templates/build/build_base.html @@ -238,4 +238,10 @@ src="{% static 'img/blank_image.png' %}" ); }); + attachNavCallbacks({ + name: 'buildorder', + default: 'details' + }); + + {% endblock %} \ No newline at end of file diff --git a/InvenTree/build/templates/build/build_children.html b/InvenTree/build/templates/build/build_children.html deleted file mode 100644 index 3bab257d81..0000000000 --- a/InvenTree/build/templates/build/build_children.html +++ /dev/null @@ -1,40 +0,0 @@ -{% extends "build/build_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "build/navbar.html" with tab="children" %} -{% endblock %} - -{% block heading %} -{% trans "Child Build Orders" %} -{% endblock %} - - -{% block details %} -
          -
          -
          - -
          -
          - -
          - -
          - -{% endblock %} - -{% block js_ready %} - -{{ block.super }} - -loadBuildTable($('#sub-build-table'), { - url: '{% url "api-build-list" %}', - filterTarget: "#filter-list-sub-build", - params: { - ancestor: {{ build.pk }}, - } -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/build/templates/build/build_output.html b/InvenTree/build/templates/build/build_output.html deleted file mode 100644 index 00d7c5d5d2..0000000000 --- a/InvenTree/build/templates/build/build_output.html +++ /dev/null @@ -1,103 +0,0 @@ -{% extends "build/build_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "build/navbar.html" with tab='output' %} -{% endblock %} - -{% block content_panels %} - -{% if not build.is_complete %} -
          -
          -

          - {% trans "Incomplete Build Outputs" %} -

          -
          - -
          -
          - {% if build.active %} - - {% endif %} -
          - - {% if build.incomplete_outputs %} -
          - {% for item in build.incomplete_outputs %} - {% include "build/allocation_card.html" with item=item tracked_items=build.has_tracked_bom_items %} - {% endfor %} -
          - {% else %} -
          - {% trans "Create a new build output" %}
          - {% trans "No incomplete build outputs remain." %}
          - {% trans "Create a new build output using the button above" %} -
          - {% endif %} - -
          -
          -{% endif %} - -
          -
          -

          - {% trans "Completed Build Outputs" %} -

          -
          - -
          - {% include "stock_table.html" with read_only=True %} -
          -
          - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -$('#btn-create-output').click(function() { - launchModalForm('{% url "build-output-create" build.id %}', - { - reload: true, - } - ); -}); - -loadStockTable($("#stock-table"), { - params: { - location_detail: true, - part_detail: true, - build: {{ build.id }}, - }, - groupByField: 'location', - buttons: [ - '#stock-options', - ], - url: "{% url 'api-stock-list' %}", -}); - -var buildInfo = { - pk: {{ build.pk }}, - quantity: {{ build.quantity }}, - completed: {{ build.completed }}, - part: {{ build.part.pk }}, -}; - -{% for item in build.incomplete_outputs %} -// Get the build output as a javascript object -inventreeGet('{% url 'api-stock-detail' item.pk %}', {}, - { - success: function(response) { - loadBuildOutputAllocationTable(buildInfo, response); - } - } -); -{% endfor %} - - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/build/templates/build/detail.html b/InvenTree/build/templates/build/detail.html index 63c04f7590..fe716b87f2 100644 --- a/InvenTree/build/templates/build/detail.html +++ b/InvenTree/build/templates/build/detail.html @@ -2,142 +2,446 @@ {% load static %} {% load i18n %} {% load status_codes %} +{% load markdownify %} {% block menubar %} -{% include "build/navbar.html" with tab='details' %} +{% include "build/navbar.html" %} {% endblock %} -{% block heading %} -{% trans "Build Details" %} -{% endblock %} +{% block page_content %} -{% block details %} -
          -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {% if build.batch %} - - - - - - {% endif %} - {% if build.parent %} - - - - - - {% endif %} - {% if build.sales_order %} - - - - - - {% endif %} - {% if build.link %} - - - - - - {% endif %} - {% if build.issued_by %} - - - - - - {% endif %} - {% if build.responsible %} - - - - - - {% endif %} -
          {% trans "Description" %}{{ build.title }}{% include "clip.html"%}
          {% trans "Part" %}{{ build.part.full_name }}{% include "clip.html"%}
          {% trans "Quantity" %}{{ build.quantity }}
          {% trans "Stock Source" %} - {% if build.take_from %} - {{ build.take_from }}{% include "clip.html"%} - {% else %} - {% trans "Stock can be taken from any available location." %} - {% endif %} -
          {% trans "Destination" %} - {% if build.destination %} - - {{ build.destination }} - {% include "clip.html"%} - {% else %} - {% trans "Destination location not specified" %} - {% endif %} -
          {% trans "Status" %}{% build_status_label build.status %}
          {% trans "Progress" %}{{ build.completed }} / {{ build.quantity }}
          {% trans "Batch" %}{{ build.batch }}{% include "clip.html"%}
          {% trans "Parent Build" %}{{ build.parent }}{% include "clip.html"%}
          {% trans "Sales Order" %}{{ build.sales_order }}{% include "clip.html"%}
          {% trans "External Link" %}{{ build.link }}{% include "clip.html"%}
          {% trans "Issued By" %}{{ build.issued_by }}
          {% trans "Responsible" %}{{ build.responsible }}
          +
          +
          +

          {% trans "Build Details" %}

          -
          - - - - - - - - - - - {% if build.target_date %} - - {% else %} - +
          +
          +
          +
          {% trans "Created" %}{{ build.creation_date }}
          {% trans "Target Date" %} - {{ build.target_date }}{% if build.is_overdue %} {% endif %} - {% trans "No target date set" %}
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {% if build.batch %} + + + + + {% endif %} - - - - - {% if build.completion_date %} - - {% else %} - + {% if build.parent %} + + + + + {% endif %} - -
          {% trans "Description" %}{{ build.title }}{% include "clip.html"%}
          {% trans "Part" %}{{ build.part.full_name }}{% include "clip.html"%}
          {% trans "Quantity" %}{{ build.quantity }}
          {% trans "Stock Source" %} + {% if build.take_from %} + {{ build.take_from }}{% include "clip.html"%} + {% else %} + {% trans "Stock can be taken from any available location." %} + {% endif %} +
          {% trans "Destination" %} + {% if build.destination %} + + {{ build.destination }} + {% include "clip.html"%} + {% else %} + {% trans "Destination location not specified" %} + {% endif %} +
          {% trans "Status" %}{% build_status_label build.status %}
          {% trans "Progress" %}{{ build.completed }} / {{ build.quantity }}
          {% trans "Batch" %}{{ build.batch }}{% include "clip.html"%}
          {% trans "Completed" %}{{ build.completion_date }}{% if build.completed_by %}{{ build.completed_by }}{% endif %}{% trans "Build not complete" %}
          {% trans "Parent Build" %}{{ build.parent }}{% include "clip.html"%}
          + {% if build.sales_order %} + + + {% trans "Sales Order" %} + {{ build.sales_order }}{% include "clip.html"%} + + {% endif %} + {% if build.link %} + + + {% trans "External Link" %} + {{ build.link }}{% include "clip.html"%} + + {% endif %} + {% if build.issued_by %} + + + {% trans "Issued By" %} + {{ build.issued_by }} + + {% endif %} + {% if build.responsible %} + + + {% trans "Responsible" %} + {{ build.responsible }} + + {% endif %} + +
          +
          + + + + + + + + + + + {% if build.target_date %} + + {% else %} + + {% endif %} + + + + + {% if build.completion_date %} + + {% else %} + + {% endif %} + +
          {% trans "Created" %}{{ build.creation_date }}
          {% trans "Target Date" %} + {{ build.target_date }}{% if build.is_overdue %} {% endif %} + {% trans "No target date set" %}
          {% trans "Completed" %}{{ build.completion_date }}{% if build.completed_by %}{{ build.completed_by }}{% endif %}{% trans "Build not complete" %}
          +
          +
          +
          +
          +

          {% trans "Child Build Orders" %}

          +
          +
          +
          +
          +
          + +
          +
          +
          +
          +
          +
          + +
          +
          +

          {% trans "Allocate Stock to Build" %}

          +
          +
          + {% if build.has_untracked_bom_items %} + {% if build.active %} +
          + + + +
          + {% if build.areUntrackedPartsFullyAllocated %} +
          + {% trans "Untracked stock has been fully allocated for this Build Order" %} +
          + {% else %} +
          + {% trans "Untracked stock has not been fully allocated for this Build Order" %} +
          + {% endif %} + {% endif %} +
          + {% else %} +
          + {% trans "This Build Order does not have any associated untracked BOM items" %} +
          + {% endif %} +
          +
          + +
          + {% if not build.is_complete %} +
          +

          {% trans "Incomplete Build Outputs" %}

          +
          +
          +
          + {% if build.active %} + + {% endif %} +
          + + {% if build.incomplete_outputs %} +
          + {% for item in build.incomplete_outputs %} + {% include "build/allocation_card.html" with item=item tracked_items=build.has_tracked_bom_items %} + {% endfor %} +
          + {% else %} +
          + {% trans "Create a new build output" %}
          + {% trans "No incomplete build outputs remain." %}
          + {% trans "Create a new build output using the button above" %} +
          + {% endif %} +
          + {% endif %} + +
          +

          + {% trans "Completed Build Outputs" %} +

          +
          + +
          + {% include "stock_table.html" with read_only=True prefix="build-" %} +
          +
          + +
          +
          +

          {% trans "Attachments" %}

          +
          +
          + {% include "attachment_table.html" %} +
          +
          + +
          +
          +
          +
          +

          {% trans "Build Notes" %}

          +
          +
          +
          + +
          +
          +
          +
          +
          + {% if build.notes %} + {{ build.notes | markdownify }} + {% endif %} +
          +
          + + {% endblock %} + +{% block js_ready %} +{{ block.super }} + +$('#btn-create-output').click(function() { + launchModalForm('{% url "build-output-create" build.id %}', + { + reload: true, + } + ); +}); + +loadStockTable($("#build-stock-table"), { + params: { + location_detail: true, + part_detail: true, + build: {{ build.id }}, + }, + groupByField: 'location', + buttons: [ + '#stock-options', + ], + url: "{% url 'api-stock-list' %}", +}); + +var buildInfo = { + pk: {{ build.pk }}, + quantity: {{ build.quantity }}, + completed: {{ build.completed }}, + part: {{ build.part.pk }}, +}; + +{% for item in build.incomplete_outputs %} +// Get the build output as a javascript object +inventreeGet('{% url 'api-stock-detail' item.pk %}', {}, + { + success: function(response) { + loadBuildOutputAllocationTable(buildInfo, response); + } + } +); +{% endfor %} + +loadBuildTable($('#sub-build-table'), { + url: '{% url "api-build-list" %}', + filterTarget: "#filter-list-sub-build", + params: { + ancestor: {{ build.pk }}, + } +}); + +enableDragAndDrop( + '#attachment-dropzone', + '{% url "api-build-attachment-list" %}', + { + data: { + build: {{ build.id }}, + }, + label: 'attachment', + success: function(data, status, xhr) { + location.reload(); + } + } +); + +// Callback for creating a new attachment +$('#new-attachment').click(function() { + + constructForm('{% url "api-build-attachment-list" %}', { + fields: { + attachment: {}, + comment: {}, + build: { + value: {{ build.pk }}, + hidden: true, + } + }, + method: 'POST', + onSuccess: reloadAttachmentTable, + title: '{% trans "Add Attachment" %}', + }); +}); + +loadAttachmentTable( + '{% url "api-build-attachment-list" %}', + { + filters: { + build: {{ build.pk }}, + }, + onEdit: function(pk) { + var url = `/api/build/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Edit Attachment" %}', + }); + }, + onDelete: function(pk) { + + constructForm(`/api/build/attachment/${pk}/`, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } +); + +$('#edit-notes').click(function() { + constructForm('{% url "api-build-detail" build.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Notes" %}', + reload: true, + }); +}); + +var buildInfo = { + pk: {{ build.pk }}, + quantity: {{ build.quantity }}, + completed: {{ build.completed }}, + part: {{ build.part.pk }}, +}; + +{% if build.has_untracked_bom_items %} +// Load allocation table for un-tracked parts +loadBuildOutputAllocationTable(buildInfo, null); +{% endif %} + +function reloadTable() { + $('#allocation-table-untracked').bootstrapTable('refresh'); +} + +{% if build.active %} +$("#btn-auto-allocate").on('click', function() { + launchModalForm( + "{% url 'build-auto-allocate' build.id %}", + { + success: reloadTable, + } + ); +}); + +$('#btn-unallocate').on('click', function() { + launchModalForm( + "{% url 'build-unallocate' build.id %}", + { + success: reloadTable, + } + ); +}); + +$("#btn-order-parts").click(function() { + launchModalForm("/order/purchase-order/order-parts/", { + data: { + build: {{ build.id }}, + }, + }); +}); + +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/build/templates/build/navbar.html b/InvenTree/build/templates/build/navbar.html index e6d2e644ce..e4c4fe4e50 100644 --- a/InvenTree/build/templates/build/navbar.html +++ b/InvenTree/build/templates/build/navbar.html @@ -9,46 +9,45 @@
        • -
        • - +
        • + {% trans "Details" %}
        • {% if build.active %} - -
        • - +
        • + {% trans "Allocate Stock" %}
        • {% endif %} -
        • - +
        • + {% trans "Build Outputs" %}
        • -
        • - +
        • + {% trans "Child Builds" %}
        • -
        • - +
        • + {% trans "Attachments" %}
        • -
        • - +
        • + {% trans "Notes" %} diff --git a/InvenTree/build/templates/build/notes.html b/InvenTree/build/templates/build/notes.html deleted file mode 100644 index 2bdbf07970..0000000000 --- a/InvenTree/build/templates/build/notes.html +++ /dev/null @@ -1,51 +0,0 @@ -{% extends "build/build_base.html" %} - -{% load static %} -{% load i18n %} -{% load markdownify %} - -{% block menubar %} -{% include "build/navbar.html" with tab='notes' %} -{% endblock %} - -{% block heading %} -{% trans "Build Notes" %} -{% if roles.build.change and not editing %} - -{% endif %} -{% endblock %} - -{% block details %} -{% if editing %} -
          -
          - {% csrf_token %} - - {{ form }} -
          - - -
          - -{{ form.media }} - -{% else %} - -{% if build.notes %} -{{ build.notes | markdownify }} -{% endif %} -{% endif %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -{% if editing %} -{% else %} -$("#edit-notes").click(function() { - location.href = "{% url 'build-notes' build.id %}?edit=1"; -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/build/urls.py b/InvenTree/build/urls.py index c354a17ac7..9814dc83f7 100644 --- a/InvenTree/build/urls.py +++ b/InvenTree/build/urls.py @@ -7,30 +7,23 @@ from django.conf.urls import url, include from . import views build_detail_urls = [ - url(r'^allocate/', views.BuildAllocate.as_view(), name='build-allocate'), url(r'^cancel/', views.BuildCancel.as_view(), name='build-cancel'), url(r'^delete/', views.BuildDelete.as_view(), name='build-delete'), url(r'^create-output/', views.BuildOutputCreate.as_view(), name='build-output-create'), url(r'^delete-output/', views.BuildOutputDelete.as_view(), name='build-output-delete'), - url(r'^complete-output/?', views.BuildOutputComplete.as_view(), name='build-output-complete'), - url(r'^auto-allocate/?', views.BuildAutoAllocate.as_view(), name='build-auto-allocate'), + url(r'^complete-output/', views.BuildOutputComplete.as_view(), name='build-output-complete'), + url(r'^auto-allocate/', views.BuildAutoAllocate.as_view(), name='build-auto-allocate'), url(r'^unallocate/', views.BuildUnallocate.as_view(), name='build-unallocate'), url(r'^complete/', views.BuildComplete.as_view(), name='build-complete'), - url(r'^notes/', views.BuildNotes.as_view(), name='build-notes'), - - url(r'^children/', views.BuildDetail.as_view(template_name='build/build_children.html'), name='build-children'), - url(r'^attachments/', views.BuildDetail.as_view(template_name='build/attachments.html'), name='build-attachments'), - url(r'^output/', views.BuildDetail.as_view(template_name='build/build_output.html'), name='build-output'), - url(r'^.*$', views.BuildDetail.as_view(), name='build-detail'), ] build_urls = [ url(r'item/', include([ url(r'^(?P\d+)/', include([ - url('^edit/?', views.BuildItemEdit.as_view(), name='build-item-edit'), - url('^delete/?', views.BuildItemDelete.as_view(), name='build-item-delete'), + url('^edit/', views.BuildItemEdit.as_view(), name='build-item-edit'), + url('^delete/', views.BuildItemDelete.as_view(), name='build-item-delete'), ])), url('^new/', views.BuildItemCreate.as_view(), name='build-item-create'), ])), diff --git a/InvenTree/build/views.py b/InvenTree/build/views.py index 2bae825b0f..8d2a8bff80 100644 --- a/InvenTree/build/views.py +++ b/InvenTree/build/views.py @@ -593,31 +593,6 @@ class BuildOutputComplete(AjaxUpdateView): } -class BuildNotes(InvenTreeRoleMixin, UpdateView): - """ View for editing the 'notes' field of a Build object. - """ - - context_object_name = 'build' - template_name = 'build/notes.html' - model = Build - - # Override the default permission role for this View - role_required = 'build.view' - - fields = ['notes'] - - def get_success_url(self): - return reverse('build-notes', kwargs={'pk': self.get_object().id}) - - def get_context_data(self, **kwargs): - - ctx = super().get_context_data(**kwargs) - - ctx['editing'] = str2bool(self.request.GET.get('edit', '')) - - return ctx - - class BuildDetail(InvenTreeRoleMixin, DetailView): """ Detail view of a single Build object. """ @@ -635,36 +610,15 @@ class BuildDetail(InvenTreeRoleMixin, DetailView): ctx['BuildStatus'] = BuildStatus ctx['sub_build_count'] = build.sub_build_count() - return ctx - - -class BuildAllocate(InvenTreeRoleMixin, DetailView): - """ View for allocating parts to a Build """ - model = Build - context_object_name = 'build' - template_name = 'build/allocate.html' - - def get_context_data(self, **kwargs): - """ Provide extra context information for the Build allocation page """ - - context = super(DetailView, self).get_context_data(**kwargs) - - build = self.get_object() part = build.part bom_items = build.bom_items - context['part'] = part - context['bom_items'] = bom_items - context['has_tracked_bom_items'] = build.has_tracked_bom_items() - context['has_untracked_bom_items'] = build.has_untracked_bom_items() - context['BuildStatus'] = BuildStatus + ctx['part'] = part + ctx['bom_items'] = bom_items + ctx['has_tracked_bom_items'] = build.has_tracked_bom_items() + ctx['has_untracked_bom_items'] = build.has_untracked_bom_items() - context['bom_price'] = build.part.get_price_info(build.quantity, buy=False) - - if str2bool(self.request.GET.get('edit', None)): - context['editing'] = True - - return context + return ctx class BuildDelete(AjaxDeleteView): diff --git a/InvenTree/templates/js/nav.js b/InvenTree/templates/js/nav.js index f33571d584..aff3435b21 100644 --- a/InvenTree/templates/js/nav.js +++ b/InvenTree/templates/js/nav.js @@ -20,7 +20,6 @@ function attachNavCallbacks(options={}) { activatePanel(panelName, options); }); - var panelClass = options.name || 'unknown'; /* Look for a default panel to initialize From c61fc7c1dfda38023d3380c0226918941a0304ca Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 23:06:37 +1000 Subject: [PATCH 413/445] Refactor part pricing page --- InvenTree/build/views.py | 3 +- InvenTree/part/templates/part/detail.html | 152 ++++++ InvenTree/part/templates/part/navbar.html | 2 +- InvenTree/part/templates/part/prices.html | 618 ++++++++-------------- InvenTree/part/urls.py | 2 - InvenTree/part/views.py | 18 +- InvenTree/templates/js/build.js | 2 +- InvenTree/templates/js/part.js | 2 +- InvenTree/templates/js/stock.js | 2 +- 9 files changed, 366 insertions(+), 435 deletions(-) diff --git a/InvenTree/build/views.py b/InvenTree/build/views.py index 8d2a8bff80..dfa655f9a4 100644 --- a/InvenTree/build/views.py +++ b/InvenTree/build/views.py @@ -7,9 +7,8 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ from django.core.exceptions import ValidationError -from django.views.generic import DetailView, ListView, UpdateView +from django.views.generic import DetailView, ListView from django.forms import HiddenInput -from django.urls import reverse from part.models import Part from .models import Build, BuildItem diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 2cb430ccf8..d9ef212fae 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -1,6 +1,8 @@ {% extends "part/part_base.html" %} {% load static %} {% load i18n %} +{% load inventree_extras %} +{% load crispy_forms_tags %} {% load markdownify %} {% block menubar %} @@ -92,6 +94,10 @@
        • +
          + {% include "part/prices.html" %} +
          +
          @@ -893,6 +899,152 @@ }); }); + {% default_currency as currency %} + + // history graphs + {% if price_history %} + var purchasepricedata = { + labels: [ + {% for line in price_history %}'{{ line.date }}',{% endfor %} + ], + datasets: [{ + label: '{% blocktrans %}Single Price - {{currency}}{% endblocktrans %}', + backgroundColor: 'rgba(255, 99, 132, 0.2)', + borderColor: 'rgb(255, 99, 132)', + yAxisID: 'y', + data: [ + {% for line in price_history %}{{ line.price|stringformat:".2f" }},{% endfor %} + ], + borderWidth: 1, + type: 'line' + }, + {% if 'price_diff' in price_history.0 %} + { + label: '{% blocktrans %}Single Price Difference - {{currency}}{% endblocktrans %}', + backgroundColor: 'rgba(68, 157, 68, 0.2)', + borderColor: 'rgb(68, 157, 68)', + yAxisID: 'y2', + data: [ + {% for line in price_history %}{{ line.price_diff|stringformat:".2f" }},{% endfor %} + ], + borderWidth: 1, + type: 'line', + hidden: true, + }, + { + label: '{% blocktrans %}Part Single Price - {{currency}}{% endblocktrans %}', + backgroundColor: 'rgba(70, 127, 155, 0.2)', + borderColor: 'rgb(70, 127, 155)', + yAxisID: 'y', + data: [ + {% for line in price_history %}{{ line.price_part|stringformat:".2f" }},{% endfor %} + ], + borderWidth: 1, + type: 'line', + hidden: true, + }, + {% endif %} + { + label: '{% trans "Quantity" %}', + backgroundColor: 'rgba(255, 206, 86, 0.2)', + borderColor: 'rgb(255, 206, 86)', + yAxisID: 'y1', + data: [ + {% for line in price_history %}{{ line.qty|stringformat:"f" }},{% endfor %} + ], + borderWidth: 1 + }] + } + var StockPriceChart = loadStockPricingChart($('#StockPriceChart'), purchasepricedata) + {% endif %} + + {% if bom_parts %} + var bom_colors = randomColor({hue: 'green', count: {{ bom_parts|length }} }) + var bomdata = { + labels: [{% for line in bom_parts %}'{{ line.name }}',{% endfor %}], + datasets: [ + { + label: 'Price', + data: [{% for line in bom_parts %}{{ line.min_price }},{% endfor %}], + backgroundColor: bom_colors, + }, + {% if bom_pie_max %} + { + label: 'Max Price', + data: [{% for line in bom_parts %}{{ line.max_price }},{% endfor %}], + backgroundColor: bom_colors, + }, + {% endif %} + ] + }; + var BomChart = loadBomChart(document.getElementById('BomChart'), bomdata) + {% endif %} + + + // Internal pricebreaks + {% settings_value "PART_INTERNAL_PRICE" as show_internal_price %} + {% if show_internal_price and roles.sales_order.view %} + initPriceBreakSet( + $('#internal-price-break-table'), + { + part_id: {{part.id}}, + pb_human_name: 'internal price break', + pb_url_slug: 'internal-price', + pb_url: '{% url 'api-part-internal-price-list' %}', + pb_new_btn: $('#new-internal-price-break'), + pb_new_url: '{% url 'internal-price-break-create' %}', + linkedGraph: $('#InternalPriceBreakChart'), + }, + ); + {% endif %} + + // Sales pricebreaks + {% if part.salable and roles.sales_order.view %} + initPriceBreakSet( + $('#price-break-table'), + { + part_id: {{part.id}}, + pb_human_name: 'sale price break', + pb_url_slug: 'sale-price', + pb_url: "{% url 'api-part-sale-price-list' %}", + pb_new_btn: $('#new-price-break'), + pb_new_url: '{% url 'sale-price-break-create' %}', + linkedGraph: $('#SalePriceBreakChart'), + }, + ); + {% endif %} + + // Sale price history + {% if sale_history %} + var salepricedata = { + labels: [ + {% for line in sale_history %}'{{ line.date }}',{% endfor %} + ], + datasets: [{ + label: '{% blocktrans %}Unit Price - {{currency}}{% endblocktrans %}', + backgroundColor: 'rgba(255, 99, 132, 0.2)', + borderColor: 'rgb(255, 99, 132)', + yAxisID: 'y', + data: [ + {% for line in sale_history %}{{ line.price|stringformat:".2f" }},{% endfor %} + ], + borderWidth: 1, + }, + { + label: '{% trans "Quantity" %}', + backgroundColor: 'rgba(255, 206, 86, 0.2)', + borderColor: 'rgb(255, 206, 86)', + yAxisID: 'y1', + data: [ + {% for line in sale_history %}{{ line.qty|stringformat:"f" }},{% endfor %} + ], + borderWidth: 1, + type: 'bar', + }] + } + var SalePriceChart = loadSellPricingChart($('#SalePriceChart'), salepricedata) + {% endif %} + attachNavCallbacks({ name: 'part', default: 'part-stock' diff --git a/InvenTree/part/templates/part/navbar.html b/InvenTree/part/templates/part/navbar.html index 4f0e92a80d..8ea1204bc8 100644 --- a/InvenTree/part/templates/part/navbar.html +++ b/InvenTree/part/templates/part/navbar.html @@ -56,7 +56,7 @@ {% endif %}
        • - + {% trans "Prices" %} diff --git a/InvenTree/part/templates/part/prices.html b/InvenTree/part/templates/part/prices.html index 6e234d3dba..65d36e005a 100644 --- a/InvenTree/part/templates/part/prices.html +++ b/InvenTree/part/templates/part/prices.html @@ -1,176 +1,168 @@ -{% extends "part/part_base.html" %} {% load static %} {% load i18n %} {% load crispy_forms_tags %} {% load inventree_extras %} -{% block menubar %} -{% include 'part/navbar.html' with tab='prices' %} -{% endblock %} +
          +

          {% trans "Pricing Information" %}

          +
          -{% block heading %} -{% trans "General Price Information" %} -{% endblock %} - - -{% block details %} {% default_currency as currency %} +
          -
          - -
          -

          {% trans "Pricing ranges" %}

          - - {% if part.supplier_count > 0 %} - {% if min_total_buy_price %} - - - - - - - {% if quantity > 1 %} - - - - - - - {% endif %} - {% else %} - - - - {% endif %} - {% endif %} - - {% if part.bom_count > 0 %} - {% if min_total_bom_price %} - - - - - - - {% if quantity > 1 %} +
          + +
          +

          {% trans "Pricing ranges" %}

          +
          {% trans 'Supplier Pricing' %} - - - {% trans 'Unit Cost' %}Min: {% include "price.html" with price=min_unit_buy_price %}Max: {% include "price.html" with price=max_unit_buy_price %}
          {% trans 'Total Cost' %}Min: {% include "price.html" with price=min_total_buy_price %}Max: {% include "price.html" with price=max_total_buy_price %}
          - {% trans 'No supplier pricing available' %} -
          {% trans 'BOM Pricing' %} - - {% trans 'Unit Cost' %}Min: {% include "price.html" with price=min_unit_bom_price %}Max: {% include "price.html" with price=max_unit_bom_price %}
          + {% if part.supplier_count > 0 %} + {% if min_total_buy_price %} + + + + + + + {% if quantity > 1 %} - - + + - {% endif %} - {% if part.has_complete_bom_pricing == False %} + {% endif %} + {% else %} {% endif %} - {% else %} + {% endif %} + + {% if part.bom_count > 0 %} + {% if min_total_bom_price %} + + + + + + + {% if quantity > 1 %} + + + + + + + {% endif %} + {% if part.has_complete_bom_pricing == False %} + + + + {% endif %} + {% else %} + + + + {% endif %} + {% endif %} + + {% if show_internal_price and roles.sales_order.view %} + {% if total_internal_part_price %} - + + + + + + + + {% endif %} - {% endif %} - - {% if show_internal_price and roles.sales_order.view %} - {% if total_internal_part_price %} - - - - - - - - - - - {% endif %} - {% endif %} - - {% if total_part_price %} - - - - - - - - - - - {% endif %} -
          {% trans 'Supplier Pricing' %} + + + {% trans 'Unit Cost' %}Min: {% include "price.html" with price=min_unit_buy_price %}Max: {% include "price.html" with price=max_unit_buy_price %}
          {% trans 'Total Cost' %}Min: {% include "price.html" with price=min_total_bom_price %}Max: {% include "price.html" with price=max_total_bom_price %}Min: {% include "price.html" with price=min_total_buy_price %}Max: {% include "price.html" with price=max_total_buy_price %}
          - {% trans 'Note: BOM pricing is incomplete for this part' %} + {% trans 'No supplier pricing available' %}
          {% trans 'BOM Pricing' %} + + {% trans 'Unit Cost' %}Min: {% include "price.html" with price=min_unit_bom_price %}Max: {% include "price.html" with price=max_unit_bom_price %}
          {% trans 'Total Cost' %}Min: {% include "price.html" with price=min_total_bom_price %}Max: {% include "price.html" with price=max_total_bom_price %}
          + {% trans 'Note: BOM pricing is incomplete for this part' %} +
          + {% trans 'No BOM pricing available' %} +
          - {% trans 'No BOM pricing available' %} - {% trans 'Internal Price' %}{% trans 'Unit Cost' %}{% include "price.html" with price=unit_internal_part_price %}
          {% trans 'Total Cost' %}{% include "price.html" with price=total_internal_part_price %}
          {% trans 'Internal Price' %}{% trans 'Unit Cost' %}{% include "price.html" with price=unit_internal_part_price %}
          {% trans 'Total Cost' %}{% include "price.html" with price=total_internal_part_price %}
          {% trans 'Sale Price' %} - - - {% trans 'Unit Cost' %}{% include "price.html" with price=unit_part_price %}
          {% trans 'Total Cost' %}{% include "price.html" with price=total_part_price %}
          + {% endif %} + + {% if total_part_price %} + + {% trans 'Sale Price' %} + + + + {% trans 'Unit Cost' %} + {% include "price.html" with price=unit_part_price %} + + + + {% trans 'Total Cost' %} + {% include "price.html" with price=total_part_price %} + + {% endif %} + - {% if min_unit_buy_price or min_unit_bom_price %} - {% else %} -
          - {% trans 'No pricing information is available for this part.' %} -
          - {% endif %} -
          + {% if min_unit_buy_price or min_unit_bom_price %} + {% else %} +
          + {% trans 'No pricing information is available for this part.' %} +
          + {% endif %} +
          -
          -

          {% trans "Calculation parameters" %}

          -
          - {% csrf_token %} - {{ form|crispy }} - -
          +
          +

          {% trans "Calculation parameters" %}

          +
          + {% csrf_token %} + {{ form|crispy }} + +
          +
          -{% endblock %} -{% block post_content_panel %} -{% default_currency as currency %} {% settings_value "PART_INTERNAL_PRICE" as show_internal_price %} - {% if part.purchaseable and roles.purchase_order.view %} -
          - -
          -

          {% trans "Supplier Cost" %} - -

          -
          + +
          +

          {% trans "Supplier Cost" %} + +

          +
          -
          -
          -

          {% trans "Suppliers" %}

          -
          -
          -
          -

          {% trans "Manufacturers" %}

          -
          -
          -
          +
          +
          +
          +

          {% trans "Suppliers" %}

          +
          +
          +
          +

          {% trans "Manufacturers" %}

          +
          +
          +
          -
          - -
          -

          {% trans "Purchase Price" %} - -

          -
          - - {% if price_history %} -

          {% trans 'Stock Pricing' %}

          +{% if price_history %} + +
          +

          {% trans "Purchase Price" %} + +

          +
          +
          +

          {% trans 'Stock Pricing' %} + +

          {% if price_history|length > 0 %}
          @@ -180,52 +172,50 @@ {% trans 'No stock pricing history is available for this part.' %}
          {% endif %} - {% endif %}
          {% endif %} - +{% endif %} {% if show_internal_price and roles.sales_order.view %} -
          - -
          -

          {% trans "Internal Cost" %} - -

          -
          + +
          +

          {% trans "Internal Cost" %} + +

          +
          -
          -
          -
          - -
          +
          +
          +
          +
          +
          -
          -
          - -
          - - -
          +
          +
          +
          +
          -
          + + +
          +
          +
          {% endif %} - {% if part.has_bom and roles.sales_order.view %} -
          - -
          -

          {% trans "BOM Cost" %} - -

          -
          + +
          +

          {% trans "BOM Cost" %} + +

          +
          -
          +
          +
          @@ -238,251 +228,55 @@
          {% endif %} -
          +
          {% endif %} - {% if part.salable and roles.sales_order.view %} -
          - -
          -

          {% trans "Sale Cost" %} - -

          -
          + +
          +

          {% trans "Sale Cost" %} + +

          +
          -
          -
          -
          - -
          +
          +
          +
          +
          +
          -
          -
          - -
          - - -
          +
          +
          +
          +
          -
          + + +
          +
          +
          -
          - -
          -

          {% trans "Sale Price" %} - -

          -
          + +
          +

          {% trans "Sale Price" %} + +

          +
          -
          - {% if sale_history|length > 0 %} -
          - -
          - {% else %} -
          - {% trans 'No sale pice history available for this part.' %} -
          - {% endif %} +
          + {% if sale_history|length > 0 %} +
          +
          -
          + {% else %} +
          + {% trans 'No sale pice history available for this part.' %} +
          + {% endif %} +
          {% endif %} - -{% endblock %} - - - -{% block js_ready %} - {{ block.super }} - - {% default_currency as currency %} - - - loadSupplierPartTable( - "#supplier-table", - "{% url 'api-supplier-part-list' %}", - { - params: { - part: {{ part.id }}, - part_detail: false, - supplier_detail: true, - manufacturer_detail: true, - }, - } - ); - - loadManufacturerPartTable( - "#manufacturer-table", - "{% url 'api-manufacturer-part-list' %}", - { - params: { - part: {{ part.id }}, - part_detail: false, - manufacturer_detail: true, - }, - } - ); - - - // history graphs - {% if price_history %} - var purchasepricedata = { - labels: [ - {% for line in price_history %}'{{ line.date }}',{% endfor %} - ], - datasets: [{ - label: '{% blocktrans %}Single Price - {{currency}}{% endblocktrans %}', - backgroundColor: 'rgba(255, 99, 132, 0.2)', - borderColor: 'rgb(255, 99, 132)', - yAxisID: 'y', - data: [ - {% for line in price_history %}{{ line.price|stringformat:".2f" }},{% endfor %} - ], - borderWidth: 1, - type: 'line' - }, - {% if 'price_diff' in price_history.0 %} - { - label: '{% blocktrans %}Single Price Difference - {{currency}}{% endblocktrans %}', - backgroundColor: 'rgba(68, 157, 68, 0.2)', - borderColor: 'rgb(68, 157, 68)', - yAxisID: 'y2', - data: [ - {% for line in price_history %}{{ line.price_diff|stringformat:".2f" }},{% endfor %} - ], - borderWidth: 1, - type: 'line', - hidden: true, - }, - { - label: '{% blocktrans %}Part Single Price - {{currency}}{% endblocktrans %}', - backgroundColor: 'rgba(70, 127, 155, 0.2)', - borderColor: 'rgb(70, 127, 155)', - yAxisID: 'y', - data: [ - {% for line in price_history %}{{ line.price_part|stringformat:".2f" }},{% endfor %} - ], - borderWidth: 1, - type: 'line', - hidden: true, - }, - {% endif %} - { - label: '{% trans "Quantity" %}', - backgroundColor: 'rgba(255, 206, 86, 0.2)', - borderColor: 'rgb(255, 206, 86)', - yAxisID: 'y1', - data: [ - {% for line in price_history %}{{ line.qty|stringformat:"f" }},{% endfor %} - ], - borderWidth: 1 - }] - } - var StockPriceChart = loadStockPricingChart($('#StockPriceChart'), purchasepricedata) - {% endif %} - - {% if bom_parts %} - var bom_colors = randomColor({hue: 'green', count: {{ bom_parts|length }} }) - var bomdata = { - labels: [{% for line in bom_parts %}'{{ line.name }}',{% endfor %}], - datasets: [ - { - label: 'Price', - data: [{% for line in bom_parts %}{{ line.min_price }},{% endfor %}], - backgroundColor: bom_colors, - }, - {% if bom_pie_max %} - { - label: 'Max Price', - data: [{% for line in bom_parts %}{{ line.max_price }},{% endfor %}], - backgroundColor: bom_colors, - }, - {% endif %} - ] - }; - var BomChart = loadBomChart(document.getElementById('BomChart'), bomdata) - {% endif %} - - - // Internal pricebreaks - {% settings_value "PART_INTERNAL_PRICE" as show_internal_price %} - {% if show_internal_price and roles.sales_order.view %} - initPriceBreakSet( - $('#internal-price-break-table'), - { - part_id: {{part.id}}, - pb_human_name: 'internal price break', - pb_url_slug: 'internal-price', - pb_url: '{% url 'api-part-internal-price-list' %}', - pb_new_btn: $('#new-internal-price-break'), - pb_new_url: '{% url 'internal-price-break-create' %}', - linkedGraph: $('#InternalPriceBreakChart'), - }, - ); - {% endif %} - - - // Load the BOM table data - loadBomTable($("#bom-table"), { - editable: {{ editing_enabled }}, - bom_url: "{% url 'api-bom-list' %}", - part_url: "{% url 'api-part-list' %}", - parent_id: {{ part.id }} , - sub_part_detail: true, - }); - - - // Sales pricebreaks - {% if part.salable and roles.sales_order.view %} - initPriceBreakSet( - $('#price-break-table'), - { - part_id: {{part.id}}, - pb_human_name: 'sale price break', - pb_url_slug: 'sale-price', - pb_url: "{% url 'api-part-sale-price-list' %}", - pb_new_btn: $('#new-price-break'), - pb_new_url: '{% url 'sale-price-break-create' %}', - linkedGraph: $('#SalePriceBreakChart'), - }, - ); - {% endif %} - - // Sale price history - {% if sale_history %} - var salepricedata = { - labels: [ - {% for line in sale_history %}'{{ line.date }}',{% endfor %} - ], - datasets: [{ - label: '{% blocktrans %}Unit Price - {{currency}}{% endblocktrans %}', - backgroundColor: 'rgba(255, 99, 132, 0.2)', - borderColor: 'rgb(255, 99, 132)', - yAxisID: 'y', - data: [ - {% for line in sale_history %}{{ line.price|stringformat:".2f" }},{% endfor %} - ], - borderWidth: 1, - }, - { - label: '{% trans "Quantity" %}', - backgroundColor: 'rgba(255, 206, 86, 0.2)', - borderColor: 'rgb(255, 206, 86)', - yAxisID: 'y1', - data: [ - {% for line in sale_history %}{{ line.qty|stringformat:"f" }},{% endfor %} - ], - borderWidth: 1, - type: 'bar', - }] - } - var SalePriceChart = loadSellPricingChart($('#SalePriceChart'), salepricedata) - {% endif %} - -{% endblock %} diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index e59ea88a05..2215e14785 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -47,8 +47,6 @@ part_detail_urls = [ url(r'^bom-upload/?', views.BomUpload.as_view(), name='upload-bom'), url(r'^bom-duplicate/?', views.BomDuplicate.as_view(), name='duplicate-bom'), - url(r'^prices/', views.PartPricingView.as_view(template_name='part/prices.html'), name='part-prices'), - url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'), # Normal thumbnail with form diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index cbaa7f3d72..7919b7d412 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -754,6 +754,7 @@ class PartDetail(InvenTreeRoleMixin, DetailView): context_object_name = 'part' queryset = Part.objects.all().select_related('category') template_name = 'part/detail.html' + form_class = part_forms.PartPriceForm # Add in some extra context information based on query params def get_context_data(self, **kwargs): @@ -774,25 +775,12 @@ class PartDetail(InvenTreeRoleMixin, DetailView): ctx = part.get_context_data(self.request) context.update(**ctx) - return context - - -class PartPricingView(PartDetail): - """ Detail view for Part object - """ - context_object_name = 'part' - template_name = 'part/order_prices.html' - form_class = part_forms.PartPriceForm - - # Add in some extra context information based on query params - def get_context_data(self, **kwargs): - """ Provide extra context data to template """ - context = super().get_context_data(**kwargs) - + # Pricing information ctx = self.get_pricing(self.get_quantity()) ctx['form'] = self.form_class(initial=self.get_initials()) context.update(ctx) + return context def get_quantity(self): diff --git a/InvenTree/templates/js/build.js b/InvenTree/templates/js/build.js index e284a0e8c8..f43de6ec2b 100644 --- a/InvenTree/templates/js/build.js +++ b/InvenTree/templates/js/build.js @@ -921,7 +921,7 @@ function loadBuildTable(table, options) { } else { - return '{% trans "No user information" %}'; + return `{% trans "No user information" %}`; } } }, diff --git a/InvenTree/templates/js/part.js b/InvenTree/templates/js/part.js index 7f034682de..169c722d79 100644 --- a/InvenTree/templates/js/part.js +++ b/InvenTree/templates/js/part.js @@ -714,7 +714,7 @@ function loadPartTable(table, url, options={}) { var html = ''; - html = `
          `; + html = `
          `; data.forEach(function(row, index) { diff --git a/InvenTree/templates/js/stock.js b/InvenTree/templates/js/stock.js index f173f868f7..754d3d5b59 100644 --- a/InvenTree/templates/js/stock.js +++ b/InvenTree/templates/js/stock.js @@ -1495,7 +1495,7 @@ function loadStockTrackingTable(table, options) { } else { - return '{% trans "No user information" %}'; + return `{% trans "No user information" %}`; } } }); From 09d175f7cfc52976f4ceaa192ffe0b1850bd30a2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 23:11:59 +1000 Subject: [PATCH 414/445] Fix purchase order import form --- InvenTree/common/files.py | 7 ++++++- InvenTree/order/templates/order/order_base.html | 4 ---- .../order/templates/order/order_wizard/po_upload.html | 4 ---- InvenTree/order/templates/order/purchase_order_detail.html | 5 +++++ 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/InvenTree/common/files.py b/InvenTree/common/files.py index f805ceaace..45b6c80050 100644 --- a/InvenTree/common/files.py +++ b/InvenTree/common/files.py @@ -99,13 +99,18 @@ class FileManager: self.update_headers() def guess_header(self, header, threshold=80): - """ Try to match a header (from the file) to a list of known headers + """ + Try to match a header (from the file) to a list of known headers Args: header - Header name to look for threshold - Match threshold for fuzzy search """ + # Replace null values with empty string + if header is None: + header = '' + # Try for an exact match for h in self.HEADERS: if h == header: diff --git a/InvenTree/order/templates/order/order_base.html b/InvenTree/order/templates/order/order_base.html index 85d8fd5c51..f1146d8b01 100644 --- a/InvenTree/order/templates/order/order_base.html +++ b/InvenTree/order/templates/order/order_base.html @@ -145,10 +145,6 @@ src="{% static 'img/blank_image.png' %}" {% block js_ready %} {{ block.super }} -enableNavbar({ - label: 'po', - toggleId: '#po-menu-toggle', -}); {% if order.status == PurchaseOrderStatus.PENDING and order.lines.count > 0 %} $("#place-order").click(function() { diff --git a/InvenTree/order/templates/order/order_wizard/po_upload.html b/InvenTree/order/templates/order/order_wizard/po_upload.html index a281725173..4357bce2c6 100644 --- a/InvenTree/order/templates/order/order_wizard/po_upload.html +++ b/InvenTree/order/templates/order/order_wizard/po_upload.html @@ -3,10 +3,6 @@ {% load i18n %} {% load static %} -{% block menubar %} -{% include 'order/po_navbar.html' with tab='upload' %} -{% endblock %} - {% block heading %} {% trans "Upload File for Purchase Order" %} {{ wizard.form.media }} diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index cbff1b2d1c..97a4ffb78e 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -77,6 +77,11 @@ {{ block.super }} + enableNavbar({ + label: 'po', + toggleId: '#po-menu-toggle', + }); + $('#edit-notes').click(function() { constructForm('{% url "api-po-detail" order.pk %}', { fields: { From e116ef9a8b2d8d6cef7ea28d455dd49b80adae66 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 23:14:40 +1000 Subject: [PATCH 415/445] Fix BOM upload form --- InvenTree/part/templates/part/bom_upload/upload_file.html | 8 +++----- InvenTree/part/templates/part/detail.html | 6 ++++++ InvenTree/part/templates/part/part_base.html | 5 ----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/InvenTree/part/templates/part/bom_upload/upload_file.html b/InvenTree/part/templates/part/bom_upload/upload_file.html index 88592c5ffc..e31cfbaf56 100644 --- a/InvenTree/part/templates/part/bom_upload/upload_file.html +++ b/InvenTree/part/templates/part/bom_upload/upload_file.html @@ -3,15 +3,13 @@ {% load i18n %} {% load inventree_extras %} -{% block menubar %} -{% include "part/navbar.html" with tab='bom' %} -{% endblock %} - {% block heading %} {% trans "Upload BOM File" %} {% endblock %} -{% block details %} +{% block page_content %} + +

          {% trans "Upload Bill of Materials" %}

          {% block form_alert %}
          diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index d9ef212fae..b92ce4fbeb 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -335,6 +335,12 @@ {% block js_ready %} {{ block.super }} + enableNavbar({ + label: 'part', + toggleId: '#part-menu-toggle', + }); + + loadBuildOrderAllocationTable("#build-order-allocation-table", { params: { part: {{ part.id }}, diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index 2437662cba..9fe6c7b486 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -253,11 +253,6 @@ {% block js_ready %} {{ block.super }} - enableNavbar({ - label: 'part', - toggleId: '#part-menu-toggle', - }); - {% if part.image %} $('#part-thumb').click(function() { showModalImage('{{ part.image.url }}'); From e86e15df99b9c1baec03351a8be7445d29f294d1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 23:18:41 +1000 Subject: [PATCH 416/445] Fix part import form --- InvenTree/part/templates/part/category_navbar.html | 2 +- .../part/templates/part/import_wizard/part_upload.html | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/InvenTree/part/templates/part/category_navbar.html b/InvenTree/part/templates/part/category_navbar.html index 8e5e085f93..aa3a491160 100644 --- a/InvenTree/part/templates/part/category_navbar.html +++ b/InvenTree/part/templates/part/category_navbar.html @@ -27,7 +27,7 @@ {% if show_import and user.is_staff and roles.part.add %}
        • - + {% trans "Import Parts" %} diff --git a/InvenTree/part/templates/part/import_wizard/part_upload.html b/InvenTree/part/templates/part/import_wizard/part_upload.html index 87809603bb..676053bbe5 100644 --- a/InvenTree/part/templates/part/import_wizard/part_upload.html +++ b/InvenTree/part/templates/part/import_wizard/part_upload.html @@ -1,13 +1,9 @@ -{% extends "part/category.html" %} +{% extends "base.html" %} {% load inventree_extras %} {% load i18n %} {% load static %} -{% block menubar %} -{% include 'part/category_navbar.html' with tab='import' %} -{% endblock %} - -{% block category_content %} +{% block content %}

          From 28b3432afe8c9a95c41c22fe06f3adf32634d401 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 15 Jul 2021 23:19:47 +1000 Subject: [PATCH 417/445] Delete outdated unit test --- InvenTree/build/tests.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/InvenTree/build/tests.py b/InvenTree/build/tests.py index 9c5134cc66..b5e5406f69 100644 --- a/InvenTree/build/tests.py +++ b/InvenTree/build/tests.py @@ -252,19 +252,6 @@ class TestBuildViews(TestCase): self.assertIn(build.title, content) - def test_build_allocate(self): - """ Test the part allocation view for a Build """ - - url = reverse('build-allocate', args=(1,)) - - # Get the page normally - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - - # Get the page in editing mode - response = self.client.get(url, {'edit': 1}) - self.assertEqual(response.status_code, 200) - def test_build_item_create(self): """ Test the BuildItem creation view (ajax form) """ From cbbd58c743ac4b13cf970664546f79fc1356c908 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 16 Jul 2021 01:13:48 +1000 Subject: [PATCH 418/445] Fixes for issues with new SPA approach - Fix manufacturer part table - Fix supplier part table - Consolidate manufacturer and supplier parts onto single page - CSS fixes --- InvenTree/InvenTree/static/css/inventree.css | 4 +- InvenTree/part/templates/part/detail.html | 66 ++++++++++---------- InvenTree/part/templates/part/navbar.html | 8 +-- 3 files changed, 35 insertions(+), 43 deletions(-) diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index 1c8d529a92..a71e29ab5d 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -781,8 +781,8 @@ input[type="submit"] { } .sidenav .list-group-item.active { - background-color: #b3a997; - border-color: #ccc; + background-color: #c6d4ea; + border: 2px #aab solid; } /* The side navigation menu */ diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index b92ce4fbeb..0ba539baea 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -223,30 +223,6 @@

          -
          -
          -

          {% trans "Part Suppliers" %}

          -
          -
          -
          -
          - -
          - - -
          -
          -
          - - -
          -
          -
          -

          {% trans "Bill of Materials" %}

          @@ -302,7 +278,29 @@
          -
          +
          +
          +

          {% trans "Part Suppliers" %}

          +
          +
          +
          +
          + +
          + + +
          +
          +
          + + +
          +
          +

          {% trans "Part Manufacturers" %}

          @@ -321,7 +319,7 @@
        • -
          +
          @@ -828,7 +826,7 @@ $("#supplier-part-delete").click(function() { - var selections = $("#supplier-table").bootstrapTable("getSelections"); + var selections = $("#supplier-part-table").bootstrapTable("getSelections"); var parts = []; @@ -845,7 +843,7 @@ }); loadSupplierPartTable( - "#supplier-table", + "#supplier-part-table", "{% url 'api-supplier-part-list' %}", { params: { @@ -857,10 +855,10 @@ } ); - linkButtonsToSelection($("#supplier-table"), ['#supplier-part-options']); + linkButtonsToSelection($("#supplier-part-table"), ['#supplier-part-options']); loadManufacturerPartTable( - '#manufacturer-table', + '#manufacturer-part-table', "{% url 'api-manufacturer-part-list' %}", { params: { @@ -871,15 +869,15 @@ } ); - linkButtonsToSelection($("#manufacturer-table"), ['#manufacturer-part-options']); + linkButtonsToSelection($("#manufacturer-part-table"), ['#manufacturer-part-options']); $("#manufacturer-part-delete").click(function() { - var selections = $("#manufacturer-table").bootstrapTable("getSelections"); + var selections = $("#manufacturer-part-table").bootstrapTable("getSelections"); deleteManufacturerParts(selections, { onSuccess: function() { - $("#manufacturer-table").bootstrapTable("refresh"); + $("#manufacturer-part-table").bootstrapTable("refresh"); } }); }); @@ -900,7 +898,7 @@ method: 'POST', title: '{% trans "Add Manufacturer Part" %}', onSuccess: function() { - $("#manufacturer-table").bootstrapTable("refresh"); + $("#manufacturer-part-table").bootstrapTable("refresh"); } }); }); diff --git a/InvenTree/part/templates/part/navbar.html b/InvenTree/part/templates/part/navbar.html index 8ea1204bc8..a2dc67c079 100644 --- a/InvenTree/part/templates/part/navbar.html +++ b/InvenTree/part/templates/part/navbar.html @@ -63,17 +63,11 @@ {% if part.purchaseable and roles.purchase_order.view %}
        • - + {% trans "Suppliers" %}
        • -
        • - - - {% trans "Manufacturers" %} - -
        • From 886d95e46745d04b89b10ac3532e0dd22b13b3fe Mon Sep 17 00:00:00 2001 From: eeintech Date: Thu, 15 Jul 2021 16:31:07 -0400 Subject: [PATCH 419/445] Easy fix! --- InvenTree/templates/registration/logged_out.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/templates/registration/logged_out.html b/InvenTree/templates/registration/logged_out.html index 6af620616b..703e077f35 100644 --- a/InvenTree/templates/registration/logged_out.html +++ b/InvenTree/templates/registration/logged_out.html @@ -14,7 +14,7 @@ - + From 0fcb4e3170d7465c4b55fa902117ed550714a50f Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 16 Jul 2021 13:30:11 +1000 Subject: [PATCH 420/445] Link fixes --- InvenTree/order/templates/order/purchase_order_detail.html | 4 ++-- InvenTree/templates/js/company.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index 97a4ffb78e..480f2f500d 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -324,9 +324,9 @@ $("#po-table").inventreeTable({ title: '{% trans "MPN" %}', formatter: function(value, row, index, field) { if (row.supplier_part_detail && row.supplier_part_detail.manufacturer_part) { - return renderLink(value, `/manufacturer-part/${row.supplier_part_detail.manufacturer_part.pk}/`); + return renderLink(value, `/manufacturer-part/${row.supplier_part_detail.manufacturer_part}/`); } else { - return ""; + return "-"; } }, }, diff --git a/InvenTree/templates/js/company.js b/InvenTree/templates/js/company.js index 18d7408b23..7daa99e1c6 100644 --- a/InvenTree/templates/js/company.js +++ b/InvenTree/templates/js/company.js @@ -539,7 +539,7 @@ function loadSupplierPartTable(table, url, options) { title: '{% trans "MPN" %}', formatter: function(value, row, index, field) { if (value && row.manufacturer_part) { - return renderLink(value, `/manufacturer-part/${row.manufacturer_part.pk}/`); + return renderLink(value, `/manufacturer-part/${row.manufacturer_part}/`); } else { return "-"; } From 733951883e4b15ed33a3cabd98ec79071c4b9912 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 16 Jul 2021 13:35:51 +1000 Subject: [PATCH 421/445] Use default curreny code --- InvenTree/order/templates/order/purchase_order_detail.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index 97a4ffb78e..f78776f790 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -187,7 +187,11 @@ $('#new-po-line').click(function() { quantity: {}, reference: {}, purchase_price: {}, - purchase_price_currency: {}, + purchase_price_currency: { + {% if order.supplier.currency %} + value: '{{ order.supplier.currency }}', + {% endif %} + }, destination: {}, notes: {}, }, From 210a4bccde91add955f7433e87e99af0f840293a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 18 Jul 2021 02:20:56 +0200 Subject: [PATCH 422/445] setting for #1796 --- InvenTree/common/models.py | 7 +++++++ InvenTree/templates/InvenTree/settings/part.html | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index c8a5839f4e..3d18d56880 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -233,6 +233,13 @@ class InvenTreeSetting(models.Model): 'validator': bool, }, + 'PART_CREATE_INITIAL': { + 'name': _('Create initial stock'), + 'description': _('Create initial stock on part creation'), + 'default': False, + 'validator': bool, + }, + 'PART_INTERNAL_PRICE': { 'name': _('Internal Prices'), 'description': _('Enable internal prices for parts'), diff --git a/InvenTree/templates/InvenTree/settings/part.html b/InvenTree/templates/InvenTree/settings/part.html index 57ffc95ba8..c7f3797841 100644 --- a/InvenTree/templates/InvenTree/settings/part.html +++ b/InvenTree/templates/InvenTree/settings/part.html @@ -23,7 +23,8 @@ {% 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_RECENT_COUNT" icon="fa-clock" %} - + {% include "InvenTree/settings/setting.html" with key="PART_CREATE_INITIAL" icon="fa-plus" %} + {% include "InvenTree/settings/setting.html" with key="PART_TEMPLATE" icon="fa-clone" %} {% include "InvenTree/settings/setting.html" with key="PART_ASSEMBLY" icon="fa-tools" %} {% include "InvenTree/settings/setting.html" with key="PART_COMPONENT" icon="fa-th"%} From 44482800e4b4886648d78f6ec730b4832acdccf5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 18 Jul 2021 02:27:15 +0200 Subject: [PATCH 423/445] switching out icon for setting --- InvenTree/templates/InvenTree/settings/part.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/templates/InvenTree/settings/part.html b/InvenTree/templates/InvenTree/settings/part.html index c7f3797841..4f49a63cb4 100644 --- a/InvenTree/templates/InvenTree/settings/part.html +++ b/InvenTree/templates/InvenTree/settings/part.html @@ -23,7 +23,7 @@ {% 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_RECENT_COUNT" icon="fa-clock" %} - {% include "InvenTree/settings/setting.html" with key="PART_CREATE_INITIAL" icon="fa-plus" %} + {% include "InvenTree/settings/setting.html" with key="PART_CREATE_INITIAL" icon="fa-boxes" %} {% include "InvenTree/settings/setting.html" with key="PART_TEMPLATE" icon="fa-clone" %} {% include "InvenTree/settings/setting.html" with key="PART_ASSEMBLY" icon="fa-tools" %} From 9719a145873e3107889aaf0dd9e67e33968486ed Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 18 Jul 2021 10:33:27 +1000 Subject: [PATCH 424/445] Add supplier_reference field to form --- InvenTree/order/templates/order/order_base.html | 1 + InvenTree/templates/js/order.js | 1 + 2 files changed, 2 insertions(+) diff --git a/InvenTree/order/templates/order/order_base.html b/InvenTree/order/templates/order/order_base.html index f1146d8b01..11396e07a7 100644 --- a/InvenTree/order/templates/order/order_base.html +++ b/InvenTree/order/templates/order/order_base.html @@ -170,6 +170,7 @@ $("#edit-order").click(function() { supplier: { }, {% endif %} + supplier_reference: {}, description: {}, target_date: { icon: 'fa-calendar-alt', diff --git a/InvenTree/templates/js/order.js b/InvenTree/templates/js/order.js index 5cb286e970..69676df01e 100644 --- a/InvenTree/templates/js/order.js +++ b/InvenTree/templates/js/order.js @@ -44,6 +44,7 @@ function createPurchaseOrder(options={}) { supplier: { value: options.supplier, }, + supplier_reference: {}, description: {}, target_date: { icon: 'fa-calendar-alt', From f4f7514b4559af6d71333f1bc171eeffb3e9a2c7 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 18 Jul 2021 10:47:35 +1000 Subject: [PATCH 425/445] Similar fix for customer_reference field --- InvenTree/order/templates/order/sales_order_base.html | 1 + InvenTree/templates/js/order.js | 1 + 2 files changed, 2 insertions(+) diff --git a/InvenTree/order/templates/order/sales_order_base.html b/InvenTree/order/templates/order/sales_order_base.html index 7a2c63c5a6..60099a2578 100644 --- a/InvenTree/order/templates/order/sales_order_base.html +++ b/InvenTree/order/templates/order/sales_order_base.html @@ -163,6 +163,7 @@ $("#edit-order").click(function() { customer: { }, {% endif %} + customer_reference: {}, description: {}, target_date: { icon: 'fa-calendar-alt', diff --git a/InvenTree/templates/js/order.js b/InvenTree/templates/js/order.js index 69676df01e..7091eb0577 100644 --- a/InvenTree/templates/js/order.js +++ b/InvenTree/templates/js/order.js @@ -14,6 +14,7 @@ function createSalesOrder(options={}) { customer: { value: options.customer, }, + customer_reference: {}, description: {}, target_date: { icon: 'fa-calendar-alt', From eba5512a3827f86bed7399c9bc6f814488423b52 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 18 Jul 2021 02:58:39 +0200 Subject: [PATCH 426/445] extending form for stock creation --- InvenTree/part/forms.py | 6 ++++++ InvenTree/part/views.py | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index f04f512045..9523550198 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -217,6 +217,11 @@ class EditPartForm(HelperForm): label=_('Include parent categories parameter templates'), widget=forms.HiddenInput()) + initial_stock = forms.IntegerField(required=False, + initial=0, + label=_('Initial stock amount'), + help_text=_('Create stock for this part')) + class Meta: model = Part fields = [ @@ -238,6 +243,7 @@ class EditPartForm(HelperForm): 'default_expiry', 'units', 'minimum_stock', + 'initial_stock', 'component', 'assembly', 'is_template', diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 7919b7d412..fb69241a10 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -44,7 +44,7 @@ from common.files import FileManager from common.views import FileManagementFormView, FileManagementAjaxView from common.forms import UploadFileForm, MatchFieldForm -from stock.models import StockLocation +from stock.models import StockItem, StockLocation import common.settings as inventree_settings @@ -487,6 +487,10 @@ class PartCreate(AjaxCreateView): if not inventree_settings.stock_expiry_enabled(): form.fields['default_expiry'].widget = HiddenInput() + # Hide the "initial stock amount" field if the feature is not enabled + if not InvenTreeSetting.get_setting('PART_CREATE_INITIAL'): + form.fields['initial_stock'].widget = HiddenInput() + # Hide the default_supplier field (there are no matching supplier parts yet!) form.fields['default_supplier'].widget = HiddenInput() @@ -547,6 +551,14 @@ class PartCreate(AjaxCreateView): # Save part and pass category template settings part.save(**{'add_category_templates': add_category_templates}) + # Add stock if set + init_stock = int(request.POST.get('initial_stock', 0)) + if init_stock: + stock = StockItem(part=part, + quantity=init_stock, + location=part.default_location) + stock.save() + data['pk'] = part.pk data['text'] = str(part) From 36cf614aed38bdaf91bcdd0ee7191d6f12ea08ea Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 18 Jul 2021 21:11:53 +1000 Subject: [PATCH 427/445] Add "level" to PartCategory serializer - Also use tree ordering by default --- InvenTree/part/api.py | 10 +++++++++- InvenTree/part/serializers.py | 7 +++++-- InvenTree/templates/js/model_renderers.js | 8 +++----- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 9abee816fa..3a5fee4e3d 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -118,9 +118,17 @@ class CategoryList(generics.ListCreateAPIView): ordering_fields = [ 'name', + 'level', + 'tree_id', + 'lft', ] - ordering = 'name' + # Use hierarchical ordering by default + ordering = [ + 'tree_id', + 'lft', + 'name' + ] search_fields = [ 'name', diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 6627639bca..92dda58590 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -32,6 +32,8 @@ class CategorySerializer(InvenTreeModelSerializer): parts = serializers.IntegerField(source='item_count', read_only=True) + level = serializers.IntegerField(read_only=True) + class Meta: model = PartCategory fields = [ @@ -40,10 +42,11 @@ class CategorySerializer(InvenTreeModelSerializer): 'description', 'default_location', 'default_keywords', - 'pathstring', - 'url', + 'level', 'parent', 'parts', + 'pathstring', + 'url', ] diff --git a/InvenTree/templates/js/model_renderers.js b/InvenTree/templates/js/model_renderers.js index caa209dc90..3b1b9c82d9 100644 --- a/InvenTree/templates/js/model_renderers.js +++ b/InvenTree/templates/js/model_renderers.js @@ -154,7 +154,9 @@ function renderOwner(name, data, parameters, options) { // Renderer for "PartCategory" model function renderPartCategory(name, data, parameters, options) { - var html = `${data.name}`; + var level = '-'.repeat(data.level); + + var html = `${level} ${data.pathstring}`; if (data.description) { html += ` - ${data.description}`; @@ -162,10 +164,6 @@ function renderPartCategory(name, data, parameters, options) { html += `{% trans "Category ID" %}: ${data.pk}`; - if (data.pathstring) { - html += `

          ${data.pathstring}

          `; - } - return html; } From 753fe9c80f7ec826eb17ddfeda4b69391b6dff70 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 18 Jul 2021 21:15:51 +1000 Subject: [PATCH 428/445] Ordering and rendering for StockLocation --- InvenTree/stock/api.py | 9 +++++++++ InvenTree/stock/serializers.py | 3 +++ InvenTree/templates/js/model_renderers.js | 8 +++----- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 08e948607a..70ab939ff1 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -363,6 +363,15 @@ class StockLocationList(generics.ListCreateAPIView): ordering_fields = [ 'name', 'items', + 'level', + 'tree_id', + 'lft', + ] + + ordering = [ + 'tree_id', + 'lft', + 'name', ] diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index 38301bdd1f..a175787c63 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -260,12 +260,15 @@ class LocationSerializer(InvenTreeModelSerializer): items = serializers.IntegerField(source='item_count', read_only=True) + level = serializers.IntegerField(read_only=True) + class Meta: model = StockLocation fields = [ 'pk', 'url', 'name', + 'level', 'description', 'parent', 'pathstring', diff --git a/InvenTree/templates/js/model_renderers.js b/InvenTree/templates/js/model_renderers.js index 3b1b9c82d9..257d296eff 100644 --- a/InvenTree/templates/js/model_renderers.js +++ b/InvenTree/templates/js/model_renderers.js @@ -67,7 +67,9 @@ function renderStockItem(name, data, parameters, options) { // Renderer for "StockLocation" model function renderStockLocation(name, data, parameters, options) { - var html = `${data.name}`; + var level = '-'.repeat(data.level); + + var html = `${level} ${data.pathstring}`; if (data.description) { html += ` - ${data.description}`; @@ -75,10 +77,6 @@ function renderStockLocation(name, data, parameters, options) { html += `{% trans "Location ID" %}: ${data.pk}`; - if (data.pathstring) { - html += `

          ${data.pathstring}

          `; - } - return html; } From c33cfe95039e3762a31a0695554f16b8ea2bcf3f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 18 Jul 2021 21:17:03 +1000 Subject: [PATCH 429/445] Small rendering improvements --- InvenTree/templates/js/model_renderers.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/InvenTree/templates/js/model_renderers.js b/InvenTree/templates/js/model_renderers.js index 257d296eff..ddb4897d8d 100644 --- a/InvenTree/templates/js/model_renderers.js +++ b/InvenTree/templates/js/model_renderers.js @@ -67,9 +67,9 @@ function renderStockItem(name, data, parameters, options) { // Renderer for "StockLocation" model function renderStockLocation(name, data, parameters, options) { - var level = '-'.repeat(data.level); + var level = '- '.repeat(data.level); - var html = `${level} ${data.pathstring}`; + var html = `${level}${data.pathstring}`; if (data.description) { html += ` - ${data.description}`; @@ -152,9 +152,9 @@ function renderOwner(name, data, parameters, options) { // Renderer for "PartCategory" model function renderPartCategory(name, data, parameters, options) { - var level = '-'.repeat(data.level); + var level = '- '.repeat(data.level); - var html = `${level} ${data.pathstring}`; + var html = `${level}${data.pathstring}`; if (data.description) { html += ` - ${data.description}`; From e17b92b12675ef7d69b483a0417ddf750d7ea585 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 18 Jul 2021 21:25:59 +1000 Subject: [PATCH 430/445] Add 'destination' field to POLineItem API serializer --- InvenTree/order/serializers.py | 3 ++- .../order/templates/order/purchase_order_detail.html | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py index 809dd0e8fb..4a95bbb166 100644 --- a/InvenTree/order/serializers.py +++ b/InvenTree/order/serializers.py @@ -132,7 +132,7 @@ class POLineItemSerializer(InvenTreeModelSerializer): purchase_price_string = serializers.CharField(source='purchase_price', read_only=True) - destination = LocationBriefSerializer(source='get_destination', read_only=True) + destination_detail = LocationBriefSerializer(source='get_destination', read_only=True) purchase_price_currency = serializers.ChoiceField( choices=currency_code_mappings(), @@ -156,6 +156,7 @@ class POLineItemSerializer(InvenTreeModelSerializer): 'purchase_price_currency', 'purchase_price_string', 'destination', + 'destination_detail', ] diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index 54d0ca76be..193fd75daa 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -401,8 +401,15 @@ $("#po-table").inventreeTable({ } }, { - field: 'destination.pathstring', + field: 'destination', title: '{% trans "Destination" %}', + formatter: function(value, row) { + if (value) { + return renderLink(row.destination_detail.pathstring, `/stock/location/${value}/`); + } else { + return '-'; + } + } }, { field: 'notes', From b04d6051a4f677a711576ac4ba47197f10022a8f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 18 Jul 2021 21:32:25 +1000 Subject: [PATCH 431/445] Disable secondary modals --- InvenTree/templates/js/modals.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/InvenTree/templates/js/modals.js b/InvenTree/templates/js/modals.js index b404af364c..4bcc31fffa 100644 --- a/InvenTree/templates/js/modals.js +++ b/InvenTree/templates/js/modals.js @@ -765,6 +765,9 @@ function attachSecondaryModal(modal, options) { function attachSecondaries(modal, secondaries) { /* Attach a provided list of secondary modals */ + // 2021-07-18 - Secondary modals will be disabled for now, until they are re-implemented in the "API forms" architecture + return; + for (var i = 0; i < secondaries.length; i++) { attachSecondaryModal(modal, secondaries[i]); } From 56fa6c512be0e505a1d881a3d1b125950ab46bbd Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 18 Jul 2021 22:21:11 +1000 Subject: [PATCH 432/445] Refactor SupplierPartCreate form --- InvenTree/company/models.py | 51 ------- InvenTree/company/serializers.py | 8 +- .../company/templates/company/detail.html | 30 ++-- .../templates/company/manufacturer_part.html | 24 ++- .../company/templates/company/navbar.html | 2 +- InvenTree/company/test_views.py | 135 ----------------- InvenTree/company/urls.py | 2 - InvenTree/company/views.py | 138 ------------------ InvenTree/part/templates/part/detail.html | 29 ++-- InvenTree/templates/js/company.js | 57 ++++++++ InvenTree/templates/js/forms.js | 5 +- InvenTree/templates/js/model_renderers.js | 30 +++- InvenTree/templates/js/stock.js | 21 --- InvenTree/templates/js/tables.js | 6 + 14 files changed, 129 insertions(+), 409 deletions(-) diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index 778e00cde1..d8ea32ee15 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -475,57 +475,6 @@ class SupplierPart(models.Model): def get_absolute_url(self): return reverse('supplier-part-detail', kwargs={'pk': self.id}) - def save(self, *args, **kwargs): - """ Overriding save method to process the linked ManufacturerPart - """ - - if 'manufacturer' in kwargs: - manufacturer_id = kwargs.pop('manufacturer') - - try: - manufacturer = Company.objects.get(pk=int(manufacturer_id)) - except (ValueError, Company.DoesNotExist): - manufacturer = None - else: - manufacturer = None - if 'MPN' in kwargs: - MPN = kwargs.pop('MPN') - else: - MPN = None - - if manufacturer or MPN: - if not self.manufacturer_part: - # Create ManufacturerPart - manufacturer_part = ManufacturerPart.create(part=self.part, - manufacturer=manufacturer, - mpn=MPN, - description=self.description) - self.manufacturer_part = manufacturer_part - else: - # Update ManufacturerPart (if ID exists) - try: - manufacturer_part_id = self.manufacturer_part.id - except AttributeError: - manufacturer_part_id = None - - if manufacturer_part_id: - try: - (manufacturer_part, created) = ManufacturerPart.objects.update_or_create(part=self.part, - manufacturer=manufacturer, - MPN=MPN) - except IntegrityError: - manufacturer_part = None - raise ValidationError(f'ManufacturerPart linked to {self.part} from manufacturer {manufacturer.name}' - f'with part number {MPN} already exists!') - - if manufacturer_part: - self.manufacturer_part = manufacturer_part - - self.clean() - self.validate_unique() - - super().save(*args, **kwargs) - class Meta: unique_together = ('part', 'supplier', 'SKU') diff --git a/InvenTree/company/serializers.py b/InvenTree/company/serializers.py index 6e5ef08d6e..721fc54c6e 100644 --- a/InvenTree/company/serializers.py +++ b/InvenTree/company/serializers.py @@ -96,7 +96,9 @@ class CompanySerializer(InvenTreeModelSerializer): class ManufacturerPartSerializer(InvenTreeModelSerializer): - """ Serializer for ManufacturerPart object """ + """ + Serializer for ManufacturerPart object + """ part_detail = PartBriefSerializer(source='part', many=False, read_only=True) @@ -106,8 +108,8 @@ class ManufacturerPartSerializer(InvenTreeModelSerializer): def __init__(self, *args, **kwargs): - part_detail = kwargs.pop('part_detail', False) - manufacturer_detail = kwargs.pop('manufacturer_detail', False) + part_detail = kwargs.pop('part_detail', True) + manufacturer_detail = kwargs.pop('manufacturer_detail', True) prettify = kwargs.pop('pretty', False) super(ManufacturerPartSerializer, self).__init__(*args, **kwargs) diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html index 105e0f82ae..9c9e836c70 100644 --- a/InvenTree/company/templates/company/detail.html +++ b/InvenTree/company/templates/company/detail.html @@ -350,28 +350,16 @@ {% if company.is_supplier %} + function reloadSupplierPartTable() { + $('#supplier-part-table').bootstrapTable('refresh'); + } + $("#supplier-part-create").click(function () { - launchModalForm( - "{% url 'supplier-part-create' %}", - { - data: { - supplier: {{ company.id }}, - }, - reload: true, - secondary: [ - { - field: 'part', - label: '{% trans "New Part" %}', - title: '{% trans "Create new Part" %}', - url: "{% url 'part-create' %}" - }, - { - field: 'supplier', - label: "{% trans 'New Supplier' %}", - title: "{% trans 'Create new Supplier' %}", - }, - ] - }); + + createSupplierPart({ + supplier: {{ company.pk }}, + onSuccess: reloadSupplierPartTable, + }); }); loadSupplierPartTable( diff --git a/InvenTree/company/templates/company/manufacturer_part.html b/InvenTree/company/templates/company/manufacturer_part.html index da5ea36173..12b869ca72 100644 --- a/InvenTree/company/templates/company/manufacturer_part.html +++ b/InvenTree/company/templates/company/manufacturer_part.html @@ -178,22 +178,16 @@ $('#parameter-create').click(function() { }); }); +function reloadSupplierPartTable() { + $('#supplier-table').bootstrapTable('refresh'); +} + $('#supplier-create').click(function () { - launchModalForm( - "{% url 'supplier-part-create' %}", - { - reload: true, - data: { - manufacturer_part: {{ part.id }} - }, - secondary: [ - { - field: 'supplier', - label: '{% trans "New Supplier" %}', - title: '{% trans "Create new supplier" %}', - }, - ] - }); + createSupplierPart({ + manufacturer_part: {{ part.pk }}, + part: {{ part.part.pk }}, + onSuccess: reloadSupplierPartTable, + }); }); $("#supplier-part-delete").click(function() { diff --git a/InvenTree/company/templates/company/navbar.html b/InvenTree/company/templates/company/navbar.html index 025b1c6b4a..b652d6b603 100644 --- a/InvenTree/company/templates/company/navbar.html +++ b/InvenTree/company/templates/company/navbar.html @@ -18,7 +18,7 @@
        • {% endif %} - {% if company.is_supplier or company.is_manufacturer %} + {% if company.is_supplier %}
        • diff --git a/InvenTree/company/test_views.py b/InvenTree/company/test_views.py index 6fc4281f2b..bb796a0763 100644 --- a/InvenTree/company/test_views.py +++ b/InvenTree/company/test_views.py @@ -75,108 +75,6 @@ class CompanyViewTestBase(TestCase): return json_data, form_errors -class SupplierPartViewTests(CompanyViewTestBase): - """ - Tests for the SupplierPart views. - """ - - def test_supplier_part_create(self): - """ - Test the SupplierPartCreate view. - - This view allows some additional functionality, - specifically it allows the user to create a single-quantity price break - automatically, when saving the new SupplierPart model. - """ - - url = reverse('supplier-part-create') - - # First check that we can GET the form - response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # How many supplier parts are already in the database? - n = SupplierPart.objects.all().count() - - data = { - 'part': 1, - 'supplier': 1, - } - - # SKU is required! (form should fail) - (response, errors) = self.post(url, data, valid=False) - - self.assertIsNotNone(errors.get('SKU', None)) - - data['SKU'] = 'TEST-ME-123' - - (response, errors) = self.post(url, data, valid=True) - - # Check that the SupplierPart was created! - self.assertEqual(n + 1, SupplierPart.objects.all().count()) - - # Check that it was created *without* a price-break - supplier_part = SupplierPart.objects.get(pk=response['pk']) - - self.assertEqual(supplier_part.price_breaks.count(), 0) - - # Duplicate SKU is prohibited - (response, errors) = self.post(url, data, valid=False) - - self.assertIsNotNone(errors.get('__all__', None)) - - # Add with a different SKU, *and* a single-quantity price - data['SKU'] = 'TEST-ME-1234' - data['single_pricing_0'] = '123.4' - data['single_pricing_1'] = 'CAD' - - (response, errors) = self.post(url, data, valid=True) - - pk = response.get('pk') - - # Check that *another* SupplierPart was created - self.assertEqual(n + 2, SupplierPart.objects.all().count()) - - supplier_part = SupplierPart.objects.get(pk=pk) - - # Check that a price-break has been created! - self.assertEqual(supplier_part.price_breaks.count(), 1) - - price_break = supplier_part.price_breaks.first() - - self.assertEqual(price_break.quantity, 1) - - def test_supplier_part_delete(self): - """ - Test the SupplierPartDelete view - """ - - url = reverse('supplier-part-delete') - - # Get form using 'part' argument - response = self.client.get(url, {'part': '1'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # Get form using 'parts' argument - response = self.client.get(url + '?parts[]=1&parts[]=2', HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # POST to delete two parts - n = SupplierPart.objects.count() - response = self.client.post( - url, - { - 'supplier-part-2': 'supplier-part-2', - 'supplier-part-3': 'supplier-part-3', - 'confirm_delete': True - }, - HTTP_X_REQUESTED_WITH='XMLHttpRequest') - - self.assertEqual(response.status_code, 200) - - self.assertEqual(n - 2, SupplierPart.objects.count()) - - class CompanyViewTest(CompanyViewTestBase): """ Tests for various 'Company' views @@ -187,36 +85,3 @@ class CompanyViewTest(CompanyViewTestBase): response = self.client.get(reverse('company-index')) self.assertEqual(response.status_code, 200) - - -class ManufacturerPartViewTests(CompanyViewTestBase): - """ - Tests for the ManufacturerPart views. - """ - - def test_supplier_part_create(self): - """ - Test that the SupplierPartCreate view creates Manufacturer Part. - """ - - url = reverse('supplier-part-create') - - # First check that we can GET the form - response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # How many manufacturer parts are already in the database? - n = ManufacturerPart.objects.all().count() - - data = { - 'part': 1, - 'supplier': 1, - 'SKU': 'SKU_TEST', - 'manufacturer': 6, - 'MPN': 'MPN_TEST', - } - - (response, errors) = self.post(url, data, valid=True) - - # Check that the ManufacturerPart was created! - self.assertEqual(n + 1, ManufacturerPart.objects.all().count()) diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index 7d2b6fb609..b983a6483b 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -42,8 +42,6 @@ supplier_part_detail_urls = [ ] supplier_part_urls = [ - url(r'^new/?', views.SupplierPartCreate.as_view(), name='supplier-part-create'), - url(r'delete/', views.SupplierPartDelete.as_view(), name='supplier-part-delete'), url(r'^(?P\d+)/', include(supplier_part_detail_urls)), diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index ab6344e810..cf683ffb90 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -285,144 +285,6 @@ class SupplierPartEdit(AjaxUpdateView): return initials -class SupplierPartCreate(AjaxCreateView): - """ Create view for making new SupplierPart """ - - model = SupplierPart - form_class = EditSupplierPartForm - ajax_template_name = 'company/supplier_part_create.html' - ajax_form_title = _('Create new Supplier Part') - context_object_name = 'part' - - def validate(self, part, form): - - single_pricing = form.cleaned_data.get('single_pricing', None) - - if single_pricing: - # TODO - What validation steps can be performed on the single_pricing field? - pass - - def get_context_data(self): - """ - Supply context data to the form - """ - - ctx = super().get_context_data() - - # Add 'part' object - form = self.get_form() - - part = form['part'].value() - - try: - part = Part.objects.get(pk=part) - except (ValueError, Part.DoesNotExist): - part = None - - ctx['part'] = part - - return ctx - - def save(self, form): - """ - If single_pricing is defined, add a price break for quantity=1 - """ - - # Save the supplier part object - supplier_part = super().save(form) - - # Process manufacturer data - manufacturer = form.cleaned_data.get('manufacturer', None) - MPN = form.cleaned_data.get('MPN', None) - kwargs = {'manufacturer': manufacturer, - 'MPN': MPN, - } - supplier_part.save(**kwargs) - - single_pricing = form.cleaned_data.get('single_pricing', None) - - if single_pricing: - - supplier_part.add_price_break(1, single_pricing) - - return supplier_part - - def get_form(self): - """ Create Form instance to create a new SupplierPart object. - Hide some fields if they are not appropriate in context - """ - form = super(AjaxCreateView, self).get_form() - - if form.initial.get('part', None): - # Hide the part field - form.fields['part'].widget = HiddenInput() - - if form.initial.get('manufacturer', None): - # Hide the manufacturer field - form.fields['manufacturer'].widget = HiddenInput() - # Hide the MPN field - form.fields['MPN'].widget = HiddenInput() - - return form - - def get_initial(self): - """ Provide initial data for new SupplierPart: - - - If 'supplier_id' provided, pre-fill supplier field - - If 'part_id' provided, pre-fill part field - """ - initials = super(SupplierPartCreate, self).get_initial().copy() - - manufacturer_id = self.get_param('manufacturer') - supplier_id = self.get_param('supplier') - part_id = self.get_param('part') - manufacturer_part_id = self.get_param('manufacturer_part') - - supplier = None - - if supplier_id: - try: - supplier = Company.objects.get(pk=supplier_id) - initials['supplier'] = supplier - except (ValueError, Company.DoesNotExist): - supplier = None - - if manufacturer_id: - try: - initials['manufacturer'] = Company.objects.get(pk=manufacturer_id) - except (ValueError, Company.DoesNotExist): - pass - - if manufacturer_part_id: - try: - # Get ManufacturerPart instance information - manufacturer_part_obj = ManufacturerPart.objects.get(pk=manufacturer_part_id) - initials['part'] = Part.objects.get(pk=manufacturer_part_obj.part.id) - initials['manufacturer'] = manufacturer_part_obj.manufacturer.id - initials['MPN'] = manufacturer_part_obj.MPN - except (ValueError, ManufacturerPart.DoesNotExist, Part.DoesNotExist, Company.DoesNotExist): - pass - - if part_id: - try: - initials['part'] = Part.objects.get(pk=part_id) - except (ValueError, Part.DoesNotExist): - pass - - # Initial value for single pricing - if supplier: - currency_code = supplier.currency_code - else: - currency_code = common.settings.currency_code_default() - - currency = CURRENCIES.get(currency_code, None) - - if currency_code: - initials['single_pricing'] = ('', currency) - - return initials - - class SupplierPartDelete(AjaxDeleteView): """ Delete view for removing a SupplierPart. diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 0ba539baea..77de5deceb 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -801,27 +801,16 @@ ) }); + function reloadSupplierPartTable() { + $('#supplier-part-table').bootstrapTable('refresh'); + } + $('#supplier-create').click(function () { - launchModalForm( - "{% url 'supplier-part-create' %}", - { - reload: true, - data: { - part: {{ part.id }} - }, - secondary: [ - { - field: 'supplier', - label: '{% trans "New Supplier" %}', - title: '{% trans "Create new supplier" %}', - }, - { - field: 'manufacturer', - label: '{% trans "New Manufacturer" %}', - title: '{% trans "Create new manufacturer" %}', - } - ] - }); + + createSupplierPart({ + part: {{ part.pk }}, + onSuccess: reloadSupplierPartTable, + }); }); $("#supplier-part-delete").click(function() { diff --git a/InvenTree/templates/js/company.js b/InvenTree/templates/js/company.js index 7daa99e1c6..7b6f145bba 100644 --- a/InvenTree/templates/js/company.js +++ b/InvenTree/templates/js/company.js @@ -1,6 +1,63 @@ {% load i18n %} +function supplierPartFields() { + + return { + part: {}, + supplier: {}, + SKU: { + icon: 'fa-hashtag', + }, + manufacturer_part: { + filters: { + part_detail: true, + manufacturer_detail: true, + } + }, + description: {}, + link: { + icon: 'fa-link', + }, + note: { + icon: 'fa-pencil-alt', + }, + packaging: { + icon: 'fa-box', + } + }; +} + +/* + * Launch a form to create a new ManufacturerPart + */ +function createSupplierPart(options={}) { + + var fields = supplierPartFields(); + + if (options.part) { + fields.manufacturer_part.filters.part = options.part; + fields.part.hidden = true; + fields.part.value = options.part; + } + + if (options.supplier) { + fields.supplier.value = options.supplier; + } + + if (options.manufacturer_part) { + fields.manufacturer_part.value = options.manufacturer_part; + } + + constructForm('{% url "api-supplier-part-list" %}', { + fields: fields, + method: 'POST', + title: '{% trans "Add Supplier Part" %}', + onSuccess: options.onSuccess, + }); +} + + // Returns a default form-set for creating / editing a Company object function companyFormFields(options={}) { diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 6dd7dbd968..568ca5ac58 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -1113,7 +1113,7 @@ function initializeRelatedField(name, field, options) { var pk = field.value; var url = `${field.api_url}/${pk}/`.replace('//', '/'); - inventreeGet(url, {}, { + inventreeGet(url, field.filters || {}, { success: function(data) { setRelatedFieldData(name, data, options); } @@ -1211,6 +1211,9 @@ function renderModelData(name, model, data, parameters, options) { case 'partparametertemplate': renderer = renderPartParameterTemplate; break; + case 'manufacturerpart': + renderer = renderManufacturerPart; + break; case 'supplierpart': renderer = renderSupplierPart; break; diff --git a/InvenTree/templates/js/model_renderers.js b/InvenTree/templates/js/model_renderers.js index ddb4897d8d..12e00cab2c 100644 --- a/InvenTree/templates/js/model_renderers.js +++ b/InvenTree/templates/js/model_renderers.js @@ -174,7 +174,35 @@ function renderPartParameterTemplate(name, data, parameters, options) { } -// Rendered for "SupplierPart" model +// Renderer for "ManufacturerPart" model +function renderManufacturerPart(name, data, parameters, options) { + + var manufacturer_image = null; + var part_image = null; + + if (data.manufacturer_detail) { + manufacturer_image = data.manufacturer_detail.image; + } + + if (data.part_detail) { + part_image = data.part_detail.thumbnail || data.part_detail.image; + } + + var html = ''; + + html += select2Thumbnail(manufacturer_image); + html += select2Thumbnail(part_image); + + html += ` ${data.manufacturer_detail.name} - ${data.MPN}`; + html += ` - ${data.part_detail.full_name}`; + + html += `{% trans "Manufacturer Part ID" %}: ${data.pk}`; + + return html; +} + + +// Renderer for "SupplierPart" model function renderSupplierPart(name, data, parameters, options) { var supplier_image = null; diff --git a/InvenTree/templates/js/stock.js b/InvenTree/templates/js/stock.js index 754d3d5b59..1d38b631a5 100644 --- a/InvenTree/templates/js/stock.js +++ b/InvenTree/templates/js/stock.js @@ -1616,27 +1616,6 @@ function createNewStockItem(options) { }, ]; - options.secondary = [ - { - field: 'part', - label: '{% trans "New Part" %}', - title: '{% trans "Create New Part" %}', - url: "{% url 'part-create' %}", - }, - { - field: 'supplier_part', - label: '{% trans "New Supplier Part" %}', - title: '{% trans "Create new Supplier Part" %}', - url: "{% url 'supplier-part-create' %}" - }, - { - field: 'location', - label: '{% trans "New Location" %}', - title: '{% trans "Create New Location" %}', - url: "{% url 'stock-location-create' %}", - }, - ]; - launchModalForm("{% url 'stock-item-create' %}", options); } diff --git a/InvenTree/templates/js/tables.js b/InvenTree/templates/js/tables.js index 8fedeb8f9e..afe1fefbc9 100644 --- a/InvenTree/templates/js/tables.js +++ b/InvenTree/templates/js/tables.js @@ -1,5 +1,11 @@ {% load i18n %} + +function reloadtable(table) { + $(table).bootstrapTable('refresh'); +} + + function editButton(url, text='Edit') { return ""; } From 29d7cb40e141e5a362e2eba20ab062fdb800e8b5 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 18 Jul 2021 22:31:04 +1000 Subject: [PATCH 433/445] Add edit and delete buttons for supplier-part table --- InvenTree/templates/js/company.js | 64 +++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/InvenTree/templates/js/company.js b/InvenTree/templates/js/company.js index 7b6f145bba..553cb9e0ba 100644 --- a/InvenTree/templates/js/company.js +++ b/InvenTree/templates/js/company.js @@ -58,6 +58,26 @@ function createSupplierPart(options={}) { } +function editSupplierPart(part, options={}) { + + constructForm(`/api/company/part/${part}/`, { + fields: supplierPartFields(), + title: '{% trans "Edit Supplier Part" %}', + onSuccess: options.onSuccess + }); +} + + +function deleteSupplierPart(part, options={}) { + + constructForm(`/api/company/part/${part}/`, { + method: 'DELETE', + title: '{% trans "Delete Supplier Part" %}', + onSuccess: options.onSuccess, + }); +} + + // Returns a default form-set for creating / editing a Company object function companyFormFields(options={}) { @@ -627,7 +647,51 @@ function loadSupplierPartTable(table, url, options) { field: 'packaging', title: '{% trans "Packaging" %}', sortable: false, + }, + { + field: 'actions', + title: '', + sortable: false, + switchable: false, + formatter: function(value, row) { + var pk = row.pk; + + var html = `
          `; + + html += makeIconButton('fa-edit icon-blue', 'button-supplier-part-edit', pk, '{% trans "Edit supplier part" %}'); + html += makeIconButton('fa-trash-alt icon-red', 'button-supplier-part-delete', pk, '{% trans "Delete manufacturer part" %}'); + + html += '
          '; + + return html; + } } ], + onPostBody: function() { + // Callbacks + $(table).find('.button-supplier-part-edit').click(function() { + var pk = $(this).attr('pk'); + + editSupplierPart( + pk, + { + onSuccess: function() { + $(table).bootstrapTable('refresh'); + } + }); + }); + + $(table).find('.button-supplier-part-delete').click(function() { + var pk = $(this).attr('pk'); + + deleteSupplierPart( + pk, + { + onSuccess: function() { + $(table).bootstrapTable('refresh'); + } + }); + }) + } }); } \ No newline at end of file From 0c91691ed291a6c881a4877f6ff6ab1e7a744a83 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 18 Jul 2021 22:46:23 +1000 Subject: [PATCH 434/445] Refactor SupplierPartEdit and SupplierPartDelete forms --- InvenTree/company/forms.py | 64 +------- InvenTree/company/models.py | 2 - .../company/templates/company/detail.html | 33 ++-- .../templates/company/manufacturer_part.html | 29 ++-- .../templates/company/supplier_part.html | 22 +-- .../company/supplier_part_create.html | 17 --- .../company/supplier_part_delete.html | 31 ---- InvenTree/company/test_views.py | 3 - InvenTree/company/urls.py | 10 +- InvenTree/company/views.py | 142 +----------------- InvenTree/part/templates/part/detail.html | 29 ++-- 11 files changed, 69 insertions(+), 313 deletions(-) delete mode 100644 InvenTree/company/templates/company/supplier_part_create.html delete mode 100644 InvenTree/company/templates/company/supplier_part_delete.html diff --git a/InvenTree/company/forms.py b/InvenTree/company/forms.py index 079e871b84..506133df00 100644 --- a/InvenTree/company/forms.py +++ b/InvenTree/company/forms.py @@ -6,13 +6,12 @@ Django Forms for interacting with Company app from __future__ import unicode_literals from InvenTree.forms import HelperForm -from InvenTree.fields import InvenTreeMoneyField, RoundingDecimalFormField +from InvenTree.fields import RoundingDecimalFormField from django.utils.translation import ugettext_lazy as _ import django.forms from .models import Company -from .models import SupplierPart from .models import SupplierPriceBreak @@ -34,67 +33,6 @@ class CompanyImageDownloadForm(HelperForm): ] -class EditSupplierPartForm(HelperForm): - """ Form for editing a SupplierPart object """ - - field_prefix = { - 'link': 'fa-link', - 'SKU': 'fa-hashtag', - 'note': 'fa-pencil-alt', - } - - single_pricing = InvenTreeMoneyField( - label=_('Single Price'), - help_text=_('Single quantity price'), - decimal_places=4, - max_digits=19, - required=False, - ) - - manufacturer = django.forms.ChoiceField( - required=False, - help_text=_('Select manufacturer'), - choices=[], - ) - - MPN = django.forms.CharField( - required=False, - help_text=_('Manufacturer Part Number'), - max_length=100, - label=_('MPN'), - ) - - class Meta: - model = SupplierPart - fields = [ - 'part', - 'supplier', - 'SKU', - 'manufacturer', - 'MPN', - 'description', - 'link', - 'note', - 'single_pricing', - # 'base_cost', - # 'multiple', - 'packaging', - ] - - def get_manufacturer_choices(self): - """ Returns tuples for all manufacturers """ - empty_choice = [('', '----------')] - - manufacturers = [(manufacturer.id, manufacturer.name) for manufacturer in Company.objects.filter(is_manufacturer=True)] - - return empty_choice + manufacturers - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - self.fields['manufacturer'].choices = self.get_manufacturer_choices() - - class EditPriceBreakForm(HelperForm): """ Form for creating / editing a supplier price break """ diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index d8ea32ee15..3b731381b8 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -9,9 +9,7 @@ import os from django.utils.translation import ugettext_lazy as _ from django.core.validators import MinValueValidator -from django.core.exceptions import ValidationError from django.db import models -from django.db.utils import IntegrityError from django.db.models import Sum, Q, UniqueConstraint from django.apps import apps diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html index 9c9e836c70..18e85718cb 100644 --- a/InvenTree/company/templates/company/detail.html +++ b/InvenTree/company/templates/company/detail.html @@ -378,22 +378,27 @@ {% endif %} $("#multi-part-delete").click(function() { - var selections = $("#part-table").bootstrapTable("getSelections"); + var selections = $("#supplier-part-table").bootstrapTable("getSelections"); - var parts = []; + var requests = []; - selections.forEach(function(item) { - parts.push(item.pk); - }); - - var url = "{% url 'supplier-part-delete' %}" - - launchModalForm(url, { - data: { - parts: parts, - }, - reload: true, - }); + showQuestionDialog( + '{% trans "Delete Supplier Parts?" %}', + '{% trans "All selected supplier parts will be deleted" %}', + { + accept: function() { + selections.forEach(function(part) { + var url = `/api/company/part/${part.pk}/`; + + requests.push(inventreeDelete(url)); + }); + + $.when.apply($, requests).then(function() { + $('#supplier-part-table').bootstrapTable('refresh'); + }); + } + } + ); }); $("#multi-part-order").click(function() { diff --git a/InvenTree/company/templates/company/manufacturer_part.html b/InvenTree/company/templates/company/manufacturer_part.html index 12b869ca72..bc6d4d5960 100644 --- a/InvenTree/company/templates/company/manufacturer_part.html +++ b/InvenTree/company/templates/company/manufacturer_part.html @@ -194,18 +194,25 @@ $("#supplier-part-delete").click(function() { var selections = $("#supplier-table").bootstrapTable("getSelections"); - var parts = []; + var requests = []; - selections.forEach(function(item) { - parts.push(item.pk); - }); - - launchModalForm("{% url 'supplier-part-delete' %}", { - data: { - parts: parts, - }, - reload: true, - }); + showQuestionDialog( + '{% trans "Delete Supplier Parts?" %}', + '{% trans "All selected supplier parts will be deleted" %}', + { + accept: function() { + selections.forEach(function(part) { + var url = `/api/company/part/${part.pk}/`; + + requests.push(inventreeDelete(url)); + }); + + $.when.apply($, requests).then(function() { + reloadSupplierPartTable(); + }); + } + } + ); }); $("#multi-parameter-delete").click(function() { diff --git a/InvenTree/company/templates/company/supplier_part.html b/InvenTree/company/templates/company/supplier_part.html index c3c2f89aa7..f751665e56 100644 --- a/InvenTree/company/templates/company/supplier_part.html +++ b/InvenTree/company/templates/company/supplier_part.html @@ -327,21 +327,21 @@ $('#order-part, #order-part2').click(function() { }); $('#edit-part').click(function () { - launchModalForm( - "{% url 'supplier-part-edit' part.id %}", - { - reload: true - } - ); + + editSupplierPart({{ part.pk }}, { + onSuccess: function() { + location.reload(); + } + }); }); $('#delete-part').click(function() { - launchModalForm( - "{% url 'supplier-part-delete' %}?part={{ part.id }}", - { - redirect: "{% url 'company-detail' part.supplier.id %}" + + deleteSupplierPart({{ part.pk }}, { + onSuccess: function() { + window.location.href = "{% url 'company-detail' part.supplier.id %}"; } - ); + }); }); attachNavCallbacks({ diff --git a/InvenTree/company/templates/company/supplier_part_create.html b/InvenTree/company/templates/company/supplier_part_create.html deleted file mode 100644 index 21c23f9075..0000000000 --- a/InvenTree/company/templates/company/supplier_part_create.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "modal_form.html" %} - -{% load i18n %} - -{% block pre_form_content %} -{{ block.super }} - -{% if part %} -
          - {% include "hover_image.html" with image=part.image %} - {{ part.full_name}} -
          - {{ part.description }} -
          -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part_delete.html b/InvenTree/company/templates/company/supplier_part_delete.html deleted file mode 100644 index 40d9ce42de..0000000000 --- a/InvenTree/company/templates/company/supplier_part_delete.html +++ /dev/null @@ -1,31 +0,0 @@ -{% extends "modal_delete_form.html" %} -{% load i18n %} - -{% block pre_form_content %} -{% trans "Are you sure you want to delete the following Supplier Parts?" %} - -
          -{% endblock %} - -{% block form_data %} - -{% for part in parts %} - - - - - - - -{% endfor %} -
          - {% include "hover_image.html" with image=part.part.image %} - {{ part.part.full_name }} - - {% include "hover_image.html" with image=part.supplier.image %} - {{ part.supplier.name }} - - {{ part.SKU }} -
          - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/test_views.py b/InvenTree/company/test_views.py index bb796a0763..89968081c3 100644 --- a/InvenTree/company/test_views.py +++ b/InvenTree/company/test_views.py @@ -10,9 +10,6 @@ from django.urls import reverse from django.contrib.auth import get_user_model from django.contrib.auth.models import Group -from .models import ManufacturerPart -from .models import SupplierPart - class CompanyViewTestBase(TestCase): diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index b983a6483b..901e7f7089 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -35,14 +35,6 @@ manufacturer_part_urls = [ ])), ] -supplier_part_detail_urls = [ - url(r'^edit/?', views.SupplierPartEdit.as_view(), name='supplier-part-edit'), - +supplier_part_urls = [ url('^.*$', views.SupplierPartDetail.as_view(template_name='company/supplier_part.html'), name='supplier-part-detail'), ] - -supplier_part_urls = [ - url(r'delete/', views.SupplierPartDelete.as_view(), name='supplier-part-delete'), - - url(r'^(?P\d+)/', include(supplier_part_detail_urls)), -] diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index cf683ffb90..f3a9af7628 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -10,31 +10,22 @@ from django.utils.translation import ugettext_lazy as _ from django.views.generic import DetailView, ListView from django.urls import reverse -from django.forms import HiddenInput from django.core.files.base import ContentFile -from moneyed import CURRENCIES - from PIL import Image import requests import io -from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView -from InvenTree.helpers import str2bool +from InvenTree.views import AjaxUpdateView from InvenTree.views import InvenTreeRoleMixin from .models import Company from .models import ManufacturerPart from .models import SupplierPart -from part.models import Part -from .forms import EditSupplierPartForm from .forms import CompanyImageDownloadForm -import common.models -import common.settings - class CompanyIndex(InvenTreeRoleMixin, ListView): """ View for displaying list of companies @@ -231,134 +222,3 @@ class SupplierPartDetail(DetailView): ctx = super().get_context_data(**kwargs) return ctx - - -class SupplierPartEdit(AjaxUpdateView): - """ Update view for editing SupplierPart """ - - model = SupplierPart - context_object_name = 'part' - form_class = EditSupplierPartForm - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Edit Supplier Part') - - def save(self, supplier_part, form, **kwargs): - """ Process ManufacturerPart data """ - - manufacturer = form.cleaned_data.get('manufacturer', None) - MPN = form.cleaned_data.get('MPN', None) - kwargs = {'manufacturer': manufacturer, - 'MPN': MPN, - } - supplier_part.save(**kwargs) - - def get_form(self): - form = super().get_form() - - supplier_part = self.get_object() - - # Hide Manufacturer fields - form.fields['manufacturer'].widget = HiddenInput() - form.fields['MPN'].widget = HiddenInput() - - # It appears that hiding a MoneyField fails validation - # Therefore the idea to set the value before hiding - if form.is_valid(): - form.cleaned_data['single_pricing'] = supplier_part.unit_pricing - # Hide the single-pricing field (only for creating a new SupplierPart!) - form.fields['single_pricing'].widget = HiddenInput() - - return form - - def get_initial(self): - """ Fetch data from ManufacturerPart """ - - initials = super(SupplierPartEdit, self).get_initial().copy() - - supplier_part = self.get_object() - - if supplier_part.manufacturer_part: - if supplier_part.manufacturer_part.manufacturer: - initials['manufacturer'] = supplier_part.manufacturer_part.manufacturer.id - initials['MPN'] = supplier_part.manufacturer_part.MPN - - return initials - - -class SupplierPartDelete(AjaxDeleteView): - """ Delete view for removing a SupplierPart. - - SupplierParts can be deleted using a variety of 'selectors'. - - - ?part= -> Delete a single SupplierPart object - - ?parts=[] -> Delete a list of SupplierPart objects - - """ - - success_url = '/supplier/' - ajax_template_name = 'company/supplier_part_delete.html' - ajax_form_title = _('Delete Supplier Part') - - role_required = 'purchase_order.delete' - - parts = [] - - def get_context_data(self): - ctx = {} - - ctx['parts'] = self.parts - - return ctx - - def get_parts(self): - """ Determine which SupplierPart object(s) the user wishes to delete. - """ - - self.parts = [] - - # User passes a single SupplierPart ID - if 'part' in self.request.GET: - try: - self.parts.append(SupplierPart.objects.get(pk=self.request.GET.get('part'))) - except (ValueError, SupplierPart.DoesNotExist): - pass - - elif 'parts[]' in self.request.GET: - - part_id_list = self.request.GET.getlist('parts[]') - - self.parts = SupplierPart.objects.filter(id__in=part_id_list) - - def get(self, request, *args, **kwargs): - self.request = request - self.get_parts() - - return self.renderJsonResponse(request, form=self.get_form()) - - def post(self, request, *args, **kwargs): - """ Handle the POST action for deleting supplier parts. - """ - - self.request = request - self.parts = [] - - for item in self.request.POST: - if item.startswith('supplier-part-'): - pk = item.replace('supplier-part-', '') - - try: - self.parts.append(SupplierPart.objects.get(pk=pk)) - except (ValueError, SupplierPart.DoesNotExist): - pass - - confirm = str2bool(self.request.POST.get('confirm_delete', False)) - - data = { - 'form_valid': confirm, - } - - if confirm: - for part in self.parts: - part.delete() - - return self.renderJsonResponse(self.request, data=data, form=self.get_form()) diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 77de5deceb..f5eee0cdfa 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -817,18 +817,25 @@ var selections = $("#supplier-part-table").bootstrapTable("getSelections"); - var parts = []; + var requests = []; - selections.forEach(function(item) { - parts.push(item.pk); - }); - - launchModalForm("{% url 'supplier-part-delete' %}", { - data: { - parts: parts, - }, - reload: true, - }); + showQuestionDialog( + '{% trans "Delete Supplier Parts?" %}', + '{% trans "All selected supplier parts will be deleted" %}', + { + accept: function() { + selections.forEach(function(part) { + var url = `/api/company/part/${part.pk}/`; + + requests.push(inventreeDelete(url)); + }); + + $.when.apply($, requests).then(function() { + reloadSupplierPartTable(); + }); + } + } + ); }); loadSupplierPartTable( From 0288a1acbfffd1a87a9a496785a255353d1f7365 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 18 Jul 2021 22:59:34 +1000 Subject: [PATCH 435/445] Refactor edit and delete views for ManufacturerPart --- .../company/templates/company/detail.html | 20 +--- .../templates/company/manufacturer_part.html | 26 ++--- InvenTree/part/templates/part/detail.html | 19 +--- InvenTree/templates/js/company.js | 105 +++++++++++++++++- 4 files changed, 119 insertions(+), 51 deletions(-) diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html index 18e85718cb..b45289eb8c 100644 --- a/InvenTree/company/templates/company/detail.html +++ b/InvenTree/company/templates/company/detail.html @@ -284,23 +284,9 @@ $("#manufacturer-part-create").click(function () { - constructForm('{% url "api-manufacturer-part-list" %}', { - fields: { - part: {}, - manufacturer: { - value: {{ company.pk }}, - }, - MPN: { - icon: 'fa-hashtag', - }, - description: {}, - link: { - icon: 'fa-link', - }, - }, - method: 'POST', - title: '{% trans "Add Manufacturer Part" %}', - onSuccess: function() { + createManufacturerPart({ + manufacturer: {{ company.pk }}, + onSuccess: function() { $("#part-table").bootstrapTable("refresh"); } }); diff --git a/InvenTree/company/templates/company/manufacturer_part.html b/InvenTree/company/templates/company/manufacturer_part.html index bc6d4d5960..94ff64440f 100644 --- a/InvenTree/company/templates/company/manufacturer_part.html +++ b/InvenTree/company/templates/company/manufacturer_part.html @@ -297,29 +297,19 @@ $('#order-part, #order-part2').click(function() { $('#edit-part').click(function () { - constructForm('{% url "api-manufacturer-part-detail" part.pk %}', { - fields: { - part: {}, - manufacturer: {}, - MPN: { - icon: 'fa-hashtag', - }, - description: {}, - link: { - icon: 'fa-link', - }, - }, - title: '{% trans "Edit Manufacturer Part" %}', - reload: true, + editManufacturerPart({{ part.pk }}, { + onSuccess: function() { + location.reload(); + } }); }); $('#delete-part').click(function() { - constructForm('{% url "api-manufacturer-part-detail" part.pk %}', { - method: 'DELETE', - title: '{% trans "Delete Manufacturer Part" %}', - redirect: "{% url 'company-detail' part.manufacturer.id %}", + deleteManufacturerPart({{ part.pk }}, { + onSuccess: function() { + window.location.href = "{% url 'company-detail' part.manufacturer.id %}"; + } }); }); diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index f5eee0cdfa..0666108e0b 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -879,21 +879,10 @@ }); $('#manufacturer-create').click(function () { - - constructForm('{% url "api-manufacturer-part-list" %}', { - fields: { - part: { - value: {{ part.pk }}, - hidden: true, - }, - manufacturer: {}, - MPN: {}, - description: {}, - link: {}, - }, - method: 'POST', - title: '{% trans "Add Manufacturer Part" %}', - onSuccess: function() { + + createManufacturerPart({ + part: {{ part.pk }}, + onSuccess: function() { $("#manufacturer-part-table").bootstrapTable("refresh"); } }); diff --git a/InvenTree/templates/js/company.js b/InvenTree/templates/js/company.js index 553cb9e0ba..b202fbcd52 100644 --- a/InvenTree/templates/js/company.js +++ b/InvenTree/templates/js/company.js @@ -1,6 +1,65 @@ {% load i18n %} +function manufacturerPartFields() { + + return { + part: {}, + manufacturer: {}, + MPN: { + icon: 'fa-hashtag', + }, + description: {}, + link: { + icon: 'fa-link', + } + }; +} + + +function createManufacturerPart(options={}) { + + var fields = manufacturerPartFields(); + + if (options.part) { + fields.part.value = options.part; + fields.part.hidden = true; + } + + if (options.manufacturer) { + fields.manufacturer.value = options.manufacturer; + } + + constructForm('{% url "api-manufacturer-part-list" %}', { + fields: fields, + method: 'POST', + title: '{% trans "Add Manufacturer Part" %}', + onSuccess: options.onSuccess + }); +} + + +function editManufacturerPart(part, options={}) { + + var url = `/api/company/part/manufacturer/${part}/`; + + constructForm(url, { + fields: manufacturerPartFields(), + title: '{% trans "Edit Manufacturer Part" %}', + onSuccess: options.onSuccess + }); +} + +function deleteManufacturerPart(part, options={}) { + + constructForm(`/api/company/part/manufacturer/${part}/`, { + method: 'DELETE', + title: '{% trans "Delete Manufacturer Part" %}', + onSuccess: options.onSuccess, + }); +} + + function supplierPartFields() { return { @@ -400,8 +459,52 @@ function loadManufacturerPartTable(table, url, options) { title: '{% trans "Description" %}', sortable: false, switchable: true, + }, + { + field: 'actions', + title: '', + sortable: false, + switchable: false, + formatter: function(value, row) { + var pk = row.pk; + + var html = `
          `; + + html += makeIconButton('fa-edit icon-blue', 'button-manufacturer-part-edit', pk, '{% trans "Edit manufacturer part" %}'); + html += makeIconButton('fa-trash-alt icon-red', 'button-manufacturer-part-delete', pk, '{% trans "Delete manufacturer part" %}'); + + html += '
          '; + + return html; + } } ], + onPostBody: function() { + // Callbacks + $(table).find('.button-manufacturer-part-edit').click(function() { + var pk = $(this).attr('pk'); + + editManufacturerPart( + pk, + { + onSuccess: function() { + $(table).bootstrapTable('refresh'); + } + }); + }); + + $(table).find('.button-manufacturer-part-delete').click(function() { + var pk = $(this).attr('pk'); + + deleteManufacturerPart( + pk, + { + onSuccess: function() { + $(table).bootstrapTable('refresh'); + } + }); + }) + } }); } @@ -659,7 +762,7 @@ function loadSupplierPartTable(table, url, options) { var html = `
          `; html += makeIconButton('fa-edit icon-blue', 'button-supplier-part-edit', pk, '{% trans "Edit supplier part" %}'); - html += makeIconButton('fa-trash-alt icon-red', 'button-supplier-part-delete', pk, '{% trans "Delete manufacturer part" %}'); + html += makeIconButton('fa-trash-alt icon-red', 'button-supplier-part-delete', pk, '{% trans "Delete supplier part" %}'); html += '
          '; From 0d660e3c6966933660b1a8abb7573b98b86f81f5 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 19 Jul 2021 00:21:02 +1000 Subject: [PATCH 436/445] Unit test fixes (cherry picked from commit 787064abc096970b805821add983ab70a9ed9a87) --- InvenTree/company/tests.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/InvenTree/company/tests.py b/InvenTree/company/tests.py index e4a70b077a..79ffc34af5 100644 --- a/InvenTree/company/tests.py +++ b/InvenTree/company/tests.py @@ -192,18 +192,14 @@ class ManufacturerPartSimpleTest(TestCase): SKU='SKU_TEST', ) - kwargs = { - 'manufacturer': manufacturer.id, - 'MPN': 'MPN_TEST', - } - supplier_part.save(**kwargs) + supplier_part.save() def test_exists(self): - self.assertEqual(ManufacturerPart.objects.count(), 5) + self.assertEqual(ManufacturerPart.objects.count(), 4) # Check that manufacturer part was created from supplier part creation manufacturer_parts = ManufacturerPart.objects.filter(manufacturer=1) - self.assertEqual(manufacturer_parts.count(), 2) + self.assertEqual(manufacturer_parts.count(), 1) def test_delete(self): # Remove a part From 565fe9a98ecc980f97b59e7ed7c9b18821caa0f6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 19 Jul 2021 09:44:48 +1000 Subject: [PATCH 437/445] Remove custom creation code for SupplierPart serializer --- InvenTree/company/serializers.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/InvenTree/company/serializers.py b/InvenTree/company/serializers.py index 721fc54c6e..e9f13d021d 100644 --- a/InvenTree/company/serializers.py +++ b/InvenTree/company/serializers.py @@ -231,25 +231,6 @@ class SupplierPartSerializer(InvenTreeModelSerializer): 'supplier_detail', ] - def create(self, validated_data): - """ Extract manufacturer data and process ManufacturerPart """ - - # Create SupplierPart - supplier_part = super().create(validated_data) - - # Get ManufacturerPart raw data (unvalidated) - manufacturer_id = self.initial_data.get('manufacturer', None) - MPN = self.initial_data.get('MPN', None) - - if manufacturer_id and MPN: - kwargs = { - 'manufacturer': manufacturer_id, - 'MPN': MPN, - } - supplier_part.save(**kwargs) - - return supplier_part - class SupplierPriceBreakSerializer(InvenTreeModelSerializer): """ Serializer for SupplierPriceBreak object """ From 33e70ec5a7ec057aea7d0ff730de2fdbeb4635e9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 19 Jul 2021 10:55:23 +1000 Subject: [PATCH 438/445] Unit test fixes --- InvenTree/company/test_api.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/InvenTree/company/test_api.py b/InvenTree/company/test_api.py index 2da6d29198..a915ad1bf5 100644 --- a/InvenTree/company/test_api.py +++ b/InvenTree/company/test_api.py @@ -218,14 +218,27 @@ class ManufacturerTest(InvenTreeAPITestCase): def test_supplier_part_create(self): url = reverse('api-supplier-part-list') - # Create supplier part + # Create a manufacturer part + response = self.post( + reverse('api-manufacturer-part-list'), + { + 'part': 1, + 'manufacturer': 7, + 'MPN': 'PART_NUMBER', + }, + expected_code=201 + ) + + pk = response.data['pk'] + + # Create a supplier part (associated with the new manufacturer part) data = { 'part': 1, 'supplier': 1, 'SKU': 'SKU_TEST', - 'manufacturer': 7, - 'MPN': 'PART_NUMBER', + 'manufacturer_part': pk, } + response = self.client.post(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_201_CREATED) From bbada3e87339e582f246c2e76b417837b72389a7 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 19 Jul 2021 14:34:58 +1000 Subject: [PATCH 439/445] Fix duplicate table naming --- InvenTree/part/templates/part/prices.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/part/templates/part/prices.html b/InvenTree/part/templates/part/prices.html index 65d36e005a..7581d659e1 100644 --- a/InvenTree/part/templates/part/prices.html +++ b/InvenTree/part/templates/part/prices.html @@ -217,7 +217,7 @@
          -
          +
          {% if part.bom_count > 0 %} From 40c203c123fe3630dd32edc75cddb4d83825dc75 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 19 Jul 2021 14:40:02 +1000 Subject: [PATCH 440/445] Ensure BOM pricing table is loaded --- InvenTree/part/templates/part/detail.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 0666108e0b..b057b98209 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -370,6 +370,16 @@ sub_part_detail: true, }); + // Load the BOM table data in the pricing view + loadBomTable($("#bom-pricing-table"), { + editable: {{ editing_enabled }}, + bom_url: "{% url 'api-bom-list' %}", + part_url: "{% url 'api-part-list' %}", + parent_id: {{ part.id }} , + sub_part_detail: true, + }); + + linkButtonsToSelection($("#bom-table"), [ "#bom-item-delete", From e04bbb016d2a916d55ba858b84712443e1f2f399 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 19 Jul 2021 15:10:57 +1000 Subject: [PATCH 441/445] 0.3.1 Bumped API version to 8 --- InvenTree/InvenTree/version.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index 44c5dd3c59..7177703afa 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -8,12 +8,16 @@ import re import common.models -INVENTREE_SW_VERSION = "0.3.0" +INVENTREE_SW_VERSION = "0.3.1" -INVENTREE_API_VERSION = 7 +INVENTREE_API_VERSION = 8 """ -Increment thi API version number whenever there is a significant change to the API that any clients need to know about +Increment this API version number whenever there is a significant change to the API that any clients need to know about + +v8 -> 2021-07-19 + - Refactors the API interface for SupplierPart and ManufacturerPart models + - ManufacturerPart objects can no longer be created via the SupplierPart API endpoint v7 -> 2021-07-03 - Introduced the concept of "API forms" in https://github.com/inventree/InvenTree/pull/1716 From 4fdb18318a0fc2c3fcb282459c20c41fe9c90041 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 19 Jul 2021 16:32:36 +1000 Subject: [PATCH 442/445] Add "installed_items" as a context variable to the StockItem TestReport template --- InvenTree/report/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index c33347f643..db06e1c95b 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -357,7 +357,8 @@ class TestReport(ReportTemplateBase): 'serial': stock_item.serial, 'part': stock_item.part, 'results': stock_item.testResultMap(include_installed=self.include_installed), - 'result_list': stock_item.testResultList(include_installed=self.include_installed) + 'result_list': stock_item.testResultList(include_installed=self.include_installed), + 'installed_items': stock_item.get_installed_items(cascade=True), } From 87d4a515750b780f8c8ef817c3ab3a37e800f0b0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 19 Jul 2021 16:44:56 +1000 Subject: [PATCH 443/445] Add "installed items" section to default TestReport --- .../report/inventree_test_report_base.html | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/InvenTree/report/templates/report/inventree_test_report_base.html b/InvenTree/report/templates/report/inventree_test_report_base.html index 4c585d531b..d6d9c5644f 100644 --- a/InvenTree/report/templates/report/inventree_test_report_base.html +++ b/InvenTree/report/templates/report/inventree_test_report_base.html @@ -56,6 +56,10 @@ content: "{% trans 'Stock Item Test Report' %}"; {% endblock %} +{% block pre_page_content %} + +{% endblock %} + {% block page_content %}
          @@ -80,6 +84,7 @@ content: "{% trans 'Stock Item Test Report' %}";
          +{% if resul_list|length > 0 %}

          {% trans "Test Results" %}

          @@ -112,5 +117,37 @@ content: "{% trans 'Stock Item Test Report' %}";
          +{% endif %} + +{% if installed_items|length > 0 %} +

          {% trans "Installed Items" %}

          + + + + + + {% for sub_item in installed_items %} + + + + + {% endfor %} + +
          + + {{ sub_item.part.full_name }} + + {% if sub_item.serialized %} + {% trans "Serial" %}: {{ sub_item.serial }} + {% else %} + {% trans "Quantity" %}: {% decimal sub_item.quantity %} + {% endif %} +
          + +{% endif %} + +{% endblock %} + +{% block post_page_content %} {% endblock %} \ No newline at end of file From efb4f194b62c2af4a7e5c5c672ab0ff53b2bdc67 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 19 Jul 2021 17:23:18 +1000 Subject: [PATCH 444/445] Refactor StockExportOptions form --- .../company/templates/company/detail.html | 12 +---- .../templates/company/supplier_part.html | 13 ++--- InvenTree/part/templates/part/detail.html | 12 +---- InvenTree/stock/forms.py | 27 ---------- InvenTree/stock/templates/stock/location.html | 17 ++----- InvenTree/stock/urls.py | 1 - InvenTree/stock/views.py | 35 +------------ InvenTree/templates/js/forms.js | 10 ++++ InvenTree/templates/js/stock.js | 49 +++++++++++++++++++ 9 files changed, 71 insertions(+), 105 deletions(-) diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html index b45289eb8c..4a9ac43758 100644 --- a/InvenTree/company/templates/company/detail.html +++ b/InvenTree/company/templates/company/detail.html @@ -267,16 +267,8 @@ }); $("#stock-export").click(function() { - launchModalForm("{% url 'stock-export-options' %}", { - submit_text: '{% trans "Export" %}', - success: function(response) { - var url = "{% url 'stock-export' %}"; - - url += "?format=" + response.format; - url += "&supplier={{ company.id }}"; - - location.href = url; - }, + exportStock({ + supplier: {{ company.id }} }); }); diff --git a/InvenTree/company/templates/company/supplier_part.html b/InvenTree/company/templates/company/supplier_part.html index f751665e56..ec85d85af9 100644 --- a/InvenTree/company/templates/company/supplier_part.html +++ b/InvenTree/company/templates/company/supplier_part.html @@ -284,18 +284,11 @@ loadStockTable($("#stock-table"), { }); $("#stock-export").click(function() { - launchModalForm("{% url 'stock-export-options' %}", { - submit_text: '{% trans "Export" %}', - success: function(response) { - var url = "{% url 'stock-export' %}"; - url += "?format=" + response.format; - url += "&cascade=" + response.cascade; - url += "&supplier_part={{ part.id }}"; - - location.href = url; - }, + exportStock({ + supplier_part: {{ part.pk }}, }); + }); $("#item-create").click(function() { diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index b057b98209..b4cebe478e 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -644,17 +644,9 @@ }); $("#stock-export").click(function() { - launchModalForm("{% url 'stock-export-options' %}", { - submit_text: "{% trans 'Export' %}", - success: function(response) { - var url = "{% url 'stock-export' %}"; - url += "?format=" + response.format; - url += "&cascade=" + response.cascade; - url += "&part={{ part.id }}"; - - location.href = url; - }, + exportStock({ + part: {{ part.pk }} }); }); diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py index 0061bbb984..2f533bb6a5 100644 --- a/InvenTree/stock/forms.py +++ b/InvenTree/stock/forms.py @@ -226,33 +226,6 @@ class TestReportFormatForm(HelperForm): template = forms.ChoiceField(label=_('Template'), help_text=_('Select test report template')) -class ExportOptionsForm(HelperForm): - """ Form for selecting stock export options """ - - file_format = forms.ChoiceField(label=_('File Format'), help_text=_('Select output file format')) - - include_sublocations = forms.BooleanField(required=False, initial=True, label=_('Include sublocations'), help_text=_("Include stock items in sub locations")) - - class Meta: - model = StockLocation - fields = [ - 'file_format', - 'include_sublocations', - ] - - def get_format_choices(self): - """ File format choices """ - - choices = [(x, x.upper()) for x in GetExportFormats()] - - return choices - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - self.fields['file_format'].choices = self.get_format_choices() - - class InstallStockForm(HelperForm): """ Form for manually installing a stock item into another stock item diff --git a/InvenTree/stock/templates/stock/location.html b/InvenTree/stock/templates/stock/location.html index 229ad9cfd1..9a5aeb6a7e 100644 --- a/InvenTree/stock/templates/stock/location.html +++ b/InvenTree/stock/templates/stock/location.html @@ -227,20 +227,11 @@ {% endif %} $("#stock-export").click(function() { - launchModalForm("{% url 'stock-export-options' %}", { - submit_text: '{% trans "Export" %}', - success: function(response) { - var url = "{% url 'stock-export' %}"; - url += "?format=" + response.format; - url += "&cascade=" + response.cascade; - - {% if location %} - url += "&location={{ location.id }}"; - {% endif %} - - location.href = url; - } + exportStock({ + {% if location %} + location: {{ location.pk }} + {% endif %} }); }); diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index bcf180b700..434acde84e 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -56,7 +56,6 @@ stock_urls = [ url(r'^track/', include(stock_tracking_urls)), - url(r'^export-options/?', views.StockExportOptions.as_view(), name='stock-export-options'), url(r'^export/?', views.StockExport.as_view(), name='stock-export'), # Individual stock items diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 6b64e8b54a..008b209bc8 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -378,38 +378,6 @@ class StockItemDeleteTestData(AjaxUpdateView): return self.renderJsonResponse(request, form, data) -class StockExportOptions(AjaxView): - """ Form for selecting StockExport options """ - - model = StockLocation - ajax_form_title = _('Stock Export Options') - form_class = StockForms.ExportOptionsForm - - def post(self, request, *args, **kwargs): - - self.request = request - - fmt = request.POST.get('file_format', 'csv').lower() - cascade = str2bool(request.POST.get('include_sublocations', False)) - - # Format a URL to redirect to - url = reverse('stock-export') - - url += '?format=' + fmt - url += '&cascade=' + str(cascade) - - data = { - 'form_valid': True, - 'format': fmt, - 'cascade': cascade - } - - return self.renderJsonResponse(self.request, self.form_class(), data=data) - - def get(self, request, *args, **kwargs): - return self.renderJsonResponse(request, self.form_class()) - - class StockExport(AjaxView): """ Export stock data from a particular location. Returns a file containing stock information for that location. @@ -471,11 +439,10 @@ class StockExport(AjaxView): ) if location: - # CHeck if locations should be cascading + # Check if locations should be cascading cascade = str2bool(request.GET.get('cascade', True)) stock_items = location.get_stock_items(cascade) else: - cascade = True stock_items = StockItem.objects.all() if part: diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index 568ca5ac58..587ea07a16 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -252,6 +252,11 @@ function constructDeleteForm(fields, options) { */ function constructForm(url, options) { + // An "empty" form will be defined locally + if (url == null) { + constructFormBody({}, options); + } + // Save the URL options.url = url; @@ -378,6 +383,11 @@ function constructFormBody(fields, options) { fields[field].placeholder = field_options.placeholder; } + // Choices + if (field_options.choices) { + fields[field].choices = field_options.choices; + } + // Field prefix if (field_options.prefix) { fields[field].prefix = field_options.prefix; diff --git a/InvenTree/templates/js/stock.js b/InvenTree/templates/js/stock.js index 1d38b631a5..947e7fb3e9 100644 --- a/InvenTree/templates/js/stock.js +++ b/InvenTree/templates/js/stock.js @@ -20,6 +20,55 @@ function stockStatusCodes() { } +/* + * Export stock table + */ +function exportStock(params={}) { + + constructFormBody({}, { + title: '{% trans "Export Stock" %}', + fields: { + format: { + label: '{% trans "Format" %}', + help_text: '{% trans "Select file format" %}', + required: true, + type: 'choice', + value: 'csv', + choices: [ + { value: 'csv', display_name: 'CSV' }, + { value: 'tsv', display_name: 'TSV' }, + { value: 'xls', display_name: 'XLS' }, + { value: 'xlsx', display_name: 'XLSX' }, + ] + }, + sublocations: { + label: '{% trans "Include Sublocations" %}', + help_text: '{% trans "Include stock items in sublocations" %}', + type: 'boolean', + value: 'true', + } + }, + onSubmit: function(fields, form_options) { + + var format = getFormFieldValue('format', fields['format'], form_options); + var cascade = getFormFieldValue('sublocations', fields['sublocations'], form_options); + + // Hide the modal + $(form_options.modal).modal('hide'); + + var url = `{% url "stock-export" %}?format=${format}&cascade=${cascade}`; + + for (var key in params) { + url += `&${key}=${params[key]}`; + } + + console.log(url); + location.href = url; + } + }); +} + + /** * Perform stock adjustments */ From 441369984424fcadef23c098450d4cfa5b7d9a80 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 19 Jul 2021 17:23:51 +1000 Subject: [PATCH 445/445] PEP fixes --- InvenTree/stock/forms.py | 1 - 1 file changed, 1 deletion(-) diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py index 2f533bb6a5..b23b71a2d6 100644 --- a/InvenTree/stock/forms.py +++ b/InvenTree/stock/forms.py @@ -13,7 +13,6 @@ from django.core.exceptions import ValidationError from mptt.fields import TreeNodeChoiceField -from InvenTree.helpers import GetExportFormats from InvenTree.forms import HelperForm from InvenTree.fields import RoundingDecimalFormField from InvenTree.fields import DatePickerFormField