diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 37a8bf82e1..6b76c7d41b 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -12,7 +12,7 @@ from decimal import Decimal from wsgiref.util import FileWrapper from django.http import StreamingHttpResponse -from django.core.exceptions import ValidationError +from django.core.exceptions import ValidationError, FieldError from django.utils.translation import ugettext as _ from django.contrib.auth.models import Permission @@ -414,7 +414,7 @@ def extract_serial_numbers(serials, expected_quantity): return numbers -def validateFilterString(value): +def validateFilterString(value, model=None): """ Validate that a provided filter string looks like a list of comma-separated key=value pairs @@ -464,6 +464,15 @@ def validateFilterString(value): results[k] = v + # If a model is provided, verify that the provided filters can be used against it + if model is not None: + try: + model.objects.filter(**results) + except FieldError as e: + raise ValidationError( + str(e), + ) + return results diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 7247caa8d9..42f4ba4660 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -11,17 +11,20 @@ database setup in this file. """ -import sys -import os import logging +import os +import sys import tempfile -import yaml - from datetime import datetime +import yaml from django.utils.translation import gettext_lazy as _ +def _is_true(x): + return x in [True, "True", "true", "Y", "y", "1"] + + # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -36,11 +39,14 @@ with open(cfg_filename, 'r') as cfg: # Default action is to run the system in Debug mode # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = CONFIG.get('debug', True) +DEBUG = _is_true(os.getenv("INVENTREE_DEBUG", CONFIG.get("debug", True))) # Configure logging settings - log_level = CONFIG.get('log_level', 'DEBUG').upper() +logging.basicConfig( + level=log_level, + format="%(asctime)s %(levelname)s %(message)s", +) if log_level not in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']: log_level = 'WARNING' @@ -59,20 +65,31 @@ LOGGING = { }, } -logging.basicConfig( - level=log_level, - format='%(asctime)s %(levelname)s %(message)s', -) - # Get a logger instance for this setup file logger = logging.getLogger(__name__) -# Read the autogenerated key-file -key_file_name = os.path.join(BASE_DIR, 'secret_key.txt') -logger.info(f'Loading SECRET_KEY from {key_file_name}') -key_file = open(key_file_name, 'r') - -SECRET_KEY = key_file.read().strip() +if os.getenv("INVENTREE_SECRET_KEY"): + # Secret key passed in directly + SECRET_KEY = os.getenv("INVENTREE_SECRET_KEY").strip() + logger.info("SECRET_KEY loaded by INVENTREE_SECRET_KEY") +else: + # Secret key passed in by file location + key_file = os.getenv("INVENTREE_SECRET_KEY_FILE") + if key_file: + if os.path.isfile(key_file): + logger.info("SECRET_KEY loaded by INVENTREE_SECRET_KEY_FILE") + else: + logger.error(f"Secret key file {key_file} not found") + exit(-1) + else: + # default secret key location + key_file = os.path.join(BASE_DIR, "secret_key.txt") + logger.info(f"SECRET_KEY loaded from {key_file}") + try: + SECRET_KEY = open(key_file, "r").read().strip() + except Exception: + logger.exception(f"Couldn't load keyfile {key_file}") + sys.exit(-1) # List of allowed hosts (default = allow all) ALLOWED_HOSTS = CONFIG.get('allowed_hosts', ['*']) @@ -112,7 +129,7 @@ MEDIA_ROOT = os.path.abspath(CONFIG.get('media_root', os.path.join(BASE_DIR, 'me if DEBUG: logger.info("InvenTree running in DEBUG mode") - + logger.info(f"MEDIA_ROOT: '{MEDIA_ROOT}'") logger.info(f"STATIC_ROOT: '{STATIC_ROOT}'") @@ -315,7 +332,7 @@ else: - However there may be reason to configure the DB via environmental variables - The following code lets the user "mix and match" database configuration """ - + logger.info("Configuring database backend:") # Extract database configuration from the config.yaml file @@ -341,7 +358,7 @@ else: # Check that required database configuration options are specified reqiured_keys = ['ENGINE', 'NAME'] - + for key in reqiured_keys: if key not in db_config: error_msg = f'Missing required database configuration value {key} in config.yaml' diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index 79c662182e..d8a64708a9 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -28,6 +28,7 @@ from company.api import company_api_urls from stock.api import stock_api_urls from build.api import build_api_urls from order.api import order_api_urls +from label.api import label_api_urls from django.conf import settings from django.conf.urls.static import static @@ -58,6 +59,7 @@ apipatterns = [ url(r'^stock/', include(stock_api_urls)), url(r'^build/', include(build_api_urls)), url(r'^order/', include(order_api_urls)), + url(r'^label/', include(label_api_urls)), # User URLs url(r'^user/', include(user_urls)), @@ -90,6 +92,7 @@ settings_urls = [ # Some javascript files are served 'dynamically', allowing them to pass through the Django translation layer dynamic_javascript_urls = [ + 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'), @@ -97,6 +100,7 @@ dynamic_javascript_urls = [ url(r'^company.js', DynamicJsView.as_view(template_name='js/company.js'), name='company.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'^stock.js', DynamicJsView.as_view(template_name='js/stock.js'), name='stock.js'), url(r'^table_filters.js', DynamicJsView.as_view(template_name='js/table_filters.js'), name='table_filters.js'), ] diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 5c04f9a7e9..4a6bde8bfe 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -160,6 +160,13 @@ class InvenTreeSetting(models.Model): 'validator': bool, }, + 'PART_SHOW_QUANTITY_IN_FORMS': { + 'name': _('Show Quantity in Forms'), + 'description': _('Display available part quantity in some forms'), + 'default': True, + 'validator': bool, + }, + 'STOCK_ENABLE_EXPIRY': { 'name': _('Stock Expiry'), 'description': _('Enable stock expiry functionality'), diff --git a/InvenTree/company/fixtures/company.yaml b/InvenTree/company/fixtures/company.yaml index 69edee693a..8301eb0f5e 100644 --- a/InvenTree/company/fixtures/company.yaml +++ b/InvenTree/company/fixtures/company.yaml @@ -5,20 +5,29 @@ fields: name: ACME description: A Cool Military Enterprise + - model: company.company pk: 2 fields: name: Appel Computers description: Think more differenter + - model: company.company pk: 3 fields: name: Zerg Corp description: We eat the competition + - model: company.company pk: 4 fields: name: A customer description: A company that we sell things to! is_customer: True - \ No newline at end of file + +- model: company.company + pk: 5 + fields: + name: Another customer! + description: Yet another company + is_customer: True diff --git a/InvenTree/label/admin.py b/InvenTree/label/admin.py index 71399efabb..2e4967ffc2 100644 --- a/InvenTree/label/admin.py +++ b/InvenTree/label/admin.py @@ -3,12 +3,13 @@ from __future__ import unicode_literals from django.contrib import admin -from .models import StockItemLabel +from .models import StockItemLabel, StockLocationLabel -class StockItemLabelAdmin(admin.ModelAdmin): +class LabelAdmin(admin.ModelAdmin): list_display = ('name', 'description', 'label', 'filters', 'enabled') -admin.site.register(StockItemLabel, StockItemLabelAdmin) +admin.site.register(StockItemLabel, LabelAdmin) +admin.site.register(StockLocationLabel, LabelAdmin) diff --git a/InvenTree/label/api.py b/InvenTree/label/api.py new file mode 100644 index 0000000000..48ead2f443 --- /dev/null +++ b/InvenTree/label/api.py @@ -0,0 +1,375 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import sys + +from django.utils.translation import ugettext as _ +from django.conf.urls import url, include + +from django_filters.rest_framework import DjangoFilterBackend + +from rest_framework import generics, filters +from rest_framework.response import Response + +import InvenTree.helpers + +from stock.models import StockItem, StockLocation + +from .models import StockItemLabel, StockLocationLabel +from .serializers import StockItemLabelSerializer, StockLocationLabelSerializer + + +class LabelListView(generics.ListAPIView): + """ + Generic API class for label templates + """ + + filter_backends = [ + DjangoFilterBackend, + filters.SearchFilter + ] + + filter_fields = [ + 'enabled', + ] + + search_fields = [ + 'name', + 'description', + ] + + +class StockItemLabelMixin: + """ + Mixin for extracting stock items from query params + """ + + def get_items(self): + """ + Return a list of requested stock items + """ + + items = [] + + params = self.request.query_params + + if 'items[]' in params: + items = params.getlist('items[]', []) + elif 'item' in params: + items = [params.get('item', None)] + + if type(items) not in [list, tuple]: + items = [items] + + valid_ids = [] + + for item in items: + try: + valid_ids.append(int(item)) + except (ValueError): + pass + + # List of StockItems which match provided values + valid_items = StockItem.objects.filter(pk__in=valid_ids) + + return valid_items + + +class StockItemLabelList(LabelListView, StockItemLabelMixin): + """ + API endpoint for viewing list of StockItemLabel objects. + + Filterable by: + + - enabled: Filter by enabled / disabled status + - item: Filter by single stock item + - items: Filter by list of stock items + + """ + + queryset = StockItemLabel.objects.all() + serializer_class = StockItemLabelSerializer + + def filter_queryset(self, queryset): + """ + Filter the StockItem label queryset. + """ + + queryset = super().filter_queryset(queryset) + + # List of StockItem objects to match against + items = self.get_items() + + # We wish to filter by stock items + if len(items) > 0: + """ + At this point, we are basically forced to be inefficient, + as we need to compare the 'filters' string of each label, + and see if it matches against each of the requested items. + + TODO: In the future, if this becomes excessively slow, it + will need to be readdressed. + """ + + # Keep track of which labels match every specified stockitem + valid_label_ids = set() + + for label in queryset.all(): + + matches = True + + # Filter string defined for the StockItemLabel object + filters = InvenTree.helpers.validateFilterString(label.filters) + + for item in items: + + item_query = StockItem.objects.filter(pk=item.pk) + + if not item_query.filter(**filters).exists(): + matches = False + break + + # Matched all items + if matches: + valid_label_ids.add(label.pk) + else: + continue + + # Reduce queryset to only valid matches + queryset = queryset.filter(pk__in=[pk for pk in valid_label_ids]) + + return queryset + + +class StockItemLabelDetail(generics.RetrieveUpdateDestroyAPIView): + """ + API endpoint for a single StockItemLabel object + """ + + queryset = StockItemLabel.objects.all() + serializer_class = StockItemLabelSerializer + + +class StockItemLabelPrint(generics.RetrieveAPIView, StockItemLabelMixin): + """ + API endpoint for printing a StockItemLabel object + """ + + queryset = StockItemLabel.objects.all() + serializer_class = StockItemLabelSerializer + + def get(self, request, *args, **kwargs): + """ + Check if valid stock item(s) have been provided. + """ + + items = self.get_items() + + if len(items) == 0: + # No valid items provided, return an error message + data = { + 'error': _('Must provide valid StockItem(s)'), + } + + return Response(data, status=400) + + label = self.get_object() + + try: + pdf = label.render(items) + except: + + e = sys.exc_info()[1] + + data = { + 'error': _('Error during label rendering'), + 'message': str(e), + } + + return Response(data, status=400) + + return InvenTree.helpers.DownloadFile( + pdf.getbuffer(), + 'stock_item_label.pdf', + content_type='application/pdf' + ) + + +class StockLocationLabelMixin: + """ + Mixin for extracting stock locations from query params + """ + + def get_locations(self): + """ + Return a list of requested stock locations + """ + + locations = [] + + params = self.request.query_params + + if 'locations[]' in params: + locations = params.getlist('locations[]', []) + elif 'location' in params: + locations = [params.get('location', None)] + + if type(locations) not in [list, tuple]: + locations = [locations] + + valid_ids = [] + + for loc in locations: + try: + valid_ids.append(int(loc)) + except (ValueError): + pass + + # List of StockLocation objects which match provided values + valid_locations = StockLocation.objects.filter(pk__in=valid_ids) + + return valid_locations + + +class StockLocationLabelList(LabelListView, StockLocationLabelMixin): + """ + API endpoint for viewiing list of StockLocationLabel objects. + + Filterable by: + + - enabled: Filter by enabled / disabled status + - location: Filter by a single stock location + - locations: Filter by list of stock locations + """ + + queryset = StockLocationLabel.objects.all() + serializer_class = StockLocationLabelSerializer + + def filter_queryset(self, queryset): + """ + Filter the StockLocationLabel queryset + """ + + queryset = super().filter_queryset(queryset) + + # List of StockLocation objects to match against + locations = self.get_locations() + + # We wish to filter by stock location(s) + if len(locations) > 0: + """ + At this point, we are basically forced to be inefficient, + as we need to compare the 'filters' string of each label, + and see if it matches against each of the requested items. + + TODO: In the future, if this becomes excessively slow, it + will need to be readdressed. + """ + + valid_label_ids = set() + + for label in queryset.all(): + + matches = True + + # Filter string defined for the StockLocationLabel object + filters = InvenTree.helpers.validateFilterString(label.filters) + + for loc in locations: + + loc_query = StockLocation.objects.filter(pk=loc.pk) + + if not loc_query.filter(**filters).exists(): + matches = False + break + + # Matched all items + if matches: + valid_label_ids.add(label.pk) + else: + continue + + # Reduce queryset to only valid matches + queryset = queryset.filter(pk__in=[pk for pk in valid_label_ids]) + + return queryset + + +class StockLocationLabelDetail(generics.RetrieveUpdateDestroyAPIView): + """ + API endpoint for a single StockLocationLabel object + """ + + queryset = StockLocationLabel.objects.all() + serializer_class = StockLocationLabelSerializer + + +class StockLocationLabelPrint(generics.RetrieveAPIView, StockLocationLabelMixin): + """ + API endpoint for printing a StockLocationLabel object + """ + + queryset = StockLocationLabel.objects.all() + seiralizers_class = StockLocationLabelSerializer + + def get(self, request, *args, **kwargs): + + locations = self.get_locations() + + if len(locations) == 0: + # No valid locations provided - return an error message + + return Response( + { + 'error': _('Must provide valid StockLocation(s)'), + }, + status=400, + ) + + label = self.get_object() + + try: + pdf = label.render(locations) + except: + e = sys.exc_info()[1] + + data = { + 'error': _('Error during label rendering'), + 'message': str(e), + } + + return Response(data, status=400) + + return InvenTree.helpers.DownloadFile( + pdf.getbuffer(), + 'stock_location_label.pdf', + content_type='application/pdf' + ) + + +label_api_urls = [ + + # Stock item labels + url(r'stock/', include([ + # Detail views + url(r'^(?P\d+)/', include([ + url(r'print/?', StockItemLabelPrint.as_view(), name='api-stockitem-label-print'), + url(r'^.*$', StockItemLabelDetail.as_view(), name='api-stockitem-label-detail'), + ])), + + # List view + url(r'^.*$', StockItemLabelList.as_view(), name='api-stockitem-label-list'), + ])), + + # Stock location labels + url(r'location/', include([ + # Detail views + url(r'^(?P\d+)/', include([ + url(r'print/?', StockLocationLabelPrint.as_view(), name='api-stocklocation-label-print'), + url(r'^.*$', StockLocationLabelDetail.as_view(), name='api-stocklocation-label-detail'), + ])), + + # List view + url(r'^.*$', StockLocationLabelList.as_view(), name='api-stocklocation-label-list'), + ])), +] diff --git a/InvenTree/label/apps.py b/InvenTree/label/apps.py index ea4fa152ff..321047a551 100644 --- a/InvenTree/label/apps.py +++ b/InvenTree/label/apps.py @@ -1,5 +1,168 @@ +import os +import shutil +import logging + from django.apps import AppConfig +from django.conf import settings + + +logger = logging.getLogger(__name__) class LabelConfig(AppConfig): name = 'label' + + def ready(self): + """ + This function is called whenever the label app is loaded + """ + + self.create_stock_item_labels() + self.create_stock_location_labels() + + def create_stock_item_labels(self): + """ + Create database entries for the default StockItemLabel templates, + if they do not already exist + """ + + try: + from .models import StockItemLabel + except: + # Database might not by ready yet + return + + src_dir = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + 'templates', + 'stockitem', + ) + + dst_dir = os.path.join( + settings.MEDIA_ROOT, + 'label', + 'inventree', + 'stockitem', + ) + + if not os.path.exists(dst_dir): + logger.info(f"Creating missing directory: '{dst_dir}'") + os.makedirs(dst_dir, exist_ok=True) + + labels = [ + { + 'file': 'qr.html', + 'name': 'QR Code', + 'description': 'Simple QR code label', + }, + ] + + for label in labels: + + filename = os.path.join( + 'label', + 'inventree', + 'stockitem', + label['file'], + ) + + # Check if the file exists in the media directory + src_file = os.path.join(src_dir, label['file']) + dst_file = os.path.join(settings.MEDIA_ROOT, filename) + + if not os.path.exists(dst_file): + logger.info(f"Copying label template '{dst_file}'") + shutil.copyfile(src_file, dst_file) + + try: + # Check if a label matching the template already exists + if StockItemLabel.objects.filter(label=filename).exists(): + continue + + logger.info(f"Creating entry for StockItemLabel '{label['name']}'") + + StockItemLabel.objects.create( + name=label['name'], + description=label['description'], + label=filename, + filters='', + enabled=True + ) + except: + pass + + def create_stock_location_labels(self): + """ + Create database entries for the default StockItemLocation templates, + if they do not already exist + """ + + try: + from .models import StockLocationLabel + except: + # Database might not yet be ready + return + + src_dir = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + 'templates', + 'stocklocation', + ) + + dst_dir = os.path.join( + settings.MEDIA_ROOT, + 'label', + 'inventree', + 'stocklocation', + ) + + if not os.path.exists(dst_dir): + logger.info(f"Creating missing directory: '{dst_dir}'") + os.makedirs(dst_dir, exist_ok=True) + + labels = [ + { + 'file': 'qr.html', + 'name': 'QR Code', + 'description': 'Simple QR code label', + }, + { + 'file': 'qr_and_text.html', + 'name': 'QR and text', + 'description': 'Label with QR code and name of location', + } + ] + + for label in labels: + + filename = os.path.join( + 'label', + 'inventree', + 'stocklocation', + label['file'], + ) + + # Check if the file exists in the media directory + src_file = os.path.join(src_dir, label['file']) + dst_file = os.path.join(settings.MEDIA_ROOT, filename) + + if not os.path.exists(dst_file): + logger.info(f"Copying label template '{dst_file}'") + shutil.copyfile(src_file, dst_file) + + try: + # Check if a label matching the template already exists + if StockLocationLabel.objects.filter(label=filename).exists(): + continue + + logger.info(f"Creating entry for StockLocationLabel '{label['name']}'") + + StockLocationLabel.objects.create( + name=label['name'], + description=label['description'], + label=filename, + filters='', + enabled=True + ) + except: + pass diff --git a/InvenTree/label/migrations/0003_stocklocationlabel.py b/InvenTree/label/migrations/0003_stocklocationlabel.py new file mode 100644 index 0000000000..d15fcfa396 --- /dev/null +++ b/InvenTree/label/migrations/0003_stocklocationlabel.py @@ -0,0 +1,30 @@ +# Generated by Django 3.0.7 on 2021-01-08 12:06 + +import InvenTree.helpers +import django.core.validators +from django.db import migrations, models +import label.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('label', '0002_stockitemlabel_enabled'), + ] + + operations = [ + migrations.CreateModel( + name='StockLocationLabel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(help_text='Label name', max_length=100, unique=True)), + ('description', models.CharField(blank=True, help_text='Label description', max_length=250, null=True)), + ('label', models.FileField(help_text='Label template file', upload_to=label.models.rename_label, validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['html'])])), + ('filters', models.CharField(blank=True, help_text='Query filters (comma-separated list of key=value pairs', max_length=250, validators=[InvenTree.helpers.validateFilterString])), + ('enabled', models.BooleanField(default=True, help_text='Label template is enabled', verbose_name='Enabled')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/InvenTree/label/migrations/0004_auto_20210111_2302.py b/InvenTree/label/migrations/0004_auto_20210111_2302.py new file mode 100644 index 0000000000..5194a4bda1 --- /dev/null +++ b/InvenTree/label/migrations/0004_auto_20210111_2302.py @@ -0,0 +1,56 @@ +# Generated by Django 3.0.7 on 2021-01-11 12:02 + +import InvenTree.helpers +import django.core.validators +from django.db import migrations, models +import label.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('label', '0003_stocklocationlabel'), + ] + + operations = [ + migrations.AlterField( + model_name='stockitemlabel', + name='description', + field=models.CharField(blank=True, help_text='Label description', max_length=250, null=True, verbose_name='Description'), + ), + migrations.AlterField( + model_name='stockitemlabel', + name='filters', + field=models.CharField(blank=True, help_text='Query filters (comma-separated list of key=value pairs', max_length=250, validators=[InvenTree.helpers.validateFilterString], verbose_name='Filters'), + ), + migrations.AlterField( + model_name='stockitemlabel', + name='label', + field=models.FileField(help_text='Label template file', unique=True, upload_to=label.models.rename_label, validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['html'])], verbose_name='Label'), + ), + migrations.AlterField( + model_name='stockitemlabel', + name='name', + field=models.CharField(help_text='Label name', max_length=100, verbose_name='Name'), + ), + migrations.AlterField( + model_name='stocklocationlabel', + name='description', + field=models.CharField(blank=True, help_text='Label description', max_length=250, null=True, verbose_name='Description'), + ), + migrations.AlterField( + model_name='stocklocationlabel', + name='filters', + field=models.CharField(blank=True, help_text='Query filters (comma-separated list of key=value pairs', max_length=250, validators=[InvenTree.helpers.validateFilterString], verbose_name='Filters'), + ), + migrations.AlterField( + model_name='stocklocationlabel', + name='label', + field=models.FileField(help_text='Label template file', unique=True, upload_to=label.models.rename_label, validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['html'])], verbose_name='Label'), + ), + migrations.AlterField( + model_name='stocklocationlabel', + name='name', + field=models.CharField(help_text='Label name', max_length=100, verbose_name='Name'), + ), + ] diff --git a/InvenTree/label/migrations/0005_auto_20210113_2302.py b/InvenTree/label/migrations/0005_auto_20210113_2302.py new file mode 100644 index 0000000000..ad256412ac --- /dev/null +++ b/InvenTree/label/migrations/0005_auto_20210113_2302.py @@ -0,0 +1,24 @@ +# Generated by Django 3.0.7 on 2021-01-13 12:02 + +from django.db import migrations, models +import label.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('label', '0004_auto_20210111_2302'), + ] + + operations = [ + migrations.AlterField( + model_name='stockitemlabel', + name='filters', + field=models.CharField(blank=True, help_text='Query filters (comma-separated list of key=value pairs', max_length=250, validators=[label.models.validate_stock_item_filters], verbose_name='Filters'), + ), + migrations.AlterField( + model_name='stocklocationlabel', + name='filters', + field=models.CharField(blank=True, help_text='Query filters (comma-separated list of key=value pairs', max_length=250, validators=[label.models.validate_stock_location_filters], verbose_name='Filters'), + ), + ] diff --git a/InvenTree/label/models.py b/InvenTree/label/models.py index 49b07572a8..a34aa3831d 100644 --- a/InvenTree/label/models.py +++ b/InvenTree/label/models.py @@ -17,7 +17,7 @@ from django.utils.translation import gettext_lazy as _ from InvenTree.helpers import validateFilterString, normalize -from stock.models import StockItem +import stock.models def rename_label(instance, filename): @@ -28,6 +28,20 @@ def rename_label(instance, filename): return os.path.join('label', 'template', instance.SUBDIR, filename) +def validate_stock_item_filters(filters): + + filters = validateFilterString(filters, model=stock.models.StockItem) + + return filters + + +def validate_stock_location_filters(filters): + + filters = validateFilterString(filters, model=stock.models.StockLocation) + + return filters + + class LabelTemplate(models.Model): """ Base class for generic, filterable labels. @@ -50,30 +64,31 @@ class LabelTemplate(models.Model): ) name = models.CharField( - unique=True, blank=False, max_length=100, + verbose_name=_('Name'), help_text=_('Label name'), ) - description = models.CharField(max_length=250, help_text=_('Label description'), blank=True, null=True) + description = models.CharField( + max_length=250, + blank=True, null=True, + verbose_name=_('Description'), + help_text=_('Label description'), + ) label = models.FileField( upload_to=rename_label, + unique=True, blank=False, null=False, + verbose_name=_('Label'), help_text=_('Label template file'), validators=[FileExtensionValidator(allowed_extensions=['html'])], ) - filters = models.CharField( - blank=True, max_length=250, - help_text=_('Query filters (comma-separated list of key=value pairs'), - validators=[validateFilterString] - ) - enabled = models.BooleanField( default=True, + verbose_name=_('Enabled'), help_text=_('Label template is enabled'), - verbose_name=_('Enabled') ) def get_record_data(self, items): @@ -117,6 +132,14 @@ class StockItemLabel(LabelTemplate): SUBDIR = "stockitem" + filters = models.CharField( + blank=True, max_length=250, + help_text=_('Query filters (comma-separated list of key=value pairs'), + verbose_name=_('Filters'), + validators=[ + validate_stock_item_filters] + ) + def matches_stock_item(self, item): """ Test if this label template matches a given StockItem object @@ -124,7 +147,7 @@ class StockItemLabel(LabelTemplate): filters = validateFilterString(self.filters) - items = StockItem.objects.filter(**filters) + items = stock.models.StockItem.objects.filter(**filters) items = items.filter(pk=item.pk) @@ -153,3 +176,47 @@ class StockItemLabel(LabelTemplate): }) return records + + +class StockLocationLabel(LabelTemplate): + """ + Template for printing StockLocation labels + """ + + SUBDIR = "stocklocation" + + filters = models.CharField( + blank=True, max_length=250, + help_text=_('Query filters (comma-separated list of key=value pairs'), + verbose_name=_('Filters'), + validators=[ + validate_stock_location_filters] + ) + + def matches_stock_location(self, location): + """ + Test if this label template matches a given StockLocation object + """ + + filters = validateFilterString(self.filters) + + locs = stock.models.StockLocation.objects.filter(**filters) + + locs = locs.filter(pk=location.pk) + + return locs.exists() + + def get_record_data(self, locations): + """ + Generate context data for each provided StockLocation + """ + + records = [] + + for loc in locations: + + records.append({ + 'location': loc, + }) + + return records diff --git a/InvenTree/label/serializers.py b/InvenTree/label/serializers.py new file mode 100644 index 0000000000..c9d487af23 --- /dev/null +++ b/InvenTree/label/serializers.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from InvenTree.serializers import InvenTreeModelSerializer +from InvenTree.serializers import InvenTreeAttachmentSerializerField + +from .models import StockItemLabel, StockLocationLabel + + +class StockItemLabelSerializer(InvenTreeModelSerializer): + """ + Serializes a StockItemLabel object. + """ + + label = InvenTreeAttachmentSerializerField(required=True) + + class Meta: + model = StockItemLabel + fields = [ + 'pk', + 'name', + 'description', + 'label', + 'filters', + 'enabled', + ] + + +class StockLocationLabelSerializer(InvenTreeModelSerializer): + """ + Serializes a StockLocationLabel object + """ + + label = InvenTreeAttachmentSerializerField(required=True) + + class Meta: + model = StockLocationLabel + fields = [ + 'pk', + 'name', + 'description', + 'label', + 'filters', + 'enabled', + ] diff --git a/InvenTree/label/templates/stockitem/qr.html b/InvenTree/label/templates/stockitem/qr.html new file mode 100644 index 0000000000..9cd9d20769 --- /dev/null +++ b/InvenTree/label/templates/stockitem/qr.html @@ -0,0 +1,16 @@ + + + diff --git a/InvenTree/label/templates/stocklocation/qr.html b/InvenTree/label/templates/stocklocation/qr.html new file mode 100644 index 0000000000..8fb22fbb40 --- /dev/null +++ b/InvenTree/label/templates/stocklocation/qr.html @@ -0,0 +1,16 @@ + + + diff --git a/InvenTree/label/templates/stocklocation/qr_and_text.html b/InvenTree/label/templates/stocklocation/qr_and_text.html new file mode 100644 index 0000000000..9a555aca15 --- /dev/null +++ b/InvenTree/label/templates/stocklocation/qr_and_text.html @@ -0,0 +1,43 @@ + + + + +
+ {{ location.name }} +
+
+
+ Location ID: {{ location.pk }} +
+ + \ No newline at end of file diff --git a/InvenTree/label/tests.py b/InvenTree/label/tests.py index a39b155ac3..dcb051c929 100644 --- a/InvenTree/label/tests.py +++ b/InvenTree/label/tests.py @@ -1 +1,76 @@ -# Create your tests here. +# Tests for Part Parameters + +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import os + +from django.test import TestCase +from django.conf import settings +from django.core.exceptions import ValidationError + +from InvenTree.helpers import validateFilterString + +from .models import StockItemLabel, StockLocationLabel +from stock.models import StockItem + + +class LabelTest(TestCase): + + # TODO - Implement this test properly. Looks like apps.py is not run first + def _test_default_labels(self): + """ + Test that the default label templates are copied across + """ + + labels = StockItemLabel.objects.all() + + self.assertTrue(labels.count() > 0) + + labels = StockLocationLabel.objects.all() + + self.assertTrue(labels.count() > 0) + + # TODO - Implement this test properly. Looks like apps.py is not run first + def _test_default_files(self): + """ + Test that label files exist in the MEDIA directory + """ + + item_dir = os.path.join( + settings.MEDIA_ROOT, + 'label', + 'inventree', + 'stockitem', + ) + + files = os.listdir(item_dir) + + self.assertTrue(len(files) > 0) + + loc_dir = os.path.join( + settings.MEDIA_ROOT, + 'label', + 'inventree', + 'stocklocation', + ) + + files = os.listdir(loc_dir) + + self.assertTrue(len(files) > 0) + + def test_filters(self): + """ + Test the label filters + """ + + filter_string = "part__pk=10" + + filters = validateFilterString(filter_string, model=StockItem) + + self.assertEqual(type(filters), dict) + + bad_filter_string = "part_pk=10" + + with self.assertRaises(ValidationError): + validateFilterString(bad_filter_string, model=StockItem) diff --git a/InvenTree/locale/de/LC_MESSAGES/django.po b/InvenTree/locale/de/LC_MESSAGES/django.po index 31e3f80413..76931db8fa 100644 --- a/InvenTree/locale/de/LC_MESSAGES/django.po +++ b/InvenTree/locale/de/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-01-07 23:48+1100\n" +"POT-Creation-Date: 2021-01-14 23:57+1100\n" "PO-Revision-Date: 2020-05-03 11:32+0200\n" "Last-Translator: Christian Schlüter \n" "Language-Team: C \n" @@ -61,8 +61,8 @@ msgstr "" msgid "Select Category" msgstr "Teilkategorie auswählen" -#: InvenTree/helpers.py:361 order/models.py:216 order/models.py:298 -#: stock/views.py:1660 +#: InvenTree/helpers.py:361 order/models.py:232 order/models.py:330 +#: stock/views.py:1573 msgid "Invalid quantity provided" msgstr "Keine gültige Menge" @@ -105,11 +105,11 @@ msgstr "Datei zum Anhängen auswählen" msgid "File comment" msgstr "Datei-Kommentar" -#: InvenTree/models.py:68 templates/js/stock.js:759 +#: InvenTree/models.py:68 templates/js/stock.js:873 msgid "User" msgstr "Benutzer" -#: InvenTree/models.py:106 part/models.py:647 +#: InvenTree/models.py:106 label/models.py:68 part/models.py:647 #: part/templates/part/params.html:24 templates/js/part.js:129 msgid "Name" msgstr "Name" @@ -120,19 +120,19 @@ msgstr "Name" msgid "Description (optional)" msgstr "Firmenbeschreibung" -#: InvenTree/settings.py:422 +#: InvenTree/settings.py:439 msgid "English" msgstr "Englisch" -#: InvenTree/settings.py:423 +#: InvenTree/settings.py:440 msgid "German" msgstr "Deutsch" -#: InvenTree/settings.py:424 +#: InvenTree/settings.py:441 msgid "French" msgstr "Französisch" -#: InvenTree/settings.py:425 +#: InvenTree/settings.py:442 msgid "Polish" msgstr "Polnisch" @@ -338,7 +338,7 @@ msgstr "" #: build/forms.py:78 build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:83 -#: build/templates/build/detail.html:29 common/models.py:589 +#: build/templates/build/detail.html:29 common/models.py:596 #: company/forms.py:112 company/templates/company/supplier_part_pricing.html:75 #: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:179 @@ -351,8 +351,8 @@ msgstr "" #: stock/templates/stock/item_base.html:46 #: stock/templates/stock/item_base.html:214 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:338 -#: templates/js/bom.js:195 templates/js/build.js:420 templates/js/stock.js:750 -#: templates/js/stock.js:989 +#: templates/js/bom.js:195 templates/js/build.js:420 templates/js/stock.js:864 +#: templates/js/stock.js:1103 msgid "Quantity" msgstr "Anzahl" @@ -437,7 +437,7 @@ msgstr "Bauauftrag" #: build/models.py:62 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:11 #: order/templates/order/so_tabs.html:9 part/templates/part/tabs.html:31 -#: templates/InvenTree/settings/tabs.html:28 users/models.py:30 +#: templates/InvenTree/settings/tabs.html:28 users/models.py:32 msgid "Build Orders" msgstr "Bauaufträge" @@ -455,15 +455,15 @@ msgstr "Referenz" #: build/models.py:116 build/templates/build/detail.html:19 #: company/models.py:359 company/templates/company/detail.html:23 #: company/templates/company/supplier_part_base.html:61 -#: company/templates/company/supplier_part_detail.html:27 +#: company/templates/company/supplier_part_detail.html:27 label/models.py:75 #: order/templates/order/purchase_order_detail.html:161 part/models.py:671 #: part/templates/part/detail.html:51 part/templates/part/set_category.html:14 #: templates/InvenTree/search.html:147 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:180 -#: templates/js/bom.js:517 templates/js/build.js:664 templates/js/company.js:56 -#: templates/js/order.js:175 templates/js/order.js:263 templates/js/part.js:188 +#: templates/js/bom.js:549 templates/js/build.js:664 templates/js/company.js:56 +#: templates/js/order.js:180 templates/js/order.js:274 templates/js/part.js:188 #: templates/js/part.js:271 templates/js/part.js:391 templates/js/part.js:572 -#: templates/js/stock.js:501 templates/js/stock.js:731 +#: templates/js/stock.js:511 templates/js/stock.js:845 msgid "Description" msgstr "Beschreibung" @@ -484,16 +484,16 @@ msgstr "Bestellung, die diesem Bau zugwiesen ist" #: build/models.py:134 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:78 -#: build/templates/build/detail.html:24 order/models.py:623 +#: build/templates/build/detail.html:24 order/models.py:651 #: order/templates/order/order_wizard/select_parts.html:30 #: order/templates/order/purchase_order_detail.html:148 #: order/templates/order/receive_parts.html:19 part/models.py:316 #: part/templates/part/part_app_base.html:7 part/templates/part/related.html:26 #: part/templates/part/set_category.html:13 templates/InvenTree/search.html:133 -#: templates/js/barcode.js:336 templates/js/bom.js:153 templates/js/bom.js:502 +#: templates/js/barcode.js:336 templates/js/bom.js:153 templates/js/bom.js:534 #: templates/js/build.js:669 templates/js/company.js:138 -#: templates/js/part.js:252 templates/js/part.js:357 templates/js/stock.js:475 -#: templates/js/stock.js:1061 +#: templates/js/part.js:252 templates/js/part.js:357 templates/js/stock.js:485 +#: templates/js/stock.js:1175 msgid "Part" msgstr "Teil" @@ -561,7 +561,7 @@ msgstr "Bau-Status" msgid "Build status code" msgstr "Bau-Statuscode" -#: build/models.py:194 stock/models.py:397 +#: build/models.py:194 stock/models.py:412 msgid "Batch Code" msgstr "Losnummer" @@ -569,7 +569,7 @@ msgstr "Losnummer" msgid "Batch code for this build output" msgstr "Chargennummer für diese Bau-Ausgabe" -#: build/models.py:205 order/models.py:404 +#: build/models.py:205 order/models.py:436 msgid "Target completion date" msgstr "" @@ -577,11 +577,11 @@ msgstr "" #: company/templates/company/supplier_part_base.html:68 #: company/templates/company/supplier_part_detail.html:24 #: part/templates/part/detail.html:80 part/templates/part/part_base.html:102 -#: stock/models.py:391 stock/templates/stock/item_base.html:297 +#: stock/models.py:406 stock/templates/stock/item_base.html:297 msgid "External Link" msgstr "Externer Link" -#: build/models.py:220 part/models.py:705 stock/models.py:393 +#: build/models.py:220 part/models.py:705 stock/models.py:408 msgid "Link to external URL" msgstr "Link zu einer externen URL" @@ -590,9 +590,9 @@ msgstr "Link zu einer externen URL" #: order/templates/order/purchase_order_detail.html:213 #: order/templates/order/so_tabs.html:23 part/models.py:831 #: part/templates/part/tabs.html:73 stock/forms.py:313 stock/forms.py:345 -#: stock/forms.py:373 stock/models.py:463 stock/models.py:1512 +#: stock/forms.py:373 stock/models.py:478 stock/models.py:1544 #: stock/templates/stock/tabs.html:26 templates/js/barcode.js:391 -#: templates/js/bom.js:263 templates/js/stock.js:117 templates/js/stock.js:603 +#: templates/js/bom.js:295 templates/js/stock.js:127 templates/js/stock.js:618 msgid "Notes" msgstr "Notizen" @@ -643,11 +643,11 @@ msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" "zugewiesene Anzahl ({n}) darf nicht die verfügbare ({q}) Anzahl überschreiten" -#: build/models.py:971 order/models.py:707 +#: build/models.py:971 order/models.py:735 msgid "StockItem is over-allocated" msgstr "Zu viele Lagerobjekte zugewiesen" -#: build/models.py:975 order/models.py:710 +#: build/models.py:975 order/models.py:738 msgid "Allocation quantity must be greater than zero" msgstr "Anzahl muss größer null sein" @@ -758,7 +758,7 @@ msgstr "Lagerobjekt dem Bau zuweisen" #: stock/templates/stock/item_base.html:244 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:183 templates/js/barcode.js:337 -#: templates/js/build.js:434 templates/js/stock.js:587 +#: templates/js/build.js:434 templates/js/stock.js:597 msgid "Location" msgstr "Standort" @@ -800,9 +800,12 @@ msgstr "Admin" #: build/templates/build/build_base.html:43 #: build/templates/build/build_base.html:100 +#: order/templates/order/order_base.html:32 +#: order/templates/order/order_base.html:83 #: order/templates/order/sales_order_base.html:41 #: order/templates/order/sales_order_base.html:83 -#: templates/js/table_filters.js:200 templates/js/table_filters.js:232 +#: templates/js/table_filters.js:200 templates/js/table_filters.js:219 +#: templates/js/table_filters.js:236 msgid "Overdue" msgstr "" @@ -833,15 +836,16 @@ msgstr "Bau-Status" #: order/templates/order/receive_parts.html:24 #: stock/templates/stock/item_base.html:343 templates/InvenTree/search.html:175 #: templates/js/barcode.js:42 templates/js/build.js:697 -#: templates/js/order.js:180 templates/js/order.js:268 -#: templates/js/stock.js:574 templates/js/stock.js:997 +#: templates/js/order.js:185 templates/js/order.js:279 +#: templates/js/stock.js:584 templates/js/stock.js:1111 msgid "Status" msgstr "Status" #: build/templates/build/build_base.html:96 #: build/templates/build/detail.html:100 +#: order/templates/order/order_base.html:121 #: order/templates/order/sales_order_base.html:114 templates/js/build.js:710 -#: templates/js/order.js:281 +#: templates/js/order.js:198 templates/js/order.js:292 #, fuzzy #| msgid "Shipment Date" msgid "Target Date" @@ -857,13 +861,13 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:120 -#: build/templates/build/detail.html:82 order/models.py:621 +#: build/templates/build/detail.html:82 order/models.py:649 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:33 #: order/templates/order/sales_order_notes.html:10 #: order/templates/order/sales_order_ship.html:25 #: part/templates/part/allocation.html:27 -#: stock/templates/stock/item_base.html:238 templates/js/order.js:229 +#: stock/templates/stock/item_base.html:238 templates/js/order.js:240 msgid "Sales Order" msgstr "Bestellung" @@ -997,14 +1001,14 @@ msgid "Destination location not specified" msgstr "Hat dieses Teil Tracking für einzelne Objekte?" #: build/templates/build/detail.html:68 -#: stock/templates/stock/item_base.html:262 templates/js/stock.js:582 -#: templates/js/stock.js:1004 templates/js/table_filters.js:80 +#: stock/templates/stock/item_base.html:262 templates/js/stock.js:592 +#: templates/js/stock.js:1118 templates/js/table_filters.js:80 #: templates/js/table_filters.js:161 msgid "Batch" msgstr "Los" #: build/templates/build/detail.html:95 -#: order/templates/order/order_base.html:98 +#: order/templates/order/order_base.html:108 #: order/templates/order/sales_order_base.html:108 templates/js/build.js:705 msgid "Created" msgstr "Erstellt" @@ -1114,7 +1118,7 @@ msgstr "Lagerbestand dem Bau zuweisen" msgid "Create Build Output" msgstr "Bau-Ausgabe" -#: build/views.py:207 stock/models.py:872 stock/views.py:1681 +#: build/views.py:207 stock/models.py:887 stock/views.py:1594 #, fuzzy #| msgid "Serial numbers already exist: " msgid "Serial numbers already exist" @@ -1136,7 +1140,7 @@ msgstr "Bau entfernt" msgid "Confirm unallocation of build stock" msgstr "Zuweisungsaufhebung bestätigen" -#: build/views.py:303 build/views.py:388 stock/views.py:417 +#: build/views.py:303 build/views.py:388 stock/views.py:330 msgid "Check the confirmation box" msgstr "Bestätigungsbox bestätigen" @@ -1262,7 +1266,7 @@ msgid "Add Build Order Attachment" msgstr "Auftragsanhang hinzufügen" #: build/views.py:1060 order/views.py:113 order/views.py:166 part/views.py:170 -#: stock/views.py:180 +#: stock/views.py:179 msgid "Added attachment" msgstr "Anhang hinzugefügt" @@ -1278,7 +1282,7 @@ msgstr "Anhang aktualisiert" msgid "Delete Attachment" msgstr "Anhang löschen" -#: build/views.py:1123 order/views.py:242 order/views.py:257 stock/views.py:238 +#: build/views.py:1123 order/views.py:242 order/views.py:257 stock/views.py:237 msgid "Deleted attachment" msgstr "Anhang gelöscht" @@ -1375,7 +1379,7 @@ msgid "Copy category parameter templates when creating a part" msgstr "" #: common/models.py:115 part/templates/part/detail.html:155 stock/forms.py:255 -#: templates/js/table_filters.js:23 templates/js/table_filters.js:266 +#: templates/js/table_filters.js:23 templates/js/table_filters.js:270 msgid "Template" msgstr "Vorlage" @@ -1386,7 +1390,7 @@ msgid "Parts are templates by default" msgstr "Teil ist nicht virtuell" #: common/models.py:122 part/models.py:794 part/templates/part/detail.html:165 -#: templates/js/table_filters.js:278 +#: templates/js/table_filters.js:282 msgid "Assembly" msgstr "Baugruppe" @@ -1397,7 +1401,7 @@ msgid "Parts can be assembled from other components by default" msgstr "Teil kann aus anderen Teilen angefertigt werden" #: common/models.py:129 part/models.py:800 part/templates/part/detail.html:175 -#: templates/js/table_filters.js:282 +#: templates/js/table_filters.js:286 msgid "Component" msgstr "Komponente" @@ -1416,7 +1420,7 @@ msgid "Parts are purchaseable by default" msgstr "" #: common/models.py:143 part/models.py:816 part/templates/part/detail.html:205 -#: templates/js/table_filters.js:290 +#: templates/js/table_filters.js:294 msgid "Salable" msgstr "Verkäuflich" @@ -1425,7 +1429,7 @@ msgid "Parts are salable by default" msgstr "" #: common/models.py:150 part/models.py:806 part/templates/part/detail.html:185 -#: templates/js/table_filters.js:31 templates/js/table_filters.js:294 +#: templates/js/table_filters.js:31 templates/js/table_filters.js:298 msgid "Trackable" msgstr "nachverfolgbar" @@ -1446,136 +1450,146 @@ msgstr "Teil ist nicht virtuell" #: common/models.py:164 #, fuzzy +#| msgid "Stock Quantity" +msgid "Show Quantity in Forms" +msgstr "Bestand" + +#: common/models.py:165 +msgid "Display available part quantity in some forms" +msgstr "" + +#: common/models.py:171 +#, fuzzy #| msgid "Stock Export Options" msgid "Stock Expiry" msgstr "Lagerbestandsexportoptionen" -#: common/models.py:165 +#: common/models.py:172 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:171 +#: common/models.py:178 #, fuzzy #| msgid "Serialize Stock" msgid "Sell Expired Stock" msgstr "Lagerbestand erfassen" -#: common/models.py:172 +#: common/models.py:179 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:178 +#: common/models.py:185 #, fuzzy #| msgid "Stock Item" msgid "Stock Stale Time" msgstr "Lagerobjekt" -#: common/models.py:179 +#: common/models.py:186 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:181 part/templates/part/detail.html:116 +#: common/models.py:188 part/templates/part/detail.html:116 msgid "days" msgstr "" -#: common/models.py:186 +#: common/models.py:193 #, fuzzy #| msgid "Builds" msgid "Build Expired Stock" msgstr "Baue" -#: common/models.py:187 +#: common/models.py:194 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:193 +#: common/models.py:200 #, fuzzy #| msgid "Order Reference" msgid "Build Order Reference Prefix" msgstr "Bestellreferenz" -#: common/models.py:194 +#: common/models.py:201 #, fuzzy #| msgid "Order reference" msgid "Prefix value for build order reference" msgstr "Bestell-Referenz" -#: common/models.py:199 +#: common/models.py:206 #, fuzzy #| msgid "Order Reference" msgid "Build Order Reference Regex" msgstr "Bestellreferenz" -#: common/models.py:200 +#: common/models.py:207 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:204 +#: common/models.py:211 #, fuzzy #| msgid "Sales Order Reference" msgid "Sales Order Reference Prefix" msgstr "Bestellungsreferenz" -#: common/models.py:205 +#: common/models.py:212 #, fuzzy #| msgid "Order reference" msgid "Prefix value for sales order reference" msgstr "Bestell-Referenz" -#: common/models.py:210 +#: common/models.py:217 #, fuzzy #| msgid "Order reference" msgid "Purchase Order Reference Prefix" msgstr "Bestell-Referenz" -#: common/models.py:211 +#: common/models.py:218 #, fuzzy #| msgid "Order reference" msgid "Prefix value for purchase order reference" msgstr "Bestell-Referenz" -#: common/models.py:434 +#: common/models.py:441 msgid "Settings key (must be unique - case insensitive" msgstr "" "Einstellungs-Schlüssel (muss einzigartig sein, Groß-/ Kleinschreibung wird " "nicht beachtet)" -#: common/models.py:436 +#: common/models.py:443 msgid "Settings value" msgstr "Einstellungs-Wert" -#: common/models.py:493 +#: common/models.py:500 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:503 +#: common/models.py:510 #, fuzzy #| msgid "Must enter integer value" msgid "Value must be an integer value" msgstr "Nur Ganzzahl eingeben" -#: common/models.py:517 +#: common/models.py:524 msgid "Key string must be unique" msgstr "Schlüsseltext muss eindeutig sein" -#: common/models.py:590 company/forms.py:113 +#: common/models.py:597 company/forms.py:113 #, fuzzy #| msgid "Price Breaks" msgid "Price break quantity" msgstr "Preisstaffelung" -#: common/models.py:598 company/templates/company/supplier_part_pricing.html:80 +#: common/models.py:605 company/templates/company/supplier_part_pricing.html:80 #: part/templates/part/sale_prices.html:87 templates/js/bom.js:246 msgid "Price" msgstr "Preis" -#: common/models.py:599 +#: common/models.py:606 #, fuzzy #| msgid "Enter a valid quantity" msgid "Unit price at specified quantity" msgstr "Bitte eine gültige Anzahl eingeben" -#: common/models.py:622 +#: common/models.py:629 #, fuzzy #| msgid "Default Location" msgid "Default" @@ -1696,7 +1710,7 @@ msgstr "Produziert diese Firma Teile?" msgid "Currency" msgstr "Währung bearbeiten" -#: company/models.py:313 stock/models.py:345 +#: company/models.py:313 stock/models.py:360 #: stock/templates/stock/item_base.html:194 msgid "Base Part" msgstr "Basisteil" @@ -1708,10 +1722,10 @@ msgstr "Teil auswählen" #: company/models.py:323 company/templates/company/detail.html:57 #: company/templates/company/supplier_part_base.html:74 #: company/templates/company/supplier_part_detail.html:21 -#: order/templates/order/order_base.html:79 +#: order/templates/order/order_base.html:89 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:170 #: stock/templates/stock/item_base.html:304 templates/js/company.js:48 -#: templates/js/company.js:164 templates/js/order.js:162 +#: templates/js/company.js:164 templates/js/order.js:167 msgid "Supplier" msgstr "Zulieferer" @@ -1814,9 +1828,9 @@ msgid "Uses default currency" msgstr "Währung entfernen" #: company/templates/company/detail.html:62 -#: order/templates/order/sales_order_base.html:89 stock/models.py:380 -#: stock/models.py:381 stock/templates/stock/item_base.html:221 -#: templates/js/company.js:40 templates/js/order.js:250 +#: order/templates/order/sales_order_base.html:89 stock/models.py:395 +#: stock/models.py:396 stock/templates/stock/item_base.html:221 +#: templates/js/company.js:40 templates/js/order.js:261 msgid "Customer" msgstr "Kunde" @@ -1831,7 +1845,7 @@ msgstr "Neues Zuliefererteil anlegen" #: company/templates/company/detail_part.html:18 #: order/templates/order/purchase_order_detail.html:68 -#: part/templates/part/supplier.html:14 templates/js/stock.js:881 +#: part/templates/part/supplier.html:14 templates/js/stock.js:995 msgid "New Supplier Part" msgstr "Neues Zulieferer-Teil" @@ -1859,7 +1873,7 @@ msgid "Delete Parts" msgstr "Teile löschen" #: company/templates/company/detail_part.html:63 -#: part/templates/part/category.html:116 templates/js/stock.js:875 +#: part/templates/part/category.html:116 templates/js/stock.js:989 msgid "New Part" msgstr "Neues Teil" @@ -1917,7 +1931,7 @@ msgstr "" #: order/templates/order/purchase_orders.html:13 #: part/templates/part/orders.html:9 part/templates/part/tabs.html:48 #: templates/InvenTree/settings/tabs.html:31 templates/navbar.html:33 -#: users/models.py:31 +#: users/models.py:33 msgid "Purchase Orders" msgstr "Bestellungen" @@ -1937,7 +1951,7 @@ msgstr "Neue Bestellung" #: order/templates/order/sales_orders.html:13 #: part/templates/part/sales_orders.html:9 part/templates/part/tabs.html:56 #: templates/InvenTree/settings/tabs.html:34 templates/navbar.html:42 -#: users/models.py:32 +#: users/models.py:34 msgid "Sales Orders" msgstr "Bestellungen" @@ -1952,7 +1966,7 @@ msgid "New Sales Order" msgstr "Neuer Auftrag" #: company/templates/company/supplier_part_base.html:6 -#: company/templates/company/supplier_part_base.html:19 stock/models.py:354 +#: company/templates/company/supplier_part_base.html:19 stock/models.py:369 #: stock/templates/stock/item_base.html:309 templates/js/company.js:180 msgid "Supplier Part" msgstr "Zulieferer-Teil" @@ -2031,8 +2045,7 @@ msgstr "Bepreisung" #: company/templates/company/tabs.html:12 part/templates/part/tabs.html:18 #: stock/templates/stock/location.html:17 templates/InvenTree/search.html:155 #: templates/InvenTree/settings/tabs.html:25 templates/js/part.js:192 -#: templates/js/part.js:418 templates/js/stock.js:509 templates/navbar.html:22 -#: users/models.py:29 +#: templates/js/part.js:418 templates/js/stock.js:519 templates/navbar.html:22 msgid "Stock" msgstr "Lagerbestand" @@ -2045,7 +2058,7 @@ msgstr "Bestellungen" #: part/templates/part/cat_link.html:7 part/templates/part/category.html:94 #: part/templates/part/category_tabs.html:6 #: templates/InvenTree/settings/tabs.html:22 templates/navbar.html:19 -#: templates/stats.html:35 templates/stats.html:44 users/models.py:28 +#: templates/stats.html:35 templates/stats.html:44 users/models.py:29 msgid "Parts" msgstr "Teile" @@ -2114,7 +2127,7 @@ msgstr "Firma gelöscht" msgid "Edit Supplier Part" msgstr "Zuliefererteil bearbeiten" -#: company/views.py:295 templates/js/stock.js:882 +#: company/views.py:295 templates/js/stock.js:996 msgid "Create new Supplier Part" msgstr "Neues Zuliefererteil anlegen" @@ -2136,43 +2149,65 @@ msgstr "Preisstaffel bearbeiten" msgid "Delete Price Break" msgstr "Preisstaffel löschen" -#: label/models.py:55 +#: label/api.py:171 +#, fuzzy +#| msgid "Move Stock Items" +msgid "Must provide valid StockItem(s)" +msgstr "Lagerobjekte bewegen" + +#: label/api.py:185 label/api.py:337 +msgid "Error during label rendering" +msgstr "" + +#: label/api.py:324 +msgid "Must provide valid StockLocation(s)" +msgstr "" + +#: label/models.py:69 #, fuzzy #| msgid "Part name" msgid "Label name" msgstr "Name des Teils" -#: label/models.py:58 +#: label/models.py:76 #, fuzzy #| msgid "Part description" msgid "Label description" msgstr "Beschreibung des Teils" -#: label/models.py:63 +#: label/models.py:83 stock/forms.py:198 +msgid "Label" +msgstr "" + +#: label/models.py:84 msgid "Label template file" msgstr "" -#: label/models.py:69 -msgid "Query filters (comma-separated list of key=value pairs" -msgstr "" - -#: label/models.py:75 -msgid "Label template is enabled" -msgstr "" - -#: label/models.py:76 report/models.py:162 +#: label/models.py:90 report/models.py:162 msgid "Enabled" msgstr "" -#: order/forms.py:25 order/templates/order/order_base.html:39 +#: label/models.py:91 +msgid "Label template is enabled" +msgstr "" + +#: label/models.py:137 label/models.py:190 +msgid "Query filters (comma-separated list of key=value pairs" +msgstr "" + +#: label/models.py:138 label/models.py:191 +msgid "Filters" +msgstr "" + +#: order/forms.py:25 order/templates/order/order_base.html:44 msgid "Place order" msgstr "Bestellung aufgeben" -#: order/forms.py:36 order/templates/order/order_base.html:46 +#: order/forms.py:36 order/templates/order/order_base.html:51 msgid "Mark order as complete" msgstr "Bestellung als vollständig markieren" -#: order/forms.py:47 order/forms.py:58 order/templates/order/order_base.html:51 +#: order/forms.py:47 order/forms.py:58 order/templates/order/order_base.html:56 #: order/templates/order/sales_order_base.html:56 msgid "Cancel order" msgstr "Bestellung stornieren" @@ -2185,19 +2220,23 @@ msgstr "Bestellung versenden" msgid "Receive parts to this location" msgstr "Teile in diesen Ort empfangen" -#: order/forms.py:100 +#: order/forms.py:101 #, fuzzy #| msgid "Order reference" msgid "Purchase Order reference" msgstr "Bestell-Referenz" -#: order/forms.py:128 +#: order/forms.py:107 +msgid "Target date for order delivery. Order will be overdue after this date." +msgstr "" + +#: order/forms.py:134 #, fuzzy #| msgid "Cancel sales order" msgid "Enter sales order number" msgstr "Auftrag stornieren" -#: order/forms.py:134 order/models.py:405 +#: order/forms.py:140 order/models.py:437 msgid "" "Target date for order completion. Order will be overdue after this date." msgstr "" @@ -2218,115 +2257,138 @@ msgstr "Link auf externe Seite" msgid "Order notes" msgstr "Bestell-Notizen" -#: order/models.py:169 order/models.py:398 +#: order/models.py:171 order/models.py:430 #, fuzzy #| msgid "Purchase Order Details" msgid "Purchase order status" msgstr "Bestelldetails" -#: order/models.py:177 +#: order/models.py:179 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:180 +#: order/models.py:182 msgid "Supplier order reference code" msgstr "Bestellreferenz" -#: order/models.py:189 +#: order/models.py:193 +#, fuzzy +#| msgid "Issue Order" +msgid "Issue Date" +msgstr "Bestellung aufgeben" + +#: order/models.py:194 msgid "Date order was issued" msgstr "" -#: order/models.py:191 +#: order/models.py:199 +#, fuzzy +#| msgid "Shipment Date" +msgid "Target Delivery Date" +msgstr "Versanddatum" + +#: order/models.py:200 +msgid "" +"Expected date for order delivery. Order will be overdue after this date." +msgstr "" + +#: order/models.py:205 +#, fuzzy +#| msgid "Creation Date" +msgid "Completion Date" +msgstr "Erstelldatum" + +#: order/models.py:206 #, fuzzy #| msgid "Mark order as complete" msgid "Date order was completed" msgstr "Bestellung als vollständig markieren" -#: order/models.py:214 order/models.py:296 part/views.py:1504 -#: stock/models.py:251 stock/models.py:856 +#: order/models.py:230 order/models.py:328 part/views.py:1504 +#: stock/models.py:259 stock/models.py:871 msgid "Quantity must be greater than zero" msgstr "Anzahl muss größer Null sein" -#: order/models.py:219 +#: order/models.py:235 msgid "Part supplier must match PO supplier" msgstr "Teile-Zulieferer muss dem Zulieferer des Kaufvertrags entsprechen" -#: order/models.py:291 +#: order/models.py:323 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "Nur Teile aufgegebener Bestllungen können empfangen werden" -#: order/models.py:394 +#: order/models.py:426 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:400 +#: order/models.py:432 msgid "Customer order reference code" msgstr "Bestellreferenz" -#: order/models.py:462 +#: order/models.py:490 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "Bestellung kann nicht versendet werden weil sie nicht anhängig ist" -#: order/models.py:549 +#: order/models.py:577 msgid "Item quantity" msgstr "Anzahl" -#: order/models.py:551 +#: order/models.py:579 msgid "Line item reference" msgstr "Position - Referenz" -#: order/models.py:553 +#: order/models.py:581 msgid "Line item notes" msgstr "Position - Notizen" -#: order/models.py:579 order/templates/order/order_base.html:9 +#: order/models.py:607 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 -#: stock/templates/stock/item_base.html:276 templates/js/order.js:146 +#: stock/templates/stock/item_base.html:276 templates/js/order.js:145 msgid "Purchase Order" msgstr "Kaufvertrag" -#: order/models.py:592 +#: order/models.py:620 msgid "Supplier part" msgstr "Zulieferer-Teil" -#: order/models.py:595 +#: order/models.py:623 msgid "Number of items received" msgstr "Empfangene Objekt-Anzahl" -#: order/models.py:602 stock/models.py:473 +#: order/models.py:630 stock/models.py:488 #: stock/templates/stock/item_base.html:283 #, fuzzy #| msgid "Purchase Order" msgid "Purchase Price" msgstr "Kaufvertrag" -#: order/models.py:603 +#: order/models.py:631 #, fuzzy #| msgid "Purchase Order" msgid "Unit purchase price" msgstr "Kaufvertrag" -#: order/models.py:698 +#: order/models.py:726 msgid "Cannot allocate stock item to a line with a different part" msgstr "Kann Lagerobjekt keiner Zeile mit einem anderen Teil hinzufügen" -#: order/models.py:700 +#: order/models.py:728 msgid "Cannot allocate stock to a line without a part" msgstr "Kann Lagerobjekt keiner Zeile ohne Teil hinzufügen" -#: order/models.py:703 +#: order/models.py:731 msgid "Allocation quantity cannot exceed stock quantity" msgstr "zugewiesene Anzahl darf nicht die verfügbare Anzahl überschreiten" -#: order/models.py:713 +#: order/models.py:741 msgid "Quantity must be 1 for serialized stock item" msgstr "Anzahl muss 1 für Objekte mit Seriennummer sein" -#: order/models.py:729 +#: order/models.py:757 msgid "Select stock item to allocate" msgstr "Lagerobjekt für Zuordnung auswählen" -#: order/models.py:732 +#: order/models.py:760 msgid "Enter stock allocation quantity" msgstr "Zuordnungsanzahl eingeben" @@ -2336,45 +2398,45 @@ msgstr "Zuordnungsanzahl eingeben" msgid "Are you sure you want to delete this attachment?" msgstr "Sind Sie sicher, dass Sie diesen Anhang löschen wollen?" -#: order/templates/order/order_base.html:35 +#: order/templates/order/order_base.html:40 #, fuzzy #| msgid "Edited company information" msgid "Edit order information" msgstr "Firmeninformation bearbeitet" -#: order/templates/order/order_base.html:43 +#: order/templates/order/order_base.html:48 #, fuzzy #| msgid "Receive line item" msgid "Receive items" msgstr "Position empfangen" -#: order/templates/order/order_base.html:56 +#: order/templates/order/order_base.html:61 msgid "Export order to file" msgstr "" -#: order/templates/order/order_base.html:64 +#: order/templates/order/order_base.html:69 msgid "Purchase Order Details" msgstr "Bestelldetails" -#: order/templates/order/order_base.html:69 +#: order/templates/order/order_base.html:74 #: order/templates/order/sales_order_base.html:74 msgid "Order Reference" msgstr "Bestellreferenz" -#: order/templates/order/order_base.html:74 +#: order/templates/order/order_base.html:79 #: order/templates/order/sales_order_base.html:79 msgid "Order Status" msgstr "Bestellstatus" -#: order/templates/order/order_base.html:85 templates/js/order.js:169 +#: order/templates/order/order_base.html:95 templates/js/order.js:175 msgid "Supplier Reference" msgstr "Zuliefererreferenz" -#: order/templates/order/order_base.html:104 +#: order/templates/order/order_base.html:114 msgid "Issued" msgstr "Aufgegeben" -#: order/templates/order/order_base.html:111 +#: order/templates/order/order_base.html:128 #: order/templates/order/purchase_order_detail.html:193 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:128 @@ -2427,7 +2489,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "Bestellungen auswählen oder anlegen." #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:193 templates/js/order.js:291 +#: templates/js/order.js:203 templates/js/order.js:302 msgid "Items" msgstr "Positionen" @@ -2469,7 +2531,7 @@ msgstr "Bestellpositionen" #: order/templates/order/purchase_order_detail.html:39 #: order/templates/order/purchase_order_detail.html:119 #: part/templates/part/category.html:173 part/templates/part/category.html:215 -#: templates/js/stock.js:627 templates/js/stock.js:887 +#: templates/js/stock.js:642 templates/js/stock.js:1001 msgid "New Location" msgstr "Neuer Standort" @@ -2542,7 +2604,7 @@ msgstr "Packliste" msgid "Sales Order Details" msgstr "Auftragsdetails" -#: order/templates/order/sales_order_base.html:95 templates/js/order.js:257 +#: order/templates/order/sales_order_base.html:95 templates/js/order.js:268 msgid "Customer Reference" msgstr "Kundenreferenz" @@ -2558,7 +2620,7 @@ msgid "Sales Order Items" msgstr "Auftragspositionen" #: order/templates/order/sales_order_detail.html:72 -#: order/templates/order/sales_order_detail.html:154 stock/models.py:385 +#: order/templates/order/sales_order_detail.html:154 stock/models.py:400 #: stock/templates/stock/item_base.html:208 templates/js/build.js:418 msgid "Serial Number" msgstr "Seriennummer" @@ -2673,18 +2735,14 @@ msgstr "Bestellung stornieren" msgid "Confirm order cancellation" msgstr "Bestellstornierung bestätigen" -#: order/views.py:435 -msgid "Order cannot be cancelled as either pending or placed" +#: order/views.py:435 order/views.py:462 +msgid "Order cannot be cancelled" msgstr "" #: order/views.py:449 msgid "Cancel sales order" msgstr "Auftrag stornieren" -#: order/views.py:462 -msgid "Order cannot be cancelled" -msgstr "" - #: order/views.py:476 msgid "Issue Order" msgstr "Bestellung aufgeben" @@ -2807,103 +2865,103 @@ msgstr "Fehler beim Lesen der Stückliste (ungültige Daten)" msgid "Error reading BOM file (incorrect row size)" msgstr "Fehler beim Lesen der Stückliste (ungültige Zeilengröße)" -#: part/forms.py:61 stock/forms.py:261 +#: part/forms.py:71 stock/forms.py:261 msgid "File Format" msgstr "Dateiformat" -#: part/forms.py:61 stock/forms.py:261 +#: part/forms.py:71 stock/forms.py:261 msgid "Select output file format" msgstr "Ausgabe-Dateiformat auswählen" -#: part/forms.py:63 +#: part/forms.py:73 msgid "Cascading" msgstr "Kaskadierend" -#: part/forms.py:63 +#: part/forms.py:73 msgid "Download cascading / multi-level BOM" msgstr "Kaskadierende Stückliste herunterladen" -#: part/forms.py:65 +#: part/forms.py:75 msgid "Levels" msgstr "" -#: part/forms.py:65 +#: part/forms.py:75 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "" -#: part/forms.py:67 +#: part/forms.py:77 #, fuzzy #| msgid "New Parameter" msgid "Include Parameter Data" msgstr "Neuer Parameter" -#: part/forms.py:67 +#: part/forms.py:77 msgid "Include part parameters data in exported BOM" msgstr "" -#: part/forms.py:69 +#: part/forms.py:79 #, fuzzy #| msgid "Include stock in sublocations" msgid "Include Stock Data" msgstr "Bestand in Unterlagerorten einschließen" -#: part/forms.py:69 +#: part/forms.py:79 #, fuzzy #| msgid "Include parts in subcategories" msgid "Include part stock data in exported BOM" msgstr "Teile in Unterkategorien einschließen" -#: part/forms.py:71 +#: part/forms.py:81 #, fuzzy #| msgid "New Supplier Part" msgid "Include Supplier Data" msgstr "Neues Zulieferer-Teil" -#: part/forms.py:71 +#: part/forms.py:81 msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:92 part/models.py:1781 +#: part/forms.py:102 part/models.py:1781 msgid "Parent Part" msgstr "Ausgangsteil" -#: part/forms.py:93 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:103 part/templates/part/bom_duplicate.html:7 #, fuzzy #| msgid "Select parent part" msgid "Select parent part to copy BOM from" msgstr "Ausgangsteil auswählen" -#: part/forms.py:99 +#: part/forms.py:109 #, fuzzy #| msgid "Select from existing images" msgid "Clear existing BOM items" msgstr "Aus vorhandenen Bildern auswählen" -#: part/forms.py:104 +#: part/forms.py:114 #, fuzzy #| msgid "Confim BOM item deletion" msgid "Confirm BOM duplication" msgstr "Löschung von BOM-Position bestätigen" -#: part/forms.py:122 +#: part/forms.py:132 msgid "Confirm that the BOM is correct" msgstr "Bestätigen, dass die Stückliste korrekt ist" -#: part/forms.py:134 +#: part/forms.py:144 msgid "Select BOM file to upload" msgstr "Stücklisten-Datei zum Upload auswählen" -#: part/forms.py:153 +#: part/forms.py:163 #, fuzzy #| msgid "Delete Parts" msgid "Related Part" msgstr "Teile löschen" -#: part/forms.py:172 +#: part/forms.py:182 msgid "Select part category" msgstr "Teilekategorie wählen" -#: part/forms.py:189 +#: part/forms.py:199 #, fuzzy #| msgid "Perform 'deep copy' which will duplicate all BOM data for this part" msgid "Duplicate all BOM data for this part" @@ -2911,49 +2969,49 @@ msgstr "" "Tiefe Kopie ausführen. Dies wird alle Daten der Stückliste für dieses Teil " "duplizieren" -#: part/forms.py:190 +#: part/forms.py:200 msgid "Copy BOM" msgstr "" -#: part/forms.py:195 +#: part/forms.py:205 msgid "Duplicate all parameter data for this part" msgstr "" -#: part/forms.py:196 +#: part/forms.py:206 #, fuzzy #| msgid "Parameters" msgid "Copy Parameters" msgstr "Parameter" -#: part/forms.py:201 +#: part/forms.py:211 msgid "Confirm part creation" msgstr "Erstellen des Teils bestätigen" -#: part/forms.py:206 +#: part/forms.py:216 #, fuzzy #| msgid "No part parameter templates found" msgid "Include category parameter templates" msgstr "Keine Teilparametervorlagen gefunden" -#: part/forms.py:211 +#: part/forms.py:221 #, fuzzy #| msgid "No part parameter templates found" msgid "Include parent categories parameter templates" msgstr "Keine Teilparametervorlagen gefunden" -#: part/forms.py:291 +#: part/forms.py:301 #, fuzzy #| msgid "Parameter template name must be unique" msgid "Add parameter template to same level categories" msgstr "Vorlagen-Name des Parameters muss eindeutig sein" -#: part/forms.py:295 +#: part/forms.py:305 #, fuzzy #| msgid "Parameter template name must be unique" msgid "Add parameter template to all categories" msgstr "Vorlagen-Name des Parameters muss eindeutig sein" -#: part/forms.py:339 +#: part/forms.py:349 msgid "Input quantity for price calculation" msgstr "Eintragsmenge zur Preisberechnung" @@ -2972,6 +3030,7 @@ msgstr "Teilkategorie" #: part/models.py:78 part/templates/part/category.html:18 #: part/templates/part/category.html:89 templates/stats.html:39 +#: users/models.py:28 msgid "Part Categories" msgstr "Teile-Kategorien" @@ -3127,7 +3186,7 @@ msgstr "Kann dieses Teil an Kunden verkauft werden?" #: part/models.py:821 part/templates/part/detail.html:222 #: templates/js/table_filters.js:19 templates/js/table_filters.js:55 -#: templates/js/table_filters.js:196 templates/js/table_filters.js:261 +#: templates/js/table_filters.js:196 templates/js/table_filters.js:265 msgid "Active" msgstr "Aktiv" @@ -3163,7 +3222,7 @@ msgstr "" "Ein Teil mit dieser Seriennummer existiert bereits für die Teilevorlage " "{part}" -#: part/models.py:1690 templates/js/part.js:567 templates/js/stock.js:93 +#: part/models.py:1690 templates/js/part.js:567 templates/js/stock.js:103 #, fuzzy #| msgid "Instance Name" msgid "Test Name" @@ -3278,7 +3337,7 @@ msgid "BOM line checksum" msgstr "Prüfsumme der Stückliste" #: part/models.py:1963 part/views.py:1510 part/views.py:1562 -#: stock/models.py:241 +#: stock/models.py:249 #, fuzzy #| msgid "Overage must be an integer value or a percentage" msgid "Quantity must be integer value for trackable parts" @@ -3296,13 +3355,13 @@ msgstr "Zuliefererbeschreibung des Teils" msgid "BOM Item" msgstr "Neue Stücklistenposition" -#: part/models.py:2092 +#: part/models.py:2098 #, fuzzy #| msgid "Select a part" msgid "Select Related Part" msgstr "Teil auswählen" -#: part/models.py:2124 +#: part/models.py:2130 msgid "" "Error creating relationship: check that the part is not related to itself " "and that the relationship is unique" @@ -3325,7 +3384,7 @@ msgstr "Bestellung" #: stock/templates/stock/item_base.html:72 #: stock/templates/stock/item_base.html:291 #: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:751 -#: templates/js/stock.js:720 templates/js/stock.js:980 +#: templates/js/stock.js:834 templates/js/stock.js:1094 msgid "Stock Item" msgstr "Lagerobjekt" @@ -3588,7 +3647,7 @@ msgstr "Teilkategorie auswählen" msgid "Export Data" msgstr "Exportieren" -#: part/templates/part/category.html:174 templates/js/stock.js:628 +#: part/templates/part/category.html:174 templates/js/stock.js:643 #, fuzzy #| msgid "Create New Location" msgid "Create new location" @@ -3612,7 +3671,7 @@ msgstr "Teilkategorie anlegen" msgid "Create new Part Category" msgstr "Teilkategorie anlegen" -#: part/templates/part/category.html:216 stock/views.py:1363 +#: part/templates/part/category.html:216 stock/views.py:1276 msgid "Create new Stock Location" msgstr "Neuen Lager-Standort erstellen" @@ -3660,7 +3719,7 @@ msgstr "Keine Seriennummern gefunden" msgid "Stock Expiry Time" msgstr "Lagerbestandsexportoptionen" -#: part/templates/part/detail.html:121 templates/js/order.js:276 +#: part/templates/part/detail.html:121 templates/js/order.js:287 msgid "Creation Date" msgstr "Erstelldatum" @@ -3754,17 +3813,17 @@ msgstr "Parameter hinzufügen" #: part/templates/part/params.html:15 #: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:41 +#: templates/InvenTree/settings/part.html:42 msgid "New Parameter" msgstr "Neuer Parameter" -#: part/templates/part/params.html:25 stock/models.py:1499 -#: templates/InvenTree/settings/header.html:8 templates/js/stock.js:113 +#: part/templates/part/params.html:25 stock/models.py:1531 +#: templates/InvenTree/settings/header.html:8 templates/js/stock.js:123 msgid "Value" msgstr "Wert" #: part/templates/part/params.html:41 part/templates/part/related.html:41 -#: part/templates/part/supplier.html:19 users/models.py:152 +#: part/templates/part/supplier.html:19 users/models.py:159 msgid "Delete" msgstr "Löschen" @@ -3863,7 +3922,7 @@ msgstr "Zu Bauaufträgen zugeordnet" msgid "Allocated to Sales Orders" msgstr "Zu Aufträgen zugeordnet" -#: part/templates/part/part_base.html:160 +#: part/templates/part/part_base.html:160 templates/js/bom.js:262 msgid "Can Build" msgstr "Herstellbar?" @@ -4089,7 +4148,7 @@ msgstr "Teil kopiert" msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:594 templates/js/stock.js:876 +#: part/views.py:594 templates/js/stock.js:990 msgid "Create New Part" msgstr "Neues Teil anlegen" @@ -4299,10 +4358,6 @@ msgstr "Einstellungs-Beschreibung" msgid "Enter unique serial numbers (or leave blank)" msgstr "Eindeutige Seriennummern eingeben (oder leer lassen)" -#: stock/forms.py:198 -msgid "Label" -msgstr "" - #: stock/forms.py:199 stock/forms.py:255 #, fuzzy #| msgid "Select stock item to allocate" @@ -4363,7 +4418,7 @@ msgstr "Ziel-Lagerbestand" msgid "Add note (required)" msgstr "" -#: stock/forms.py:377 stock/views.py:935 stock/views.py:1133 +#: stock/forms.py:377 stock/views.py:848 stock/views.py:1046 msgid "Confirm stock adjustment" msgstr "Bestands-Anpassung bestätigen" @@ -4381,272 +4436,272 @@ msgstr "Standard-Lagerort" msgid "Set the destination as the default location for selected parts" msgstr "Setze das Ziel als Standard-Ziel für ausgewählte Teile" -#: stock/models.py:186 +#: stock/models.py:194 #, fuzzy #| msgid "Created new stock item" msgid "Created stock item" msgstr "Neues Lagerobjekt erstellt" -#: stock/models.py:222 +#: stock/models.py:230 #, fuzzy #| msgid "A stock item with this serial number already exists" msgid "StockItem with this serial number already exists" msgstr "Ein Teil mit dieser Seriennummer existiert bereits" -#: stock/models.py:258 +#: stock/models.py:266 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "Teile-Typ ('{pf}') muss {pe} sein" -#: stock/models.py:268 stock/models.py:277 +#: stock/models.py:276 stock/models.py:285 msgid "Quantity must be 1 for item with a serial number" msgstr "Anzahl muss für Objekte mit Seriennummer \"1\" sein" -#: stock/models.py:269 +#: stock/models.py:277 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" "Seriennummer kann nicht gesetzt werden wenn die Anzahl größer als \"1\" ist" -#: stock/models.py:291 +#: stock/models.py:299 msgid "Item cannot belong to itself" msgstr "Teil kann nicht zu sich selbst gehören" -#: stock/models.py:297 +#: stock/models.py:305 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:304 +#: stock/models.py:312 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:337 +#: stock/models.py:352 msgid "Parent Stock Item" msgstr "Eltern-Lagerobjekt" -#: stock/models.py:346 +#: stock/models.py:361 msgid "Base part" msgstr "Basis-Teil" -#: stock/models.py:355 +#: stock/models.py:370 msgid "Select a matching supplier part for this stock item" msgstr "Passenden Zulieferer für dieses Lagerobjekt auswählen" -#: stock/models.py:360 stock/templates/stock/stock_app_base.html:7 +#: stock/models.py:375 stock/templates/stock/stock_app_base.html:7 msgid "Stock Location" msgstr "Lagerort" -#: stock/models.py:363 +#: stock/models.py:378 msgid "Where is this stock item located?" msgstr "Wo wird dieses Teil normalerweise gelagert?" -#: stock/models.py:368 stock/templates/stock/item_base.html:229 +#: stock/models.py:383 stock/templates/stock/item_base.html:229 msgid "Installed In" msgstr "Installiert in" -#: stock/models.py:371 +#: stock/models.py:386 msgid "Is this item installed in another item?" msgstr "Ist dieses Teil in einem anderen verbaut?" -#: stock/models.py:387 +#: stock/models.py:402 msgid "Serial number for this item" msgstr "Seriennummer für dieses Teil" -#: stock/models.py:399 +#: stock/models.py:414 msgid "Batch code for this stock item" msgstr "Losnummer für dieses Lagerobjekt" -#: stock/models.py:403 +#: stock/models.py:418 msgid "Stock Quantity" msgstr "Bestand" -#: stock/models.py:412 +#: stock/models.py:427 msgid "Source Build" msgstr "Quellbau" -#: stock/models.py:414 +#: stock/models.py:429 msgid "Build for this stock item" msgstr "Bau für dieses Lagerobjekt" -#: stock/models.py:425 +#: stock/models.py:440 msgid "Source Purchase Order" msgstr "Quellbestellung" -#: stock/models.py:428 +#: stock/models.py:443 msgid "Purchase order for this stock item" msgstr "Bestellung für dieses Teil" -#: stock/models.py:434 +#: stock/models.py:449 msgid "Destination Sales Order" msgstr "Zielauftrag" -#: stock/models.py:440 stock/templates/stock/item_base.html:316 -#: templates/js/stock.js:597 +#: stock/models.py:455 stock/templates/stock/item_base.html:316 +#: templates/js/stock.js:612 #, fuzzy #| msgid "Export" msgid "Expiry Date" msgstr "Exportieren" -#: stock/models.py:441 +#: stock/models.py:456 msgid "" "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:454 +#: stock/models.py:469 msgid "Delete this Stock Item when stock is depleted" msgstr "Objekt löschen wenn Lagerbestand aufgebraucht" -#: stock/models.py:464 stock/templates/stock/item_notes.html:14 +#: stock/models.py:479 stock/templates/stock/item_notes.html:14 #: stock/templates/stock/item_notes.html:30 msgid "Stock Item Notes" msgstr "Lagerobjekt-Notizen" -#: stock/models.py:474 +#: stock/models.py:489 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:574 +#: stock/models.py:589 #, fuzzy #| msgid "Item assigned to customer?" msgid "Assigned to Customer" msgstr "Ist dieses Objekt einem Kunden zugeteilt?" -#: stock/models.py:576 +#: stock/models.py:591 #, fuzzy #| msgid "Item assigned to customer?" msgid "Manually assigned to customer" msgstr "Ist dieses Objekt einem Kunden zugeteilt?" -#: stock/models.py:589 +#: stock/models.py:604 #, fuzzy #| msgid "Item assigned to customer?" msgid "Returned from customer" msgstr "Ist dieses Objekt einem Kunden zugeteilt?" -#: stock/models.py:591 +#: stock/models.py:606 #, fuzzy #| msgid "Create new stock location" msgid "Returned to location" msgstr "Neuen Lagerort anlegen" -#: stock/models.py:716 +#: stock/models.py:731 #, fuzzy #| msgid "Installed in Stock Item" msgid "Installed into stock item" msgstr "In Lagerobjekt installiert" -#: stock/models.py:724 +#: stock/models.py:739 #, fuzzy #| msgid "Installed in Stock Item" msgid "Installed stock item" msgstr "In Lagerobjekt installiert" -#: stock/models.py:748 +#: stock/models.py:763 #, fuzzy #| msgid "Installed in Stock Item" msgid "Uninstalled stock item" msgstr "In Lagerobjekt installiert" -#: stock/models.py:767 +#: stock/models.py:782 #, fuzzy #| msgid "Include sublocations" msgid "Uninstalled into location" msgstr "Unterlagerorte einschließen" -#: stock/models.py:847 +#: stock/models.py:862 #, fuzzy #| msgid "Part is not a virtual part" msgid "Part is not set as trackable" msgstr "Teil ist nicht virtuell" -#: stock/models.py:853 +#: stock/models.py:868 msgid "Quantity must be integer" msgstr "Anzahl muss eine Ganzzahl sein" -#: stock/models.py:859 +#: stock/models.py:874 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "Anzahl darf nicht die verfügbare Anzahl überschreiten ({n})" -#: stock/models.py:862 +#: stock/models.py:877 msgid "Serial numbers must be a list of integers" msgstr "Seriennummern muss eine Liste von Ganzzahlen sein" -#: stock/models.py:865 +#: stock/models.py:880 msgid "Quantity does not match serial numbers" msgstr "Anzahl stimmt nicht mit den Seriennummern überein" -#: stock/models.py:897 +#: stock/models.py:912 msgid "Add serial number" msgstr "Seriennummer hinzufügen" -#: stock/models.py:900 +#: stock/models.py:915 #, python-brace-format msgid "Serialized {n} items" msgstr "{n} Teile serialisiert" -#: stock/models.py:1011 +#: stock/models.py:1026 msgid "StockItem cannot be moved as it is not in stock" msgstr "Lagerobjekt kann nicht bewegt werden, da kein Bestand vorhanden ist" -#: stock/models.py:1400 +#: stock/models.py:1432 msgid "Tracking entry title" msgstr "Name des Eintrags-Trackings" -#: stock/models.py:1402 +#: stock/models.py:1434 msgid "Entry notes" msgstr "Eintrags-Notizen" -#: stock/models.py:1404 +#: stock/models.py:1436 msgid "Link to external page for further information" msgstr "Link auf externe Seite für weitere Informationen" -#: stock/models.py:1464 +#: stock/models.py:1496 #, fuzzy #| msgid "Serial number for this item" msgid "Value must be provided for this test" msgstr "Seriennummer für dieses Teil" -#: stock/models.py:1470 +#: stock/models.py:1502 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1487 +#: stock/models.py:1519 msgid "Test" msgstr "" -#: stock/models.py:1488 +#: stock/models.py:1520 #, fuzzy #| msgid "Part name" msgid "Test name" msgstr "Name des Teils" -#: stock/models.py:1493 +#: stock/models.py:1525 #, fuzzy #| msgid "Search Results" msgid "Result" msgstr "Suchergebnisse" -#: stock/models.py:1494 templates/js/table_filters.js:172 +#: stock/models.py:1526 templates/js/table_filters.js:172 msgid "Test result" msgstr "" -#: stock/models.py:1500 +#: stock/models.py:1532 msgid "Test output value" msgstr "" -#: stock/models.py:1506 +#: stock/models.py:1538 #, fuzzy #| msgid "Attachments" msgid "Attachment" msgstr "Anhänge" -#: stock/models.py:1507 +#: stock/models.py:1539 #, fuzzy #| msgid "Delete attachment" msgid "Test result attachment" msgstr "Anhang löschen" -#: stock/models.py:1513 +#: stock/models.py:1545 #, fuzzy #| msgid "Edit notes" msgid "Test notes" @@ -4748,15 +4803,15 @@ msgid "Stock adjustment actions" msgstr "Bestands-Anpassung bestätigen" #: stock/templates/stock/item_base.html:141 -#: stock/templates/stock/location.html:41 templates/stock_table.html:23 +#: stock/templates/stock/location.html:41 templates/stock_table.html:24 msgid "Count stock" msgstr "Bestand zählen" -#: stock/templates/stock/item_base.html:142 templates/stock_table.html:21 +#: stock/templates/stock/item_base.html:142 templates/stock_table.html:22 msgid "Add stock" msgstr "Bestand hinzufügen" -#: stock/templates/stock/item_base.html:143 templates/stock_table.html:22 +#: stock/templates/stock/item_base.html:143 templates/stock_table.html:23 msgid "Remove stock" msgstr "Bestand entfernen" @@ -4784,7 +4839,7 @@ msgstr "Ist dieses Objekt einem Kunden zugeteilt?" msgid "Return to stock" msgstr "Bestand zählen" -#: stock/templates/stock/item_base.html:158 templates/js/stock.js:1017 +#: stock/templates/stock/item_base.html:158 templates/js/stock.js:1131 #, fuzzy #| msgid "Installed in Stock Item" msgid "Uninstall stock item" @@ -4948,53 +5003,54 @@ msgstr "Alle Lagerobjekte" msgid "Check-in Items" msgstr "Kind-Lagerobjekte" -#: stock/templates/stock/location.html:45 +#: stock/templates/stock/location.html:47 #, fuzzy #| msgid "Location Description" msgid "Location actions" msgstr "Standort-Beschreibung" -#: stock/templates/stock/location.html:47 +#: stock/templates/stock/location.html:49 #, fuzzy #| msgid "Edit stock location" msgid "Edit location" msgstr "Lagerort bearbeiten" -#: stock/templates/stock/location.html:49 +#: stock/templates/stock/location.html:51 #, fuzzy #| msgid "Delete stock location" msgid "Delete location" msgstr "Lagerort löschen" -#: stock/templates/stock/location.html:59 +#: stock/templates/stock/location.html:61 msgid "Location Details" msgstr "Standort-Details" -#: stock/templates/stock/location.html:64 +#: stock/templates/stock/location.html:66 msgid "Location Path" msgstr "Standord-Pfad" -#: stock/templates/stock/location.html:69 +#: stock/templates/stock/location.html:71 msgid "Location Description" msgstr "Standort-Beschreibung" -#: stock/templates/stock/location.html:74 +#: stock/templates/stock/location.html:76 msgid "Sublocations" msgstr "Sub-Standorte" -#: stock/templates/stock/location.html:79 -#: stock/templates/stock/location.html:94 +#: stock/templates/stock/location.html:81 +#: stock/templates/stock/location.html:96 #: templates/InvenTree/search_stock_items.html:6 templates/stats.html:48 -#: templates/stats.html:57 +#: templates/stats.html:57 users/models.py:31 msgid "Stock Items" msgstr "Lagerobjekte" -#: stock/templates/stock/location.html:84 +#: stock/templates/stock/location.html:86 msgid "Stock Details" msgstr "Objekt-Details" -#: stock/templates/stock/location.html:89 +#: stock/templates/stock/location.html:91 #: templates/InvenTree/search_stock_location.html:6 templates/stats.html:52 +#: users/models.py:30 msgid "Stock Locations" msgstr "Lagerobjekt-Standorte" @@ -5010,7 +5066,7 @@ msgstr "Sind Sie sicher, dass Sie diesen Anhang löschen wollen?" msgid "The following stock items will be uninstalled" msgstr "Die folgenden Objekte werden erstellt" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1335 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1248 #, fuzzy #| msgid "Count Stock Items" msgid "Convert Stock Item" @@ -5048,243 +5104,231 @@ msgstr "Kinder" msgid "Installed Items" msgstr "Installiert in" -#: stock/views.py:123 +#: stock/views.py:122 msgid "Edit Stock Location" msgstr "Lagerobjekt-Standort bearbeiten" -#: stock/views.py:148 +#: stock/views.py:147 msgid "Stock Location QR code" msgstr "QR-Code für diesen Standort" -#: stock/views.py:167 +#: stock/views.py:166 #, fuzzy #| msgid "Add Attachment" msgid "Add Stock Item Attachment" msgstr "Anhang hinzufügen" -#: stock/views.py:214 +#: stock/views.py:213 #, fuzzy #| msgid "Edit Stock Item" msgid "Edit Stock Item Attachment" msgstr "Lagerobjekt bearbeiten" -#: stock/views.py:231 +#: stock/views.py:230 #, fuzzy #| msgid "Delete Part Attachment" msgid "Delete Stock Item Attachment" msgstr "Teilanhang löschen" -#: stock/views.py:248 +#: stock/views.py:247 #, fuzzy #| msgid "Item assigned to customer?" msgid "Assign to Customer" msgstr "Ist dieses Objekt einem Kunden zugeteilt?" -#: stock/views.py:258 +#: stock/views.py:257 msgid "Customer must be specified" msgstr "" -#: stock/views.py:282 +#: stock/views.py:281 #, fuzzy #| msgid "Part Stock" msgid "Return to Stock" msgstr "Teilbestand" -#: stock/views.py:292 +#: stock/views.py:291 #, fuzzy #| msgid "Include sublocations" msgid "Specify a valid location" msgstr "Unterlagerorte einschließen" -#: stock/views.py:303 +#: stock/views.py:302 msgid "Stock item returned from customer" msgstr "" #: stock/views.py:313 #, fuzzy -#| msgid "Select valid part" -msgid "Select Label Template" -msgstr "Bitte ein gültiges Teil auswählen" - -#: stock/views.py:336 -#, fuzzy -#| msgid "Select valid part" -msgid "Select valid label" -msgstr "Bitte ein gültiges Teil auswählen" - -#: stock/views.py:400 -#, fuzzy #| msgid "Delete Template" msgid "Delete All Test Data" msgstr "Vorlage löschen" -#: stock/views.py:416 +#: stock/views.py:329 #, fuzzy #| msgid "Confirm Part Deletion" msgid "Confirm test data deletion" msgstr "Löschen des Teils bestätigen" -#: stock/views.py:436 +#: stock/views.py:349 msgid "Add Test Result" msgstr "" -#: stock/views.py:477 +#: stock/views.py:390 #, fuzzy #| msgid "Edit Template" msgid "Edit Test Result" msgstr "Vorlage bearbeiten" -#: stock/views.py:495 +#: stock/views.py:408 #, fuzzy #| msgid "Delete Template" msgid "Delete Test Result" msgstr "Vorlage löschen" -#: stock/views.py:507 +#: stock/views.py:420 #, fuzzy #| msgid "Delete Template" msgid "Select Test Report Template" msgstr "Vorlage löschen" -#: stock/views.py:537 +#: stock/views.py:450 #, fuzzy #| msgid "Select valid part" msgid "Select valid template" msgstr "Bitte ein gültiges Teil auswählen" -#: stock/views.py:590 +#: stock/views.py:503 msgid "Stock Export Options" msgstr "Lagerbestandsexportoptionen" -#: stock/views.py:712 +#: stock/views.py:625 msgid "Stock Item QR Code" msgstr "Lagerobjekt-QR-Code" -#: stock/views.py:738 +#: stock/views.py:651 #, fuzzy #| msgid "Installed in Stock Item" msgid "Install Stock Item" msgstr "In Lagerobjekt installiert" -#: stock/views.py:838 +#: stock/views.py:751 #, fuzzy #| msgid "Installed in Stock Item" msgid "Uninstall Stock Items" msgstr "In Lagerobjekt installiert" -#: stock/views.py:946 +#: stock/views.py:859 #, fuzzy #| msgid "Installed in Stock Item" msgid "Uninstalled stock items" msgstr "In Lagerobjekt installiert" -#: stock/views.py:971 +#: stock/views.py:884 msgid "Adjust Stock" msgstr "Lagerbestand anpassen" -#: stock/views.py:1081 +#: stock/views.py:994 msgid "Move Stock Items" msgstr "Lagerobjekte bewegen" -#: stock/views.py:1082 +#: stock/views.py:995 msgid "Count Stock Items" msgstr "Lagerobjekte zählen" -#: stock/views.py:1083 +#: stock/views.py:996 msgid "Remove From Stock" msgstr "Aus Lagerbestand entfernen" -#: stock/views.py:1084 +#: stock/views.py:997 msgid "Add Stock Items" msgstr "Lagerobjekte hinzufügen" -#: stock/views.py:1085 +#: stock/views.py:998 msgid "Delete Stock Items" msgstr "Lagerobjekte löschen" -#: stock/views.py:1113 +#: stock/views.py:1026 msgid "Must enter integer value" msgstr "Nur Ganzzahl eingeben" -#: stock/views.py:1118 +#: stock/views.py:1031 msgid "Quantity must be positive" msgstr "Anzahl muss positiv sein" -#: stock/views.py:1125 +#: stock/views.py:1038 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "Anzahl darf {x} nicht überschreiten" -#: stock/views.py:1204 +#: stock/views.py:1117 #, python-brace-format msgid "Added stock to {n} items" msgstr "Vorrat zu {n} Lagerobjekten hinzugefügt" -#: stock/views.py:1219 +#: stock/views.py:1132 #, python-brace-format msgid "Removed stock from {n} items" msgstr "Vorrat von {n} Lagerobjekten entfernt" -#: stock/views.py:1232 +#: stock/views.py:1145 #, python-brace-format msgid "Counted stock for {n} items" msgstr "Bestand für {n} Objekte erfasst" -#: stock/views.py:1260 +#: stock/views.py:1173 msgid "No items were moved" msgstr "Keine Lagerobjekte wurden bewegt" -#: stock/views.py:1263 +#: stock/views.py:1176 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "{n} Teile nach {dest} bewegt" -#: stock/views.py:1282 +#: stock/views.py:1195 #, python-brace-format msgid "Deleted {n} stock items" msgstr "{n} Teile im Lager gelöscht" -#: stock/views.py:1294 +#: stock/views.py:1207 msgid "Edit Stock Item" msgstr "Lagerobjekt bearbeiten" -#: stock/views.py:1385 +#: stock/views.py:1298 msgid "Serialize Stock" msgstr "Lagerbestand erfassen" -#: stock/views.py:1479 templates/js/build.js:210 +#: stock/views.py:1392 templates/js/build.js:210 msgid "Create new Stock Item" msgstr "Neues Lagerobjekt hinzufügen" -#: stock/views.py:1587 +#: stock/views.py:1500 #, fuzzy #| msgid "Count stock items" msgid "Duplicate Stock Item" msgstr "Lagerobjekte zählen" -#: stock/views.py:1664 +#: stock/views.py:1577 #, fuzzy #| msgid "Quantity must be greater than zero" msgid "Quantity cannot be negative" msgstr "Anzahl muss größer Null sein" -#: stock/views.py:1750 +#: stock/views.py:1663 msgid "Delete Stock Location" msgstr "Standort löschen" -#: stock/views.py:1764 +#: stock/views.py:1677 msgid "Delete Stock Item" msgstr "Lagerobjekt löschen" -#: stock/views.py:1776 +#: stock/views.py:1689 msgid "Delete Stock Tracking Entry" msgstr "Lagerbestands-Tracking-Eintrag löschen" -#: stock/views.py:1795 +#: stock/views.py:1708 msgid "Edit Stock Tracking Entry" msgstr "Lagerbestands-Tracking-Eintrag bearbeiten" -#: stock/views.py:1805 +#: stock/views.py:1718 msgid "Add Stock Tracking Entry" msgstr "Lagerbestands-Tracking-Eintrag hinzufügen" @@ -5346,6 +5390,12 @@ msgstr "Ausgangsteil" msgid "Outstanding Purchase Orders" msgstr "Bestellung bearbeiten" +#: templates/InvenTree/po_overdue.html:7 +#, fuzzy +#| msgid "Sales Orders" +msgid "Overdue Purchase Orders" +msgstr "Bestellungen" + #: templates/InvenTree/required_stock_build.html:7 #, fuzzy #| msgid "Complete Build" @@ -5368,13 +5418,13 @@ msgstr "Keine Ergebnisse gefunden" msgid "Enter a search query" msgstr "Auftrag stornieren" -#: templates/InvenTree/search.html:191 templates/js/stock.js:290 +#: templates/InvenTree/search.html:191 templates/js/stock.js:300 #, fuzzy #| msgid "Item assigned to customer?" msgid "Shipped to customer" msgstr "Ist dieses Objekt einem Kunden zugeteilt?" -#: templates/InvenTree/search.html:194 templates/js/stock.js:300 +#: templates/InvenTree/search.html:194 templates/js/stock.js:310 msgid "No stock location set" msgstr "Kein Lagerort gesetzt" @@ -5415,12 +5465,12 @@ msgid "Default Value" msgstr "Standard-Lagerort" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:78 +#: templates/InvenTree/settings/part.html:79 msgid "Edit Template" msgstr "Vorlage bearbeiten" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:79 +#: templates/InvenTree/settings/part.html:80 msgid "Delete Template" msgstr "Vorlage löschen" @@ -5448,13 +5498,13 @@ msgstr "Einstellungen" msgid "Part Options" msgstr "Quell-Standort" -#: templates/InvenTree/settings/part.html:37 +#: templates/InvenTree/settings/part.html:38 #, fuzzy #| msgid "Edit Part Parameter Template" msgid "Part Parameter Templates" msgstr "Teilparametervorlage bearbeiten" -#: templates/InvenTree/settings/part.html:58 +#: templates/InvenTree/settings/part.html:59 msgid "No part parameter templates found" msgstr "Keine Teilparametervorlagen gefunden" @@ -5676,7 +5726,7 @@ msgstr "Quell-Standort" msgid "Enter barcode data" msgstr "Keine Strichcodedaten bereitgestellt" -#: templates/js/barcode.js:42 +#: templates/js/barcode.js:42 templates/js/modals.js:856 msgid "Invalid server response" msgstr "" @@ -5775,41 +5825,41 @@ msgstr "Optionen" msgid "No pricing available" msgstr "Keine Preisinformation verfügbar" -#: templates/js/bom.js:272 templates/js/build.js:571 +#: templates/js/bom.js:304 templates/js/build.js:571 #, fuzzy #| msgid "Options" msgid "Actions" msgstr "Optionen" -#: templates/js/bom.js:280 +#: templates/js/bom.js:312 msgid "Validate BOM Item" msgstr "BOM-Position validieren" -#: templates/js/bom.js:282 +#: templates/js/bom.js:314 msgid "This line has been validated" msgstr "Diese Position wurde validiert" -#: templates/js/bom.js:284 +#: templates/js/bom.js:316 msgid "Edit BOM Item" msgstr "BOM-Position bearbeiten" -#: templates/js/bom.js:286 +#: templates/js/bom.js:318 msgid "Delete BOM Item" msgstr "BOM-Position löschen" -#: templates/js/bom.js:363 templates/js/build.js:305 +#: templates/js/bom.js:395 templates/js/build.js:305 msgid "No BOM items found" msgstr "Keine BOM-Einträge gefunden" -#: templates/js/bom.js:509 +#: templates/js/bom.js:541 msgid "INACTIVE" msgstr "INAKTIV" -#: templates/js/bom.js:523 +#: templates/js/bom.js:555 msgid "Uses" msgstr "" -#: templates/js/bom.js:534 +#: templates/js/bom.js:566 #, fuzzy #| msgid "No matching action found" msgid "No matching parts found" @@ -5861,7 +5911,7 @@ msgstr "Anzahl" msgid "Build stock" msgstr "Baue" -#: templates/js/build.js:582 templates/stock_table.html:25 +#: templates/js/build.js:582 templates/stock_table.html:26 msgid "Order stock" msgstr "Bestand bestellen" @@ -5911,25 +5961,181 @@ msgstr "Vorlagenteil" msgid "Assembled part" msgstr "Baugruppe" +#: templates/js/label.js:10 +#, fuzzy +#| msgid "Delete Stock Items" +msgid "Select Stock Items" +msgstr "Lagerobjekte löschen" + +#: templates/js/label.js:11 +#, fuzzy +#| msgid "StockItem has been allocated" +msgid "Stock item(s) must be selected before printing labels" +msgstr "Lagerobjekt wurde zugewiesen" + +#: templates/js/label.js:29 templates/js/label.js:79 +#, fuzzy +#| msgid "No parts found" +msgid "No Labels Found" +msgstr "Keine Teile gefunden" + +#: templates/js/label.js:30 +#, fuzzy +#| msgid "Remove selected BOM items" +msgid "No labels found which match selected stock item(s)" +msgstr "Ausgewählte Stücklistenpositionen entfernen" + +#: templates/js/label.js:61 +#, fuzzy +#| msgid "Delete Stock Location" +msgid "Select Stock Locations" +msgstr "Standort löschen" + +#: templates/js/label.js:62 +msgid "Stock location(s) must be selected before printing labels" +msgstr "" + +#: templates/js/label.js:80 +msgid "No labels found which match selected stock location(s)" +msgstr "" + +#: templates/js/label.js:141 +#, fuzzy +#| msgid "Select valid part" +msgid "Select Label" +msgstr "Bitte ein gültiges Teil auswählen" + +#: templates/js/label.js:156 +#, fuzzy +#| msgid "Select valid part" +msgid "Select Label Template" +msgstr "Bitte ein gültiges Teil auswählen" + +#: templates/js/modals.js:406 +#, fuzzy +#| msgid "Show pricing information" +msgid "Show Error Information" +msgstr "Kosteninformationen ansehen" + +#: templates/js/modals.js:473 +msgid "Accept" +msgstr "" + +#: templates/js/modals.js:474 +#, fuzzy +#| msgid "Cancelled" +msgid "Cancel" +msgstr "Storniert" + +#: templates/js/modals.js:538 +msgid "Loading Data" +msgstr "" + +#: templates/js/modals.js:549 templates/js/modals.js:807 +#: templates/modals.html:19 templates/modals.html:41 +#, fuzzy +#| msgid "Edit BOM" +msgid "Submit" +msgstr "Stückliste bearbeiten" + +#: templates/js/modals.js:550 templates/js/modals.js:808 +#: templates/modals.html:18 templates/modals.html:40 +msgid "Close" +msgstr "" + +#: templates/js/modals.js:759 +#, fuzzy +#| msgid "Unknown barcode format" +msgid "Invalid response from server" +msgstr "Unbekanntes Strichcode-Format" + +#: templates/js/modals.js:759 +msgid "Form data missing from server response" +msgstr "" + +#: templates/js/modals.js:772 +msgid "Error posting form data" +msgstr "" + +#: templates/js/modals.js:856 +msgid "JSON response missing form data" +msgstr "" + +#: templates/js/modals.js:866 +msgid "No Response" +msgstr "" + +#: templates/js/modals.js:867 +#, fuzzy +#| msgid "Unknown barcode format" +msgid "No response from the InvenTree server" +msgstr "Unbekanntes Strichcode-Format" + +#: templates/js/modals.js:871 +msgid "Error 400: Bad Request" +msgstr "" + +#: templates/js/modals.js:872 +msgid "Server returned error code 400" +msgstr "" + +#: templates/js/modals.js:876 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/modals.js:877 +#, fuzzy +#| msgid "Does this part have tracking for unique items?" +msgid "Authentication credentials not supplied" +msgstr "Hat dieses Teil Tracking für einzelne Objekte?" + +#: templates/js/modals.js:881 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/modals.js:882 +msgid "You do not have the required permissions to access this function" +msgstr "" + +#: templates/js/modals.js:886 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/modals.js:887 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/modals.js:891 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/modals.js:892 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/modals.js:895 +msgid "Error requesting form data" +msgstr "" + #: templates/js/order.js:135 msgid "No purchase orders found" msgstr "Keine Bestellungen gefunden" -#: templates/js/order.js:188 templates/js/stock.js:702 -msgid "Date" -msgstr "Datum" - -#: templates/js/order.js:218 -msgid "No sales orders found" -msgstr "Keine Aufträge gefunden" - -#: templates/js/order.js:241 +#: templates/js/order.js:159 templates/js/order.js:252 #, fuzzy #| msgid "Build order allocation is complete" msgid "Order is overdue" msgstr "Bau-Zuweisung ist vollständig" -#: templates/js/order.js:286 +#: templates/js/order.js:193 templates/js/stock.js:816 +msgid "Date" +msgstr "Datum" + +#: templates/js/order.js:229 +msgid "No sales orders found" +msgstr "Keine Aufträge gefunden" + +#: templates/js/order.js:297 msgid "Shipment Date" msgstr "Versanddatum" @@ -5963,8 +6169,8 @@ msgstr "Keine Teile gefunden" msgid "No parts found" msgstr "Keine Teile gefunden" -#: templates/js/part.js:343 templates/js/stock.js:463 -#: templates/js/stock.js:1049 +#: templates/js/part.js:343 templates/js/stock.js:473 +#: templates/js/stock.js:1163 msgid "Select" msgstr "Auswählen" @@ -5972,7 +6178,7 @@ msgstr "Auswählen" msgid "No category" msgstr "Keine Kategorie" -#: templates/js/part.js:429 templates/js/table_filters.js:274 +#: templates/js/part.js:429 templates/js/table_filters.js:278 msgid "Low stock" msgstr "Bestand niedrig" @@ -5994,13 +6200,13 @@ msgstr "" msgid "No test templates matching query" msgstr "Keine zur Anfrage passenden Lagerobjekte" -#: templates/js/part.js:604 templates/js/stock.js:64 +#: templates/js/part.js:604 templates/js/stock.js:74 #, fuzzy #| msgid "Edit Sales Order" msgid "Edit test result" msgstr "Auftrag bearbeiten" -#: templates/js/part.js:605 templates/js/stock.js:65 +#: templates/js/part.js:605 templates/js/stock.js:75 #, fuzzy #| msgid "Delete attachment" msgid "Delete test result" @@ -6010,149 +6216,179 @@ msgstr "Anhang löschen" msgid "This test is defined for a parent part" msgstr "" -#: templates/js/stock.js:27 +#: templates/js/stock.js:37 msgid "PASS" msgstr "" -#: templates/js/stock.js:29 +#: templates/js/stock.js:39 msgid "FAIL" msgstr "" -#: templates/js/stock.js:34 +#: templates/js/stock.js:44 msgid "NO RESULT" msgstr "" -#: templates/js/stock.js:60 +#: templates/js/stock.js:70 #, fuzzy #| msgid "Edit Sales Order" msgid "Add test result" msgstr "Auftrag bearbeiten" -#: templates/js/stock.js:79 +#: templates/js/stock.js:89 #, fuzzy #| msgid "No results found" msgid "No test results found" msgstr "Keine Ergebnisse gefunden" -#: templates/js/stock.js:121 +#: templates/js/stock.js:131 #, fuzzy #| msgid "Shipment Date" msgid "Test Date" msgstr "Versanddatum" -#: templates/js/stock.js:282 +#: templates/js/stock.js:292 msgid "In production" msgstr "" -#: templates/js/stock.js:286 +#: templates/js/stock.js:296 #, fuzzy #| msgid "Installed in Stock Item" msgid "Installed in Stock Item" msgstr "In Lagerobjekt installiert" -#: templates/js/stock.js:294 +#: templates/js/stock.js:304 #, fuzzy #| msgid "Item assigned to customer?" msgid "Assigned to Sales Order" msgstr "Ist dieses Objekt einem Kunden zugeteilt?" -#: templates/js/stock.js:314 +#: templates/js/stock.js:324 msgid "No stock items matching query" msgstr "Keine zur Anfrage passenden Lagerobjekte" -#: templates/js/stock.js:431 +#: templates/js/stock.js:441 #, fuzzy #| msgid "Include sublocations" msgid "Undefined location" msgstr "Unterlagerorte einschließen" -#: templates/js/stock.js:525 +#: templates/js/stock.js:535 #, fuzzy #| msgid "StockItem is lost" msgid "Stock item is in production" msgstr "Lagerobjekt verloren" -#: templates/js/stock.js:530 +#: templates/js/stock.js:540 #, fuzzy #| msgid "This stock item is allocated to Sales Order" msgid "Stock item assigned to sales order" msgstr "Dieses Lagerobjekt ist dem Auftrag zugewiesen" -#: templates/js/stock.js:533 +#: templates/js/stock.js:543 #, fuzzy #| msgid "StockItem has been allocated" msgid "Stock item assigned to customer" msgstr "Lagerobjekt wurde zugewiesen" -#: templates/js/stock.js:537 +#: templates/js/stock.js:547 #, fuzzy #| msgid "StockItem has been allocated" msgid "Stock item has expired" msgstr "Lagerobjekt wurde zugewiesen" -#: templates/js/stock.js:539 +#: templates/js/stock.js:549 #, fuzzy #| msgid "StockItem is lost" msgid "Stock item will expire soon" msgstr "Lagerobjekt verloren" -#: templates/js/stock.js:543 +#: templates/js/stock.js:553 #, fuzzy #| msgid "StockItem has been allocated" msgid "Stock item has been allocated" msgstr "Lagerobjekt wurde zugewiesen" -#: templates/js/stock.js:547 +#: templates/js/stock.js:557 #, fuzzy #| msgid "Is this item installed in another item?" msgid "Stock item has been installed in another item" msgstr "Ist dieses Teil in einem anderen verbaut?" -#: templates/js/stock.js:555 +#: templates/js/stock.js:565 #, fuzzy #| msgid "StockItem has been allocated" msgid "Stock item has been rejected" msgstr "Lagerobjekt wurde zugewiesen" -#: templates/js/stock.js:559 +#: templates/js/stock.js:569 #, fuzzy #| msgid "StockItem is lost" msgid "Stock item is lost" msgstr "Lagerobjekt verloren" -#: templates/js/stock.js:562 +#: templates/js/stock.js:572 #, fuzzy #| msgid "StockItem is lost" msgid "Stock item is destroyed" msgstr "Lagerobjekt verloren" -#: templates/js/stock.js:566 templates/js/table_filters.js:106 +#: templates/js/stock.js:576 templates/js/table_filters.js:106 #, fuzzy #| msgid "Delete" msgid "Depleted" msgstr "Löschen" -#: templates/js/stock.js:768 +#: templates/js/stock.js:605 +#, fuzzy +#| msgid "Last Stocktake" +msgid "Stocktake" +msgstr "Letzte Inventur" + +#: templates/js/stock.js:732 +#, fuzzy +#| msgid "Stock status" +msgid "Stock Status" +msgstr "Bestandsstatus" + +#: templates/js/stock.js:747 +#, fuzzy +#| msgid "Stock status" +msgid "Set Stock Status" +msgstr "Bestandsstatus" + +#: templates/js/stock.js:761 +#, fuzzy +#| msgid "Select part to build" +msgid "Select Status Code" +msgstr "Teil für den Bau wählen" + +#: templates/js/stock.js:762 +#, fuzzy +#| msgid "StockItem has been allocated" +msgid "Status code must be selected" +msgstr "Lagerobjekt wurde zugewiesen" + +#: templates/js/stock.js:882 msgid "No user information" msgstr "Keine Benutzerinformation" -#: templates/js/stock.js:888 +#: templates/js/stock.js:1002 msgid "Create New Location" msgstr "Neuen Standort anlegen" -#: templates/js/stock.js:987 +#: templates/js/stock.js:1101 #, fuzzy #| msgid "Serial Number" msgid "Serial" msgstr "Seriennummer" -#: templates/js/stock.js:1080 templates/js/table_filters.js:131 +#: templates/js/stock.js:1194 templates/js/table_filters.js:131 #, fuzzy #| msgid "Installed In" msgid "Installed" msgstr "Installiert in" -#: templates/js/stock.js:1105 +#: templates/js/stock.js:1219 #, fuzzy #| msgid "Installed In" msgid "Install item" @@ -6213,7 +6449,7 @@ msgstr "Seriennummer" msgid "Batch code" msgstr "Losnummer" -#: templates/js/table_filters.js:91 templates/js/table_filters.js:241 +#: templates/js/table_filters.js:91 templates/js/table_filters.js:245 msgid "Active parts" msgstr "Aktive Teile" @@ -6293,47 +6529,47 @@ msgstr "Bestandsstatus" msgid "Build status" msgstr "Bau-Status" -#: templates/js/table_filters.js:210 templates/js/table_filters.js:223 +#: templates/js/table_filters.js:210 templates/js/table_filters.js:227 msgid "Order status" msgstr "Bestellstatus" -#: templates/js/table_filters.js:215 templates/js/table_filters.js:228 +#: templates/js/table_filters.js:215 templates/js/table_filters.js:232 #, fuzzy #| msgid "Cascading" msgid "Outstanding" msgstr "Kaskadierend" -#: templates/js/table_filters.js:251 +#: templates/js/table_filters.js:255 msgid "Include subcategories" msgstr "Unterkategorien einschließen" -#: templates/js/table_filters.js:252 +#: templates/js/table_filters.js:256 msgid "Include parts in subcategories" msgstr "Teile in Unterkategorien einschließen" -#: templates/js/table_filters.js:256 +#: templates/js/table_filters.js:260 msgid "Has IPN" msgstr "" -#: templates/js/table_filters.js:257 +#: templates/js/table_filters.js:261 #, fuzzy #| msgid "Internal Part Number" msgid "Part has internal part number" msgstr "Interne Teilenummer" -#: templates/js/table_filters.js:262 +#: templates/js/table_filters.js:266 msgid "Show active parts" msgstr "Aktive Teile anzeigen" -#: templates/js/table_filters.js:270 +#: templates/js/table_filters.js:274 msgid "Stock available" msgstr "Bestand verfügbar" -#: templates/js/table_filters.js:286 +#: templates/js/table_filters.js:290 msgid "Starred" msgstr "Favorit" -#: templates/js/table_filters.js:298 +#: templates/js/table_filters.js:302 msgid "Purchasable" msgstr "Käuflich" @@ -6341,16 +6577,6 @@ msgstr "Käuflich" msgid "Form errors exist" msgstr "" -#: templates/modals.html:18 templates/modals.html:40 -msgid "Close" -msgstr "" - -#: templates/modals.html:19 templates/modals.html:41 -#, fuzzy -#| msgid "Edit BOM" -msgid "Submit" -msgstr "Stückliste bearbeiten" - #: templates/navbar.html:29 msgid "Buy" msgstr "Kaufen" @@ -6417,117 +6643,133 @@ msgstr "Bestellung aufgeben" msgid "Export Stock Information" msgstr "Lagerobjekt-Standort bearbeiten" -#: templates/stock_table.html:21 +#: templates/stock_table.html:20 +msgid "Print labels" +msgstr "" + +#: templates/stock_table.html:22 #, fuzzy #| msgid "Added stock to {n} items" msgid "Add to selected stock items" msgstr "Vorrat zu {n} Lagerobjekten hinzugefügt" -#: templates/stock_table.html:22 +#: templates/stock_table.html:23 #, fuzzy #| msgid "Remove selected BOM items" msgid "Remove from selected stock items" msgstr "Ausgewählte Stücklistenpositionen entfernen" -#: templates/stock_table.html:23 +#: templates/stock_table.html:24 #, fuzzy #| msgid "Delete Stock Item" msgid "Stocktake selected stock items" msgstr "Lagerobjekt löschen" -#: templates/stock_table.html:24 +#: templates/stock_table.html:25 #, fuzzy #| msgid "Delete Stock Item" msgid "Move selected stock items" msgstr "Lagerobjekt löschen" -#: templates/stock_table.html:24 +#: templates/stock_table.html:25 msgid "Move stock" msgstr "Bestand bewegen" -#: templates/stock_table.html:25 +#: templates/stock_table.html:26 #, fuzzy #| msgid "Remove selected BOM items" msgid "Order selected items" msgstr "Ausgewählte Stücklistenpositionen entfernen" -#: templates/stock_table.html:28 +#: templates/stock_table.html:27 +#, fuzzy +#| msgid "Settings" +msgid "Change status" +msgstr "Einstellungen" + +#: templates/stock_table.html:27 +#, fuzzy +#| msgid "Stock status" +msgid "Change stock status" +msgstr "Bestandsstatus" + +#: templates/stock_table.html:30 #, fuzzy #| msgid "Delete line item" msgid "Delete selected items" msgstr "Position löschen" -#: templates/stock_table.html:28 +#: templates/stock_table.html:30 msgid "Delete Stock" msgstr "Bestand löschen" -#: users/admin.py:62 +#: users/admin.py:64 #, fuzzy #| msgid "User" msgid "Users" msgstr "Benutzer" -#: users/admin.py:63 +#: users/admin.py:65 msgid "Select which users are assigned to this group" msgstr "" -#: users/admin.py:178 +#: users/admin.py:187 msgid "The following users are members of multiple groups:" msgstr "" -#: users/admin.py:201 +#: users/admin.py:210 #, fuzzy #| msgid "External Link" msgid "Personal info" msgstr "Externer Link" -#: users/admin.py:202 +#: users/admin.py:211 #, fuzzy #| msgid "Revision" msgid "Permissions" msgstr "Revision" -#: users/admin.py:205 +#: users/admin.py:214 #, fuzzy #| msgid "Import BOM data" msgid "Important dates" msgstr "Stückliste importieren" -#: users/models.py:135 +#: users/models.py:142 msgid "Permission set" msgstr "" -#: users/models.py:143 +#: users/models.py:150 msgid "Group" msgstr "" -#: users/models.py:146 +#: users/models.py:153 msgid "View" msgstr "" -#: users/models.py:146 +#: users/models.py:153 msgid "Permission to view items" msgstr "" -#: users/models.py:148 +#: users/models.py:155 #, fuzzy #| msgid "Address" msgid "Add" msgstr "Adresse" -#: users/models.py:148 +#: users/models.py:155 msgid "Permission to add items" msgstr "" -#: users/models.py:150 +#: users/models.py:157 msgid "Change" msgstr "" -#: users/models.py:150 +#: users/models.py:157 msgid "Permissions to edit items" msgstr "" -#: users/models.py:152 +#: users/models.py:159 #, fuzzy #| msgid "Remove selected BOM items" msgid "Permission to delete items" diff --git a/InvenTree/locale/en/LC_MESSAGES/django.po b/InvenTree/locale/en/LC_MESSAGES/django.po index 18f86b6972..7389af937b 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-01-07 23:48+1100\n" +"POT-Creation-Date: 2021-01-14 23:57+1100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -54,8 +54,8 @@ msgstr "" msgid "Select Category" msgstr "" -#: InvenTree/helpers.py:361 order/models.py:216 order/models.py:298 -#: stock/views.py:1660 +#: InvenTree/helpers.py:361 order/models.py:232 order/models.py:330 +#: stock/views.py:1573 msgid "Invalid quantity provided" msgstr "" @@ -95,11 +95,11 @@ msgstr "" msgid "File comment" msgstr "" -#: InvenTree/models.py:68 templates/js/stock.js:759 +#: InvenTree/models.py:68 templates/js/stock.js:873 msgid "User" msgstr "" -#: InvenTree/models.py:106 part/models.py:647 +#: InvenTree/models.py:106 label/models.py:68 part/models.py:647 #: part/templates/part/params.html:24 templates/js/part.js:129 msgid "Name" msgstr "" @@ -108,19 +108,19 @@ msgstr "" msgid "Description (optional)" msgstr "" -#: InvenTree/settings.py:422 +#: InvenTree/settings.py:439 msgid "English" msgstr "" -#: InvenTree/settings.py:423 +#: InvenTree/settings.py:440 msgid "German" msgstr "" -#: InvenTree/settings.py:424 +#: InvenTree/settings.py:441 msgid "French" msgstr "" -#: InvenTree/settings.py:425 +#: InvenTree/settings.py:442 msgid "Polish" msgstr "" @@ -302,7 +302,7 @@ msgstr "" #: build/forms.py:78 build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:83 -#: build/templates/build/detail.html:29 common/models.py:589 +#: build/templates/build/detail.html:29 common/models.py:596 #: company/forms.py:112 company/templates/company/supplier_part_pricing.html:75 #: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:179 @@ -315,8 +315,8 @@ msgstr "" #: stock/templates/stock/item_base.html:46 #: stock/templates/stock/item_base.html:214 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:338 -#: templates/js/bom.js:195 templates/js/build.js:420 templates/js/stock.js:750 -#: templates/js/stock.js:989 +#: templates/js/bom.js:195 templates/js/build.js:420 templates/js/stock.js:864 +#: templates/js/stock.js:1103 msgid "Quantity" msgstr "" @@ -381,7 +381,7 @@ msgstr "" #: build/models.py:62 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:11 #: order/templates/order/so_tabs.html:9 part/templates/part/tabs.html:31 -#: templates/InvenTree/settings/tabs.html:28 users/models.py:30 +#: templates/InvenTree/settings/tabs.html:28 users/models.py:32 msgid "Build Orders" msgstr "" @@ -397,15 +397,15 @@ msgstr "" #: build/models.py:116 build/templates/build/detail.html:19 #: company/models.py:359 company/templates/company/detail.html:23 #: company/templates/company/supplier_part_base.html:61 -#: company/templates/company/supplier_part_detail.html:27 +#: company/templates/company/supplier_part_detail.html:27 label/models.py:75 #: order/templates/order/purchase_order_detail.html:161 part/models.py:671 #: part/templates/part/detail.html:51 part/templates/part/set_category.html:14 #: templates/InvenTree/search.html:147 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:180 -#: templates/js/bom.js:517 templates/js/build.js:664 templates/js/company.js:56 -#: templates/js/order.js:175 templates/js/order.js:263 templates/js/part.js:188 +#: templates/js/bom.js:549 templates/js/build.js:664 templates/js/company.js:56 +#: templates/js/order.js:180 templates/js/order.js:274 templates/js/part.js:188 #: templates/js/part.js:271 templates/js/part.js:391 templates/js/part.js:572 -#: templates/js/stock.js:501 templates/js/stock.js:731 +#: templates/js/stock.js:511 templates/js/stock.js:845 msgid "Description" msgstr "" @@ -424,16 +424,16 @@ msgstr "" #: build/models.py:134 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:78 -#: build/templates/build/detail.html:24 order/models.py:623 +#: build/templates/build/detail.html:24 order/models.py:651 #: order/templates/order/order_wizard/select_parts.html:30 #: order/templates/order/purchase_order_detail.html:148 #: order/templates/order/receive_parts.html:19 part/models.py:316 #: part/templates/part/part_app_base.html:7 part/templates/part/related.html:26 #: part/templates/part/set_category.html:13 templates/InvenTree/search.html:133 -#: templates/js/barcode.js:336 templates/js/bom.js:153 templates/js/bom.js:502 +#: templates/js/barcode.js:336 templates/js/bom.js:153 templates/js/bom.js:534 #: templates/js/build.js:669 templates/js/company.js:138 -#: templates/js/part.js:252 templates/js/part.js:357 templates/js/stock.js:475 -#: templates/js/stock.js:1061 +#: templates/js/part.js:252 templates/js/part.js:357 templates/js/stock.js:485 +#: templates/js/stock.js:1175 msgid "Part" msgstr "" @@ -491,7 +491,7 @@ msgstr "" msgid "Build status code" msgstr "" -#: build/models.py:194 stock/models.py:397 +#: build/models.py:194 stock/models.py:412 msgid "Batch Code" msgstr "" @@ -499,7 +499,7 @@ msgstr "" msgid "Batch code for this build output" msgstr "" -#: build/models.py:205 order/models.py:404 +#: build/models.py:205 order/models.py:436 msgid "Target completion date" msgstr "" @@ -507,11 +507,11 @@ msgstr "" #: company/templates/company/supplier_part_base.html:68 #: company/templates/company/supplier_part_detail.html:24 #: part/templates/part/detail.html:80 part/templates/part/part_base.html:102 -#: stock/models.py:391 stock/templates/stock/item_base.html:297 +#: stock/models.py:406 stock/templates/stock/item_base.html:297 msgid "External Link" msgstr "" -#: build/models.py:220 part/models.py:705 stock/models.py:393 +#: build/models.py:220 part/models.py:705 stock/models.py:408 msgid "Link to external URL" msgstr "" @@ -520,9 +520,9 @@ msgstr "" #: order/templates/order/purchase_order_detail.html:213 #: order/templates/order/so_tabs.html:23 part/models.py:831 #: part/templates/part/tabs.html:73 stock/forms.py:313 stock/forms.py:345 -#: stock/forms.py:373 stock/models.py:463 stock/models.py:1512 +#: stock/forms.py:373 stock/models.py:478 stock/models.py:1544 #: stock/templates/stock/tabs.html:26 templates/js/barcode.js:391 -#: templates/js/bom.js:263 templates/js/stock.js:117 templates/js/stock.js:603 +#: templates/js/bom.js:295 templates/js/stock.js:127 templates/js/stock.js:618 msgid "Notes" msgstr "" @@ -564,11 +564,11 @@ msgstr "" msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:971 order/models.py:707 +#: build/models.py:971 order/models.py:735 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:975 order/models.py:710 +#: build/models.py:975 order/models.py:738 msgid "Allocation quantity must be greater than zero" msgstr "" @@ -657,7 +657,7 @@ msgstr "" #: stock/templates/stock/item_base.html:244 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:183 templates/js/barcode.js:337 -#: templates/js/build.js:434 templates/js/stock.js:587 +#: templates/js/build.js:434 templates/js/stock.js:597 msgid "Location" msgstr "" @@ -689,9 +689,12 @@ msgstr "" #: build/templates/build/build_base.html:43 #: build/templates/build/build_base.html:100 +#: order/templates/order/order_base.html:32 +#: order/templates/order/order_base.html:83 #: order/templates/order/sales_order_base.html:41 #: order/templates/order/sales_order_base.html:83 -#: templates/js/table_filters.js:200 templates/js/table_filters.js:232 +#: templates/js/table_filters.js:200 templates/js/table_filters.js:219 +#: templates/js/table_filters.js:236 msgid "Overdue" msgstr "" @@ -720,15 +723,16 @@ msgstr "" #: order/templates/order/receive_parts.html:24 #: stock/templates/stock/item_base.html:343 templates/InvenTree/search.html:175 #: templates/js/barcode.js:42 templates/js/build.js:697 -#: templates/js/order.js:180 templates/js/order.js:268 -#: templates/js/stock.js:574 templates/js/stock.js:997 +#: templates/js/order.js:185 templates/js/order.js:279 +#: templates/js/stock.js:584 templates/js/stock.js:1111 msgid "Status" msgstr "" #: build/templates/build/build_base.html:96 #: build/templates/build/detail.html:100 +#: order/templates/order/order_base.html:121 #: order/templates/order/sales_order_base.html:114 templates/js/build.js:710 -#: templates/js/order.js:281 +#: templates/js/order.js:198 templates/js/order.js:292 msgid "Target Date" msgstr "" @@ -742,13 +746,13 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:120 -#: build/templates/build/detail.html:82 order/models.py:621 +#: build/templates/build/detail.html:82 order/models.py:649 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:33 #: order/templates/order/sales_order_notes.html:10 #: order/templates/order/sales_order_ship.html:25 #: part/templates/part/allocation.html:27 -#: stock/templates/stock/item_base.html:238 templates/js/order.js:229 +#: stock/templates/stock/item_base.html:238 templates/js/order.js:240 msgid "Sales Order" msgstr "" @@ -849,14 +853,14 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:68 -#: stock/templates/stock/item_base.html:262 templates/js/stock.js:582 -#: templates/js/stock.js:1004 templates/js/table_filters.js:80 +#: stock/templates/stock/item_base.html:262 templates/js/stock.js:592 +#: templates/js/stock.js:1118 templates/js/table_filters.js:80 #: templates/js/table_filters.js:161 msgid "Batch" msgstr "" #: build/templates/build/detail.html:95 -#: order/templates/order/order_base.html:98 +#: order/templates/order/order_base.html:108 #: order/templates/order/sales_order_base.html:108 templates/js/build.js:705 msgid "Created" msgstr "" @@ -949,7 +953,7 @@ msgstr "" msgid "Create Build Output" msgstr "" -#: build/views.py:207 stock/models.py:872 stock/views.py:1681 +#: build/views.py:207 stock/models.py:887 stock/views.py:1594 msgid "Serial numbers already exist" msgstr "" @@ -965,7 +969,7 @@ msgstr "" msgid "Confirm unallocation of build stock" msgstr "" -#: build/views.py:303 build/views.py:388 stock/views.py:417 +#: build/views.py:303 build/views.py:388 stock/views.py:330 msgid "Check the confirmation box" msgstr "" @@ -1059,7 +1063,7 @@ msgid "Add Build Order Attachment" msgstr "" #: build/views.py:1060 order/views.py:113 order/views.py:166 part/views.py:170 -#: stock/views.py:180 +#: stock/views.py:179 msgid "Added attachment" msgstr "" @@ -1075,7 +1079,7 @@ msgstr "" msgid "Delete Attachment" msgstr "" -#: build/views.py:1123 order/views.py:242 order/views.py:257 stock/views.py:238 +#: build/views.py:1123 order/views.py:242 order/views.py:257 stock/views.py:237 msgid "Deleted attachment" msgstr "" @@ -1152,7 +1156,7 @@ msgid "Copy category parameter templates when creating a part" msgstr "" #: common/models.py:115 part/templates/part/detail.html:155 stock/forms.py:255 -#: templates/js/table_filters.js:23 templates/js/table_filters.js:266 +#: templates/js/table_filters.js:23 templates/js/table_filters.js:270 msgid "Template" msgstr "" @@ -1161,7 +1165,7 @@ msgid "Parts are templates by default" msgstr "" #: common/models.py:122 part/models.py:794 part/templates/part/detail.html:165 -#: templates/js/table_filters.js:278 +#: templates/js/table_filters.js:282 msgid "Assembly" msgstr "" @@ -1170,7 +1174,7 @@ msgid "Parts can be assembled from other components by default" msgstr "" #: common/models.py:129 part/models.py:800 part/templates/part/detail.html:175 -#: templates/js/table_filters.js:282 +#: templates/js/table_filters.js:286 msgid "Component" msgstr "" @@ -1187,7 +1191,7 @@ msgid "Parts are purchaseable by default" msgstr "" #: common/models.py:143 part/models.py:816 part/templates/part/detail.html:205 -#: templates/js/table_filters.js:290 +#: templates/js/table_filters.js:294 msgid "Salable" msgstr "" @@ -1196,7 +1200,7 @@ msgid "Parts are salable by default" msgstr "" #: common/models.py:150 part/models.py:806 part/templates/part/detail.html:185 -#: templates/js/table_filters.js:31 templates/js/table_filters.js:294 +#: templates/js/table_filters.js:31 templates/js/table_filters.js:298 msgid "Trackable" msgstr "" @@ -1214,107 +1218,115 @@ msgid "Parts are virtual by default" msgstr "" #: common/models.py:164 -msgid "Stock Expiry" +msgid "Show Quantity in Forms" msgstr "" #: common/models.py:165 -msgid "Enable stock expiry functionality" +msgid "Display available part quantity in some forms" msgstr "" #: common/models.py:171 -msgid "Sell Expired Stock" +msgid "Stock Expiry" msgstr "" #: common/models.py:172 -msgid "Allow sale of expired stock" +msgid "Enable stock expiry functionality" msgstr "" #: common/models.py:178 -msgid "Stock Stale Time" +msgid "Sell Expired Stock" msgstr "" #: common/models.py:179 -msgid "Number of days stock items are considered stale before expiring" +msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:181 part/templates/part/detail.html:116 -msgid "days" +#: common/models.py:185 +msgid "Stock Stale Time" msgstr "" #: common/models.py:186 -msgid "Build Expired Stock" +msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:187 -msgid "Allow building with expired stock" +#: common/models.py:188 part/templates/part/detail.html:116 +msgid "days" msgstr "" #: common/models.py:193 -msgid "Build Order Reference Prefix" +msgid "Build Expired Stock" msgstr "" #: common/models.py:194 -msgid "Prefix value for build order reference" -msgstr "" - -#: common/models.py:199 -msgid "Build Order Reference Regex" +msgid "Allow building with expired stock" msgstr "" #: common/models.py:200 +msgid "Build Order Reference Prefix" +msgstr "" + +#: common/models.py:201 +msgid "Prefix value for build order reference" +msgstr "" + +#: common/models.py:206 +msgid "Build Order Reference Regex" +msgstr "" + +#: common/models.py:207 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:204 +#: common/models.py:211 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:205 +#: common/models.py:212 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:210 +#: common/models.py:217 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:211 +#: common/models.py:218 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:434 +#: common/models.py:441 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:436 +#: common/models.py:443 msgid "Settings value" msgstr "" -#: common/models.py:493 +#: common/models.py:500 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:503 +#: common/models.py:510 msgid "Value must be an integer value" msgstr "" -#: common/models.py:517 +#: common/models.py:524 msgid "Key string must be unique" msgstr "" -#: common/models.py:590 company/forms.py:113 +#: common/models.py:597 company/forms.py:113 msgid "Price break quantity" msgstr "" -#: common/models.py:598 company/templates/company/supplier_part_pricing.html:80 +#: common/models.py:605 company/templates/company/supplier_part_pricing.html:80 #: part/templates/part/sale_prices.html:87 templates/js/bom.js:246 msgid "Price" msgstr "" -#: common/models.py:599 +#: common/models.py:606 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:622 +#: common/models.py:629 msgid "Default" msgstr "" @@ -1415,7 +1427,7 @@ msgstr "" msgid "Currency" msgstr "" -#: company/models.py:313 stock/models.py:345 +#: company/models.py:313 stock/models.py:360 #: stock/templates/stock/item_base.html:194 msgid "Base Part" msgstr "" @@ -1427,10 +1439,10 @@ msgstr "" #: company/models.py:323 company/templates/company/detail.html:57 #: company/templates/company/supplier_part_base.html:74 #: company/templates/company/supplier_part_detail.html:21 -#: order/templates/order/order_base.html:79 +#: order/templates/order/order_base.html:89 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:170 #: stock/templates/stock/item_base.html:304 templates/js/company.js:48 -#: templates/js/company.js:164 templates/js/order.js:162 +#: templates/js/company.js:164 templates/js/order.js:167 msgid "Supplier" msgstr "" @@ -1525,9 +1537,9 @@ msgid "Uses default currency" msgstr "" #: company/templates/company/detail.html:62 -#: order/templates/order/sales_order_base.html:89 stock/models.py:380 -#: stock/models.py:381 stock/templates/stock/item_base.html:221 -#: templates/js/company.js:40 templates/js/order.js:250 +#: order/templates/order/sales_order_base.html:89 stock/models.py:395 +#: stock/models.py:396 stock/templates/stock/item_base.html:221 +#: templates/js/company.js:40 templates/js/order.js:261 msgid "Customer" msgstr "" @@ -1542,7 +1554,7 @@ msgstr "" #: company/templates/company/detail_part.html:18 #: order/templates/order/purchase_order_detail.html:68 -#: part/templates/part/supplier.html:14 templates/js/stock.js:881 +#: part/templates/part/supplier.html:14 templates/js/stock.js:995 msgid "New Supplier Part" msgstr "" @@ -1566,7 +1578,7 @@ msgid "Delete Parts" msgstr "" #: company/templates/company/detail_part.html:63 -#: part/templates/part/category.html:116 templates/js/stock.js:875 +#: part/templates/part/category.html:116 templates/js/stock.js:989 msgid "New Part" msgstr "" @@ -1623,7 +1635,7 @@ msgstr "" #: order/templates/order/purchase_orders.html:13 #: part/templates/part/orders.html:9 part/templates/part/tabs.html:48 #: templates/InvenTree/settings/tabs.html:31 templates/navbar.html:33 -#: users/models.py:31 +#: users/models.py:33 msgid "Purchase Orders" msgstr "" @@ -1643,7 +1655,7 @@ msgstr "" #: order/templates/order/sales_orders.html:13 #: part/templates/part/sales_orders.html:9 part/templates/part/tabs.html:56 #: templates/InvenTree/settings/tabs.html:34 templates/navbar.html:42 -#: users/models.py:32 +#: users/models.py:34 msgid "Sales Orders" msgstr "" @@ -1658,7 +1670,7 @@ msgid "New Sales Order" msgstr "" #: company/templates/company/supplier_part_base.html:6 -#: company/templates/company/supplier_part_base.html:19 stock/models.py:354 +#: company/templates/company/supplier_part_base.html:19 stock/models.py:369 #: stock/templates/stock/item_base.html:309 templates/js/company.js:180 msgid "Supplier Part" msgstr "" @@ -1731,8 +1743,7 @@ msgstr "" #: company/templates/company/tabs.html:12 part/templates/part/tabs.html:18 #: stock/templates/stock/location.html:17 templates/InvenTree/search.html:155 #: templates/InvenTree/settings/tabs.html:25 templates/js/part.js:192 -#: templates/js/part.js:418 templates/js/stock.js:509 templates/navbar.html:22 -#: users/models.py:29 +#: templates/js/part.js:418 templates/js/stock.js:519 templates/navbar.html:22 msgid "Stock" msgstr "" @@ -1745,7 +1756,7 @@ msgstr "" #: part/templates/part/cat_link.html:7 part/templates/part/category.html:94 #: part/templates/part/category_tabs.html:6 #: templates/InvenTree/settings/tabs.html:22 templates/navbar.html:19 -#: templates/stats.html:35 templates/stats.html:44 users/models.py:28 +#: templates/stats.html:35 templates/stats.html:44 users/models.py:29 msgid "Parts" msgstr "" @@ -1814,7 +1825,7 @@ msgstr "" msgid "Edit Supplier Part" msgstr "" -#: company/views.py:295 templates/js/stock.js:882 +#: company/views.py:295 templates/js/stock.js:996 msgid "Create new Supplier Part" msgstr "" @@ -1834,39 +1845,59 @@ msgstr "" msgid "Delete Price Break" msgstr "" -#: label/models.py:55 -msgid "Label name" +#: label/api.py:171 +msgid "Must provide valid StockItem(s)" msgstr "" -#: label/models.py:58 -msgid "Label description" +#: label/api.py:185 label/api.py:337 +msgid "Error during label rendering" msgstr "" -#: label/models.py:63 -msgid "Label template file" +#: label/api.py:324 +msgid "Must provide valid StockLocation(s)" msgstr "" #: label/models.py:69 -msgid "Query filters (comma-separated list of key=value pairs" +msgid "Label name" msgstr "" -#: label/models.py:75 -msgid "Label template is enabled" +#: label/models.py:76 +msgid "Label description" msgstr "" -#: label/models.py:76 report/models.py:162 +#: label/models.py:83 stock/forms.py:198 +msgid "Label" +msgstr "" + +#: label/models.py:84 +msgid "Label template file" +msgstr "" + +#: label/models.py:90 report/models.py:162 msgid "Enabled" msgstr "" -#: order/forms.py:25 order/templates/order/order_base.html:39 +#: label/models.py:91 +msgid "Label template is enabled" +msgstr "" + +#: label/models.py:137 label/models.py:190 +msgid "Query filters (comma-separated list of key=value pairs" +msgstr "" + +#: label/models.py:138 label/models.py:191 +msgid "Filters" +msgstr "" + +#: order/forms.py:25 order/templates/order/order_base.html:44 msgid "Place order" msgstr "" -#: order/forms.py:36 order/templates/order/order_base.html:46 +#: order/forms.py:36 order/templates/order/order_base.html:51 msgid "Mark order as complete" msgstr "" -#: order/forms.py:47 order/forms.py:58 order/templates/order/order_base.html:51 +#: order/forms.py:47 order/forms.py:58 order/templates/order/order_base.html:56 #: order/templates/order/sales_order_base.html:56 msgid "Cancel order" msgstr "" @@ -1879,15 +1910,19 @@ msgstr "" msgid "Receive parts to this location" msgstr "" -#: order/forms.py:100 +#: order/forms.py:101 msgid "Purchase Order reference" msgstr "" -#: order/forms.py:128 +#: order/forms.py:107 +msgid "Target date for order delivery. Order will be overdue after this date." +msgstr "" + +#: order/forms.py:134 msgid "Enter sales order number" msgstr "" -#: order/forms.py:134 order/models.py:405 +#: order/forms.py:140 order/models.py:437 msgid "" "Target date for order completion. Order will be overdue after this date." msgstr "" @@ -1908,107 +1943,124 @@ msgstr "" msgid "Order notes" msgstr "" -#: order/models.py:169 order/models.py:398 +#: order/models.py:171 order/models.py:430 msgid "Purchase order status" msgstr "" -#: order/models.py:177 +#: order/models.py:179 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:180 +#: order/models.py:182 msgid "Supplier order reference code" msgstr "" -#: order/models.py:189 +#: order/models.py:193 +msgid "Issue Date" +msgstr "" + +#: order/models.py:194 msgid "Date order was issued" msgstr "" -#: order/models.py:191 +#: order/models.py:199 +msgid "Target Delivery Date" +msgstr "" + +#: order/models.py:200 +msgid "" +"Expected date for order delivery. Order will be overdue after this date." +msgstr "" + +#: order/models.py:205 +msgid "Completion Date" +msgstr "" + +#: order/models.py:206 msgid "Date order was completed" msgstr "" -#: order/models.py:214 order/models.py:296 part/views.py:1504 -#: stock/models.py:251 stock/models.py:856 +#: order/models.py:230 order/models.py:328 part/views.py:1504 +#: stock/models.py:259 stock/models.py:871 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:219 +#: order/models.py:235 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:291 +#: order/models.py:323 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:394 +#: order/models.py:426 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:400 +#: order/models.py:432 msgid "Customer order reference code" msgstr "" -#: order/models.py:462 +#: order/models.py:490 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:549 +#: order/models.py:577 msgid "Item quantity" msgstr "" -#: order/models.py:551 +#: order/models.py:579 msgid "Line item reference" msgstr "" -#: order/models.py:553 +#: order/models.py:581 msgid "Line item notes" msgstr "" -#: order/models.py:579 order/templates/order/order_base.html:9 +#: order/models.py:607 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 -#: stock/templates/stock/item_base.html:276 templates/js/order.js:146 +#: stock/templates/stock/item_base.html:276 templates/js/order.js:145 msgid "Purchase Order" msgstr "" -#: order/models.py:592 +#: order/models.py:620 msgid "Supplier part" msgstr "" -#: order/models.py:595 +#: order/models.py:623 msgid "Number of items received" msgstr "" -#: order/models.py:602 stock/models.py:473 +#: order/models.py:630 stock/models.py:488 #: stock/templates/stock/item_base.html:283 msgid "Purchase Price" msgstr "" -#: order/models.py:603 +#: order/models.py:631 msgid "Unit purchase price" msgstr "" -#: order/models.py:698 +#: order/models.py:726 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:700 +#: order/models.py:728 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:703 +#: order/models.py:731 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:713 +#: order/models.py:741 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:729 +#: order/models.py:757 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:732 +#: order/models.py:760 msgid "Enter stock allocation quantity" msgstr "" @@ -2018,41 +2070,41 @@ msgstr "" msgid "Are you sure you want to delete this attachment?" msgstr "" -#: order/templates/order/order_base.html:35 +#: order/templates/order/order_base.html:40 msgid "Edit order information" msgstr "" -#: order/templates/order/order_base.html:43 +#: order/templates/order/order_base.html:48 msgid "Receive items" msgstr "" -#: order/templates/order/order_base.html:56 +#: order/templates/order/order_base.html:61 msgid "Export order to file" msgstr "" -#: order/templates/order/order_base.html:64 +#: order/templates/order/order_base.html:69 msgid "Purchase Order Details" msgstr "" -#: order/templates/order/order_base.html:69 +#: order/templates/order/order_base.html:74 #: order/templates/order/sales_order_base.html:74 msgid "Order Reference" msgstr "" -#: order/templates/order/order_base.html:74 +#: order/templates/order/order_base.html:79 #: order/templates/order/sales_order_base.html:79 msgid "Order Status" msgstr "" -#: order/templates/order/order_base.html:85 templates/js/order.js:169 +#: order/templates/order/order_base.html:95 templates/js/order.js:175 msgid "Supplier Reference" msgstr "" -#: order/templates/order/order_base.html:104 +#: order/templates/order/order_base.html:114 msgid "Issued" msgstr "" -#: order/templates/order/order_base.html:111 +#: order/templates/order/order_base.html:128 #: order/templates/order/purchase_order_detail.html:193 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:128 @@ -2100,7 +2152,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "" #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:193 templates/js/order.js:291 +#: templates/js/order.js:203 templates/js/order.js:302 msgid "Items" msgstr "" @@ -2138,7 +2190,7 @@ msgstr "" #: order/templates/order/purchase_order_detail.html:39 #: order/templates/order/purchase_order_detail.html:119 #: part/templates/part/category.html:173 part/templates/part/category.html:215 -#: templates/js/stock.js:627 templates/js/stock.js:887 +#: templates/js/stock.js:642 templates/js/stock.js:1001 msgid "New Location" msgstr "" @@ -2207,7 +2259,7 @@ msgstr "" msgid "Sales Order Details" msgstr "" -#: order/templates/order/sales_order_base.html:95 templates/js/order.js:257 +#: order/templates/order/sales_order_base.html:95 templates/js/order.js:268 msgid "Customer Reference" msgstr "" @@ -2223,7 +2275,7 @@ msgid "Sales Order Items" msgstr "" #: order/templates/order/sales_order_detail.html:72 -#: order/templates/order/sales_order_detail.html:154 stock/models.py:385 +#: order/templates/order/sales_order_detail.html:154 stock/models.py:400 #: stock/templates/stock/item_base.html:208 templates/js/build.js:418 msgid "Serial Number" msgstr "" @@ -2334,18 +2386,14 @@ msgstr "" msgid "Confirm order cancellation" msgstr "" -#: order/views.py:435 -msgid "Order cannot be cancelled as either pending or placed" +#: order/views.py:435 order/views.py:462 +msgid "Order cannot be cancelled" msgstr "" #: order/views.py:449 msgid "Cancel sales order" msgstr "" -#: order/views.py:462 -msgid "Order cannot be cancelled" -msgstr "" - #: order/views.py:476 msgid "Issue Order" msgstr "" @@ -2460,123 +2508,123 @@ msgstr "" msgid "Error reading BOM file (incorrect row size)" msgstr "" -#: part/forms.py:61 stock/forms.py:261 +#: part/forms.py:71 stock/forms.py:261 msgid "File Format" msgstr "" -#: part/forms.py:61 stock/forms.py:261 +#: part/forms.py:71 stock/forms.py:261 msgid "Select output file format" msgstr "" -#: part/forms.py:63 +#: part/forms.py:73 msgid "Cascading" msgstr "" -#: part/forms.py:63 +#: part/forms.py:73 msgid "Download cascading / multi-level BOM" msgstr "" -#: part/forms.py:65 +#: part/forms.py:75 msgid "Levels" msgstr "" -#: part/forms.py:65 +#: part/forms.py:75 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "" -#: part/forms.py:67 +#: part/forms.py:77 msgid "Include Parameter Data" msgstr "" -#: part/forms.py:67 +#: part/forms.py:77 msgid "Include part parameters data in exported BOM" msgstr "" -#: part/forms.py:69 +#: part/forms.py:79 msgid "Include Stock Data" msgstr "" -#: part/forms.py:69 +#: part/forms.py:79 msgid "Include part stock data in exported BOM" msgstr "" -#: part/forms.py:71 +#: part/forms.py:81 msgid "Include Supplier Data" msgstr "" -#: part/forms.py:71 +#: part/forms.py:81 msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:92 part/models.py:1781 +#: part/forms.py:102 part/models.py:1781 msgid "Parent Part" msgstr "" -#: part/forms.py:93 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:103 part/templates/part/bom_duplicate.html:7 msgid "Select parent part to copy BOM from" msgstr "" -#: part/forms.py:99 +#: part/forms.py:109 msgid "Clear existing BOM items" msgstr "" -#: part/forms.py:104 +#: part/forms.py:114 msgid "Confirm BOM duplication" msgstr "" -#: part/forms.py:122 +#: part/forms.py:132 msgid "Confirm that the BOM is correct" msgstr "" -#: part/forms.py:134 +#: part/forms.py:144 msgid "Select BOM file to upload" msgstr "" -#: part/forms.py:153 +#: part/forms.py:163 msgid "Related Part" msgstr "" -#: part/forms.py:172 +#: part/forms.py:182 msgid "Select part category" msgstr "" -#: part/forms.py:189 +#: part/forms.py:199 msgid "Duplicate all BOM data for this part" msgstr "" -#: part/forms.py:190 +#: part/forms.py:200 msgid "Copy BOM" msgstr "" -#: part/forms.py:195 +#: part/forms.py:205 msgid "Duplicate all parameter data for this part" msgstr "" -#: part/forms.py:196 +#: part/forms.py:206 msgid "Copy Parameters" msgstr "" -#: part/forms.py:201 +#: part/forms.py:211 msgid "Confirm part creation" msgstr "" -#: part/forms.py:206 +#: part/forms.py:216 msgid "Include category parameter templates" msgstr "" -#: part/forms.py:211 +#: part/forms.py:221 msgid "Include parent categories parameter templates" msgstr "" -#: part/forms.py:291 +#: part/forms.py:301 msgid "Add parameter template to same level categories" msgstr "" -#: part/forms.py:295 +#: part/forms.py:305 msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:339 +#: part/forms.py:349 msgid "Input quantity for price calculation" msgstr "" @@ -2595,6 +2643,7 @@ msgstr "" #: part/models.py:78 part/templates/part/category.html:18 #: part/templates/part/category.html:89 templates/stats.html:39 +#: users/models.py:28 msgid "Part Categories" msgstr "" @@ -2742,7 +2791,7 @@ msgstr "" #: part/models.py:821 part/templates/part/detail.html:222 #: templates/js/table_filters.js:19 templates/js/table_filters.js:55 -#: templates/js/table_filters.js:196 templates/js/table_filters.js:261 +#: templates/js/table_filters.js:196 templates/js/table_filters.js:265 msgid "Active" msgstr "" @@ -2770,7 +2819,7 @@ msgstr "" msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:1690 templates/js/part.js:567 templates/js/stock.js:93 +#: part/models.py:1690 templates/js/part.js:567 templates/js/stock.js:103 msgid "Test Name" msgstr "" @@ -2869,7 +2918,7 @@ msgid "BOM line checksum" msgstr "" #: part/models.py:1963 part/views.py:1510 part/views.py:1562 -#: stock/models.py:241 +#: stock/models.py:249 msgid "Quantity must be integer value for trackable parts" msgstr "" @@ -2881,11 +2930,11 @@ msgstr "" msgid "BOM Item" msgstr "" -#: part/models.py:2092 +#: part/models.py:2098 msgid "Select Related Part" msgstr "" -#: part/models.py:2124 +#: part/models.py:2130 msgid "" "Error creating relationship: check that the part is not related to itself " "and that the relationship is unique" @@ -2908,7 +2957,7 @@ msgstr "" #: stock/templates/stock/item_base.html:72 #: stock/templates/stock/item_base.html:291 #: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:751 -#: templates/js/stock.js:720 templates/js/stock.js:980 +#: templates/js/stock.js:834 templates/js/stock.js:1094 msgid "Stock Item" msgstr "" @@ -3125,7 +3174,7 @@ msgstr "" msgid "Export Data" msgstr "" -#: part/templates/part/category.html:174 templates/js/stock.js:628 +#: part/templates/part/category.html:174 templates/js/stock.js:643 msgid "Create new location" msgstr "" @@ -3141,7 +3190,7 @@ msgstr "" msgid "Create new Part Category" msgstr "" -#: part/templates/part/category.html:216 stock/views.py:1363 +#: part/templates/part/category.html:216 stock/views.py:1276 msgid "Create new Stock Location" msgstr "" @@ -3177,7 +3226,7 @@ msgstr "" msgid "Stock Expiry Time" msgstr "" -#: part/templates/part/detail.html:121 templates/js/order.js:276 +#: part/templates/part/detail.html:121 templates/js/order.js:287 msgid "Creation Date" msgstr "" @@ -3263,17 +3312,17 @@ msgstr "" #: part/templates/part/params.html:15 #: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:41 +#: templates/InvenTree/settings/part.html:42 msgid "New Parameter" msgstr "" -#: part/templates/part/params.html:25 stock/models.py:1499 -#: templates/InvenTree/settings/header.html:8 templates/js/stock.js:113 +#: part/templates/part/params.html:25 stock/models.py:1531 +#: templates/InvenTree/settings/header.html:8 templates/js/stock.js:123 msgid "Value" msgstr "" #: part/templates/part/params.html:41 part/templates/part/related.html:41 -#: part/templates/part/supplier.html:19 users/models.py:152 +#: part/templates/part/supplier.html:19 users/models.py:159 msgid "Delete" msgstr "" @@ -3356,7 +3405,7 @@ msgstr "" msgid "Allocated to Sales Orders" msgstr "" -#: part/templates/part/part_base.html:160 +#: part/templates/part/part_base.html:160 templates/js/bom.js:262 msgid "Can Build" msgstr "" @@ -3546,7 +3595,7 @@ msgstr "" msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:594 templates/js/stock.js:876 +#: part/views.py:594 templates/js/stock.js:990 msgid "Create New Part" msgstr "" @@ -3730,10 +3779,6 @@ msgstr "" msgid "Enter unique serial numbers (or leave blank)" msgstr "" -#: stock/forms.py:198 -msgid "Label" -msgstr "" - #: stock/forms.py:199 stock/forms.py:255 msgid "Select test report template" msgstr "" @@ -3778,7 +3823,7 @@ msgstr "" msgid "Add note (required)" msgstr "" -#: stock/forms.py:377 stock/views.py:935 stock/views.py:1133 +#: stock/forms.py:377 stock/views.py:848 stock/views.py:1046 msgid "Confirm stock adjustment" msgstr "" @@ -3794,237 +3839,237 @@ msgstr "" msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:186 +#: stock/models.py:194 msgid "Created stock item" msgstr "" -#: stock/models.py:222 +#: stock/models.py:230 msgid "StockItem with this serial number already exists" msgstr "" -#: stock/models.py:258 +#: stock/models.py:266 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:268 stock/models.py:277 +#: stock/models.py:276 stock/models.py:285 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:269 +#: stock/models.py:277 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:291 +#: stock/models.py:299 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:297 +#: stock/models.py:305 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:304 +#: stock/models.py:312 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:337 +#: stock/models.py:352 msgid "Parent Stock Item" msgstr "" -#: stock/models.py:346 +#: stock/models.py:361 msgid "Base part" msgstr "" -#: stock/models.py:355 +#: stock/models.py:370 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:360 stock/templates/stock/stock_app_base.html:7 +#: stock/models.py:375 stock/templates/stock/stock_app_base.html:7 msgid "Stock Location" msgstr "" -#: stock/models.py:363 +#: stock/models.py:378 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:368 stock/templates/stock/item_base.html:229 +#: stock/models.py:383 stock/templates/stock/item_base.html:229 msgid "Installed In" msgstr "" -#: stock/models.py:371 +#: stock/models.py:386 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:387 +#: stock/models.py:402 msgid "Serial number for this item" msgstr "" -#: stock/models.py:399 +#: stock/models.py:414 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:403 +#: stock/models.py:418 msgid "Stock Quantity" msgstr "" -#: stock/models.py:412 +#: stock/models.py:427 msgid "Source Build" msgstr "" -#: stock/models.py:414 +#: stock/models.py:429 msgid "Build for this stock item" msgstr "" -#: stock/models.py:425 +#: stock/models.py:440 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:428 +#: stock/models.py:443 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:434 +#: stock/models.py:449 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:440 stock/templates/stock/item_base.html:316 -#: templates/js/stock.js:597 +#: stock/models.py:455 stock/templates/stock/item_base.html:316 +#: templates/js/stock.js:612 msgid "Expiry Date" msgstr "" -#: stock/models.py:441 +#: stock/models.py:456 msgid "" "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:454 +#: stock/models.py:469 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:464 stock/templates/stock/item_notes.html:14 +#: stock/models.py:479 stock/templates/stock/item_notes.html:14 #: stock/templates/stock/item_notes.html:30 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:474 +#: stock/models.py:489 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:574 +#: stock/models.py:589 msgid "Assigned to Customer" msgstr "" -#: stock/models.py:576 +#: stock/models.py:591 msgid "Manually assigned to customer" msgstr "" -#: stock/models.py:589 +#: stock/models.py:604 msgid "Returned from customer" msgstr "" -#: stock/models.py:591 +#: stock/models.py:606 msgid "Returned to location" msgstr "" -#: stock/models.py:716 +#: stock/models.py:731 msgid "Installed into stock item" msgstr "" -#: stock/models.py:724 +#: stock/models.py:739 msgid "Installed stock item" msgstr "" -#: stock/models.py:748 +#: stock/models.py:763 msgid "Uninstalled stock item" msgstr "" -#: stock/models.py:767 +#: stock/models.py:782 msgid "Uninstalled into location" msgstr "" -#: stock/models.py:847 +#: stock/models.py:862 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:853 +#: stock/models.py:868 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:859 +#: stock/models.py:874 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:862 +#: stock/models.py:877 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:865 +#: stock/models.py:880 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:897 +#: stock/models.py:912 msgid "Add serial number" msgstr "" -#: stock/models.py:900 +#: stock/models.py:915 #, python-brace-format msgid "Serialized {n} items" msgstr "" -#: stock/models.py:1011 +#: stock/models.py:1026 msgid "StockItem cannot be moved as it is not in stock" msgstr "" -#: stock/models.py:1400 +#: stock/models.py:1432 msgid "Tracking entry title" msgstr "" -#: stock/models.py:1402 +#: stock/models.py:1434 msgid "Entry notes" msgstr "" -#: stock/models.py:1404 +#: stock/models.py:1436 msgid "Link to external page for further information" msgstr "" -#: stock/models.py:1464 +#: stock/models.py:1496 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1470 +#: stock/models.py:1502 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1487 +#: stock/models.py:1519 msgid "Test" msgstr "" -#: stock/models.py:1488 +#: stock/models.py:1520 msgid "Test name" msgstr "" -#: stock/models.py:1493 +#: stock/models.py:1525 msgid "Result" msgstr "" -#: stock/models.py:1494 templates/js/table_filters.js:172 +#: stock/models.py:1526 templates/js/table_filters.js:172 msgid "Test result" msgstr "" -#: stock/models.py:1500 +#: stock/models.py:1532 msgid "Test output value" msgstr "" -#: stock/models.py:1506 +#: stock/models.py:1538 msgid "Attachment" msgstr "" -#: stock/models.py:1507 +#: stock/models.py:1539 msgid "Test result attachment" msgstr "" -#: stock/models.py:1513 +#: stock/models.py:1545 msgid "Test notes" msgstr "" @@ -4108,15 +4153,15 @@ msgid "Stock adjustment actions" msgstr "" #: stock/templates/stock/item_base.html:141 -#: stock/templates/stock/location.html:41 templates/stock_table.html:23 +#: stock/templates/stock/location.html:41 templates/stock_table.html:24 msgid "Count stock" msgstr "" -#: stock/templates/stock/item_base.html:142 templates/stock_table.html:21 +#: stock/templates/stock/item_base.html:142 templates/stock_table.html:22 msgid "Add stock" msgstr "" -#: stock/templates/stock/item_base.html:143 templates/stock_table.html:22 +#: stock/templates/stock/item_base.html:143 templates/stock_table.html:23 msgid "Remove stock" msgstr "" @@ -4136,7 +4181,7 @@ msgstr "" msgid "Return to stock" msgstr "" -#: stock/templates/stock/item_base.html:158 templates/js/stock.js:1017 +#: stock/templates/stock/item_base.html:158 templates/js/stock.js:1131 msgid "Uninstall stock item" msgstr "" @@ -4266,47 +4311,48 @@ msgstr "" msgid "Check-in Items" msgstr "" -#: stock/templates/stock/location.html:45 +#: stock/templates/stock/location.html:47 msgid "Location actions" msgstr "" -#: stock/templates/stock/location.html:47 +#: stock/templates/stock/location.html:49 msgid "Edit location" msgstr "" -#: stock/templates/stock/location.html:49 +#: stock/templates/stock/location.html:51 msgid "Delete location" msgstr "" -#: stock/templates/stock/location.html:59 +#: stock/templates/stock/location.html:61 msgid "Location Details" msgstr "" -#: stock/templates/stock/location.html:64 +#: stock/templates/stock/location.html:66 msgid "Location Path" msgstr "" -#: stock/templates/stock/location.html:69 +#: stock/templates/stock/location.html:71 msgid "Location Description" msgstr "" -#: stock/templates/stock/location.html:74 +#: stock/templates/stock/location.html:76 msgid "Sublocations" msgstr "" -#: stock/templates/stock/location.html:79 -#: stock/templates/stock/location.html:94 +#: stock/templates/stock/location.html:81 +#: stock/templates/stock/location.html:96 #: templates/InvenTree/search_stock_items.html:6 templates/stats.html:48 -#: templates/stats.html:57 +#: templates/stats.html:57 users/models.py:31 msgid "Stock Items" msgstr "" -#: stock/templates/stock/location.html:84 +#: stock/templates/stock/location.html:86 msgid "Stock Details" msgstr "" -#: stock/templates/stock/location.html:89 +#: stock/templates/stock/location.html:91 #: templates/InvenTree/search_stock_location.html:6 templates/stats.html:52 +#: users/models.py:30 msgid "Stock Locations" msgstr "" @@ -4318,7 +4364,7 @@ msgstr "" msgid "The following stock items will be uninstalled" msgstr "" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1335 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1248 msgid "Convert Stock Item" msgstr "" @@ -4350,205 +4396,197 @@ msgstr "" msgid "Installed Items" msgstr "" -#: stock/views.py:123 +#: stock/views.py:122 msgid "Edit Stock Location" msgstr "" -#: stock/views.py:148 +#: stock/views.py:147 msgid "Stock Location QR code" msgstr "" -#: stock/views.py:167 +#: stock/views.py:166 msgid "Add Stock Item Attachment" msgstr "" -#: stock/views.py:214 +#: stock/views.py:213 msgid "Edit Stock Item Attachment" msgstr "" -#: stock/views.py:231 +#: stock/views.py:230 msgid "Delete Stock Item Attachment" msgstr "" -#: stock/views.py:248 +#: stock/views.py:247 msgid "Assign to Customer" msgstr "" -#: stock/views.py:258 +#: stock/views.py:257 msgid "Customer must be specified" msgstr "" -#: stock/views.py:282 +#: stock/views.py:281 msgid "Return to Stock" msgstr "" -#: stock/views.py:292 +#: stock/views.py:291 msgid "Specify a valid location" msgstr "" -#: stock/views.py:303 +#: stock/views.py:302 msgid "Stock item returned from customer" msgstr "" #: stock/views.py:313 -msgid "Select Label Template" -msgstr "" - -#: stock/views.py:336 -msgid "Select valid label" -msgstr "" - -#: stock/views.py:400 msgid "Delete All Test Data" msgstr "" -#: stock/views.py:416 +#: stock/views.py:329 msgid "Confirm test data deletion" msgstr "" -#: stock/views.py:436 +#: stock/views.py:349 msgid "Add Test Result" msgstr "" -#: stock/views.py:477 +#: stock/views.py:390 msgid "Edit Test Result" msgstr "" -#: stock/views.py:495 +#: stock/views.py:408 msgid "Delete Test Result" msgstr "" -#: stock/views.py:507 +#: stock/views.py:420 msgid "Select Test Report Template" msgstr "" -#: stock/views.py:537 +#: stock/views.py:450 msgid "Select valid template" msgstr "" -#: stock/views.py:590 +#: stock/views.py:503 msgid "Stock Export Options" msgstr "" -#: stock/views.py:712 +#: stock/views.py:625 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:738 +#: stock/views.py:651 msgid "Install Stock Item" msgstr "" -#: stock/views.py:838 +#: stock/views.py:751 msgid "Uninstall Stock Items" msgstr "" -#: stock/views.py:946 +#: stock/views.py:859 msgid "Uninstalled stock items" msgstr "" -#: stock/views.py:971 +#: stock/views.py:884 msgid "Adjust Stock" msgstr "" -#: stock/views.py:1081 +#: stock/views.py:994 msgid "Move Stock Items" msgstr "" -#: stock/views.py:1082 +#: stock/views.py:995 msgid "Count Stock Items" msgstr "" -#: stock/views.py:1083 +#: stock/views.py:996 msgid "Remove From Stock" msgstr "" -#: stock/views.py:1084 +#: stock/views.py:997 msgid "Add Stock Items" msgstr "" -#: stock/views.py:1085 +#: stock/views.py:998 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:1113 +#: stock/views.py:1026 msgid "Must enter integer value" msgstr "" -#: stock/views.py:1118 +#: stock/views.py:1031 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:1125 +#: stock/views.py:1038 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:1204 +#: stock/views.py:1117 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:1219 +#: stock/views.py:1132 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:1232 +#: stock/views.py:1145 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:1260 +#: stock/views.py:1173 msgid "No items were moved" msgstr "" -#: stock/views.py:1263 +#: stock/views.py:1176 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:1282 +#: stock/views.py:1195 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:1294 +#: stock/views.py:1207 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:1385 +#: stock/views.py:1298 msgid "Serialize Stock" msgstr "" -#: stock/views.py:1479 templates/js/build.js:210 +#: stock/views.py:1392 templates/js/build.js:210 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:1587 +#: stock/views.py:1500 msgid "Duplicate Stock Item" msgstr "" -#: stock/views.py:1664 +#: stock/views.py:1577 msgid "Quantity cannot be negative" msgstr "" -#: stock/views.py:1750 +#: stock/views.py:1663 msgid "Delete Stock Location" msgstr "" -#: stock/views.py:1764 +#: stock/views.py:1677 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:1776 +#: stock/views.py:1689 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:1795 +#: stock/views.py:1708 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:1805 +#: stock/views.py:1718 msgid "Add Stock Tracking Entry" msgstr "" @@ -4596,6 +4634,10 @@ msgstr "" msgid "Outstanding Purchase Orders" msgstr "" +#: templates/InvenTree/po_overdue.html:7 +msgid "Overdue Purchase Orders" +msgstr "" + #: templates/InvenTree/required_stock_build.html:7 msgid "Require Stock To Complete Build" msgstr "" @@ -4612,11 +4654,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:191 templates/js/stock.js:290 +#: templates/InvenTree/search.html:191 templates/js/stock.js:300 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:194 templates/js/stock.js:300 +#: templates/InvenTree/search.html:194 templates/js/stock.js:310 msgid "No stock location set" msgstr "" @@ -4645,12 +4687,12 @@ msgid "Default Value" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:78 +#: templates/InvenTree/settings/part.html:79 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:79 +#: templates/InvenTree/settings/part.html:80 msgid "Delete Template" msgstr "" @@ -4670,11 +4712,11 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:37 +#: templates/InvenTree/settings/part.html:38 msgid "Part Parameter Templates" msgstr "" -#: templates/InvenTree/settings/part.html:58 +#: templates/InvenTree/settings/part.html:59 msgid "No part parameter templates found" msgstr "" @@ -4854,7 +4896,7 @@ msgstr "" msgid "Enter barcode data" msgstr "" -#: templates/js/barcode.js:42 +#: templates/js/barcode.js:42 templates/js/modals.js:856 msgid "Invalid server response" msgstr "" @@ -4931,39 +4973,39 @@ msgstr "" msgid "No pricing available" msgstr "" -#: templates/js/bom.js:272 templates/js/build.js:571 +#: templates/js/bom.js:304 templates/js/build.js:571 msgid "Actions" msgstr "" -#: templates/js/bom.js:280 +#: templates/js/bom.js:312 msgid "Validate BOM Item" msgstr "" -#: templates/js/bom.js:282 +#: templates/js/bom.js:314 msgid "This line has been validated" msgstr "" -#: templates/js/bom.js:284 +#: templates/js/bom.js:316 msgid "Edit BOM Item" msgstr "" -#: templates/js/bom.js:286 +#: templates/js/bom.js:318 msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:363 templates/js/build.js:305 +#: templates/js/bom.js:395 templates/js/build.js:305 msgid "No BOM items found" msgstr "" -#: templates/js/bom.js:509 +#: templates/js/bom.js:541 msgid "INACTIVE" msgstr "" -#: templates/js/bom.js:523 +#: templates/js/bom.js:555 msgid "Uses" msgstr "" -#: templates/js/bom.js:534 +#: templates/js/bom.js:566 msgid "No matching parts found" msgstr "" @@ -4999,7 +5041,7 @@ msgstr "" msgid "Build stock" msgstr "" -#: templates/js/build.js:582 templates/stock_table.html:25 +#: templates/js/build.js:582 templates/stock_table.html:26 msgid "Order stock" msgstr "" @@ -5043,23 +5085,153 @@ msgstr "" msgid "Assembled part" msgstr "" +#: templates/js/label.js:10 +msgid "Select Stock Items" +msgstr "" + +#: templates/js/label.js:11 +msgid "Stock item(s) must be selected before printing labels" +msgstr "" + +#: templates/js/label.js:29 templates/js/label.js:79 +msgid "No Labels Found" +msgstr "" + +#: templates/js/label.js:30 +msgid "No labels found which match selected stock item(s)" +msgstr "" + +#: templates/js/label.js:61 +msgid "Select Stock Locations" +msgstr "" + +#: templates/js/label.js:62 +msgid "Stock location(s) must be selected before printing labels" +msgstr "" + +#: templates/js/label.js:80 +msgid "No labels found which match selected stock location(s)" +msgstr "" + +#: templates/js/label.js:141 +msgid "Select Label" +msgstr "" + +#: templates/js/label.js:156 +msgid "Select Label Template" +msgstr "" + +#: templates/js/modals.js:406 +msgid "Show Error Information" +msgstr "" + +#: templates/js/modals.js:473 +msgid "Accept" +msgstr "" + +#: templates/js/modals.js:474 +msgid "Cancel" +msgstr "" + +#: templates/js/modals.js:538 +msgid "Loading Data" +msgstr "" + +#: templates/js/modals.js:549 templates/js/modals.js:807 +#: templates/modals.html:19 templates/modals.html:41 +msgid "Submit" +msgstr "" + +#: templates/js/modals.js:550 templates/js/modals.js:808 +#: templates/modals.html:18 templates/modals.html:40 +msgid "Close" +msgstr "" + +#: templates/js/modals.js:759 +msgid "Invalid response from server" +msgstr "" + +#: templates/js/modals.js:759 +msgid "Form data missing from server response" +msgstr "" + +#: templates/js/modals.js:772 +msgid "Error posting form data" +msgstr "" + +#: templates/js/modals.js:856 +msgid "JSON response missing form data" +msgstr "" + +#: templates/js/modals.js:866 +msgid "No Response" +msgstr "" + +#: templates/js/modals.js:867 +msgid "No response from the InvenTree server" +msgstr "" + +#: templates/js/modals.js:871 +msgid "Error 400: Bad Request" +msgstr "" + +#: templates/js/modals.js:872 +msgid "Server returned error code 400" +msgstr "" + +#: templates/js/modals.js:876 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/modals.js:877 +msgid "Authentication credentials not supplied" +msgstr "" + +#: templates/js/modals.js:881 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/modals.js:882 +msgid "You do not have the required permissions to access this function" +msgstr "" + +#: templates/js/modals.js:886 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/modals.js:887 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/modals.js:891 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/modals.js:892 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/modals.js:895 +msgid "Error requesting form data" +msgstr "" + #: templates/js/order.js:135 msgid "No purchase orders found" msgstr "" -#: templates/js/order.js:188 templates/js/stock.js:702 -msgid "Date" -msgstr "" - -#: templates/js/order.js:218 -msgid "No sales orders found" -msgstr "" - -#: templates/js/order.js:241 +#: templates/js/order.js:159 templates/js/order.js:252 msgid "Order is overdue" msgstr "" -#: templates/js/order.js:286 +#: templates/js/order.js:193 templates/js/stock.js:816 +msgid "Date" +msgstr "" + +#: templates/js/order.js:229 +msgid "No sales orders found" +msgstr "" + +#: templates/js/order.js:297 msgid "Shipment Date" msgstr "" @@ -5087,8 +5259,8 @@ msgstr "" msgid "No parts found" msgstr "" -#: templates/js/part.js:343 templates/js/stock.js:463 -#: templates/js/stock.js:1049 +#: templates/js/part.js:343 templates/js/stock.js:473 +#: templates/js/stock.js:1163 msgid "Select" msgstr "" @@ -5096,7 +5268,7 @@ msgstr "" msgid "No category" msgstr "" -#: templates/js/part.js:429 templates/js/table_filters.js:274 +#: templates/js/part.js:429 templates/js/table_filters.js:278 msgid "Low stock" msgstr "" @@ -5116,11 +5288,11 @@ msgstr "" msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:604 templates/js/stock.js:64 +#: templates/js/part.js:604 templates/js/stock.js:74 msgid "Edit test result" msgstr "" -#: templates/js/part.js:605 templates/js/stock.js:65 +#: templates/js/part.js:605 templates/js/stock.js:75 msgid "Delete test result" msgstr "" @@ -5128,111 +5300,131 @@ msgstr "" msgid "This test is defined for a parent part" msgstr "" -#: templates/js/stock.js:27 +#: templates/js/stock.js:37 msgid "PASS" msgstr "" -#: templates/js/stock.js:29 +#: templates/js/stock.js:39 msgid "FAIL" msgstr "" -#: templates/js/stock.js:34 +#: templates/js/stock.js:44 msgid "NO RESULT" msgstr "" -#: templates/js/stock.js:60 +#: templates/js/stock.js:70 msgid "Add test result" msgstr "" -#: templates/js/stock.js:79 +#: templates/js/stock.js:89 msgid "No test results found" msgstr "" -#: templates/js/stock.js:121 +#: templates/js/stock.js:131 msgid "Test Date" msgstr "" -#: templates/js/stock.js:282 +#: templates/js/stock.js:292 msgid "In production" msgstr "" -#: templates/js/stock.js:286 +#: templates/js/stock.js:296 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:304 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:314 +#: templates/js/stock.js:324 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:431 +#: templates/js/stock.js:441 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:525 +#: templates/js/stock.js:535 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:530 +#: templates/js/stock.js:540 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:533 +#: templates/js/stock.js:543 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:537 +#: templates/js/stock.js:547 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:539 +#: templates/js/stock.js:549 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:543 +#: templates/js/stock.js:553 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:547 +#: templates/js/stock.js:557 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:555 +#: templates/js/stock.js:565 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:559 +#: templates/js/stock.js:569 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:562 +#: templates/js/stock.js:572 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:566 templates/js/table_filters.js:106 +#: templates/js/stock.js:576 templates/js/table_filters.js:106 msgid "Depleted" msgstr "" -#: templates/js/stock.js:768 +#: templates/js/stock.js:605 +msgid "Stocktake" +msgstr "" + +#: templates/js/stock.js:732 +msgid "Stock Status" +msgstr "" + +#: templates/js/stock.js:747 +msgid "Set Stock Status" +msgstr "" + +#: templates/js/stock.js:761 +msgid "Select Status Code" +msgstr "" + +#: templates/js/stock.js:762 +msgid "Status code must be selected" +msgstr "" + +#: templates/js/stock.js:882 msgid "No user information" msgstr "" -#: templates/js/stock.js:888 +#: templates/js/stock.js:1002 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:987 +#: templates/js/stock.js:1101 msgid "Serial" msgstr "" -#: templates/js/stock.js:1080 templates/js/table_filters.js:131 +#: templates/js/stock.js:1194 templates/js/table_filters.js:131 msgid "Installed" msgstr "" -#: templates/js/stock.js:1105 +#: templates/js/stock.js:1219 msgid "Install item" msgstr "" @@ -5273,7 +5465,7 @@ msgstr "" msgid "Batch code" msgstr "" -#: templates/js/table_filters.js:91 templates/js/table_filters.js:241 +#: templates/js/table_filters.js:91 templates/js/table_filters.js:245 msgid "Active parts" msgstr "" @@ -5341,43 +5533,43 @@ msgstr "" msgid "Build status" msgstr "" -#: templates/js/table_filters.js:210 templates/js/table_filters.js:223 +#: templates/js/table_filters.js:210 templates/js/table_filters.js:227 msgid "Order status" msgstr "" -#: templates/js/table_filters.js:215 templates/js/table_filters.js:228 +#: templates/js/table_filters.js:215 templates/js/table_filters.js:232 msgid "Outstanding" msgstr "" -#: templates/js/table_filters.js:251 +#: templates/js/table_filters.js:255 msgid "Include subcategories" msgstr "" -#: templates/js/table_filters.js:252 +#: templates/js/table_filters.js:256 msgid "Include parts in subcategories" msgstr "" -#: templates/js/table_filters.js:256 +#: templates/js/table_filters.js:260 msgid "Has IPN" msgstr "" -#: templates/js/table_filters.js:257 +#: templates/js/table_filters.js:261 msgid "Part has internal part number" msgstr "" -#: templates/js/table_filters.js:262 +#: templates/js/table_filters.js:266 msgid "Show active parts" msgstr "" -#: templates/js/table_filters.js:270 +#: templates/js/table_filters.js:274 msgid "Stock available" msgstr "" -#: templates/js/table_filters.js:286 +#: templates/js/table_filters.js:290 msgid "Starred" msgstr "" -#: templates/js/table_filters.js:298 +#: templates/js/table_filters.js:302 msgid "Purchasable" msgstr "" @@ -5385,14 +5577,6 @@ msgstr "" msgid "Form errors exist" msgstr "" -#: templates/modals.html:18 templates/modals.html:40 -msgid "Close" -msgstr "" - -#: templates/modals.html:19 templates/modals.html:41 -msgid "Submit" -msgstr "" - #: templates/navbar.html:29 msgid "Buy" msgstr "" @@ -5453,94 +5637,106 @@ msgstr "" msgid "Export Stock Information" msgstr "" -#: templates/stock_table.html:21 -msgid "Add to selected stock items" +#: templates/stock_table.html:20 +msgid "Print labels" msgstr "" #: templates/stock_table.html:22 -msgid "Remove from selected stock items" +msgid "Add to selected stock items" msgstr "" #: templates/stock_table.html:23 +msgid "Remove from selected stock items" +msgstr "" + +#: templates/stock_table.html:24 msgid "Stocktake selected stock items" msgstr "" -#: templates/stock_table.html:24 +#: templates/stock_table.html:25 msgid "Move selected stock items" msgstr "" -#: templates/stock_table.html:24 +#: templates/stock_table.html:25 msgid "Move stock" msgstr "" -#: templates/stock_table.html:25 +#: templates/stock_table.html:26 msgid "Order selected items" msgstr "" -#: templates/stock_table.html:28 +#: templates/stock_table.html:27 +msgid "Change status" +msgstr "" + +#: templates/stock_table.html:27 +msgid "Change stock status" +msgstr "" + +#: templates/stock_table.html:30 msgid "Delete selected items" msgstr "" -#: templates/stock_table.html:28 +#: templates/stock_table.html:30 msgid "Delete Stock" msgstr "" -#: users/admin.py:62 +#: users/admin.py:64 msgid "Users" msgstr "" -#: users/admin.py:63 +#: users/admin.py:65 msgid "Select which users are assigned to this group" msgstr "" -#: users/admin.py:178 +#: users/admin.py:187 msgid "The following users are members of multiple groups:" msgstr "" -#: users/admin.py:201 +#: users/admin.py:210 msgid "Personal info" msgstr "" -#: users/admin.py:202 +#: users/admin.py:211 msgid "Permissions" msgstr "" -#: users/admin.py:205 +#: users/admin.py:214 msgid "Important dates" msgstr "" -#: users/models.py:135 +#: users/models.py:142 msgid "Permission set" msgstr "" -#: users/models.py:143 +#: users/models.py:150 msgid "Group" msgstr "" -#: users/models.py:146 +#: users/models.py:153 msgid "View" msgstr "" -#: users/models.py:146 +#: users/models.py:153 msgid "Permission to view items" msgstr "" -#: users/models.py:148 +#: users/models.py:155 msgid "Add" msgstr "" -#: users/models.py:148 +#: users/models.py:155 msgid "Permission to add items" msgstr "" -#: users/models.py:150 +#: users/models.py:157 msgid "Change" msgstr "" -#: users/models.py:150 +#: users/models.py:157 msgid "Permissions to edit items" msgstr "" -#: users/models.py:152 +#: users/models.py:159 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 18f86b6972..7389af937b 100644 --- a/InvenTree/locale/es/LC_MESSAGES/django.po +++ b/InvenTree/locale/es/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-01-07 23:48+1100\n" +"POT-Creation-Date: 2021-01-14 23:57+1100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -54,8 +54,8 @@ msgstr "" msgid "Select Category" msgstr "" -#: InvenTree/helpers.py:361 order/models.py:216 order/models.py:298 -#: stock/views.py:1660 +#: InvenTree/helpers.py:361 order/models.py:232 order/models.py:330 +#: stock/views.py:1573 msgid "Invalid quantity provided" msgstr "" @@ -95,11 +95,11 @@ msgstr "" msgid "File comment" msgstr "" -#: InvenTree/models.py:68 templates/js/stock.js:759 +#: InvenTree/models.py:68 templates/js/stock.js:873 msgid "User" msgstr "" -#: InvenTree/models.py:106 part/models.py:647 +#: InvenTree/models.py:106 label/models.py:68 part/models.py:647 #: part/templates/part/params.html:24 templates/js/part.js:129 msgid "Name" msgstr "" @@ -108,19 +108,19 @@ msgstr "" msgid "Description (optional)" msgstr "" -#: InvenTree/settings.py:422 +#: InvenTree/settings.py:439 msgid "English" msgstr "" -#: InvenTree/settings.py:423 +#: InvenTree/settings.py:440 msgid "German" msgstr "" -#: InvenTree/settings.py:424 +#: InvenTree/settings.py:441 msgid "French" msgstr "" -#: InvenTree/settings.py:425 +#: InvenTree/settings.py:442 msgid "Polish" msgstr "" @@ -302,7 +302,7 @@ msgstr "" #: build/forms.py:78 build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:83 -#: build/templates/build/detail.html:29 common/models.py:589 +#: build/templates/build/detail.html:29 common/models.py:596 #: company/forms.py:112 company/templates/company/supplier_part_pricing.html:75 #: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:179 @@ -315,8 +315,8 @@ msgstr "" #: stock/templates/stock/item_base.html:46 #: stock/templates/stock/item_base.html:214 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:338 -#: templates/js/bom.js:195 templates/js/build.js:420 templates/js/stock.js:750 -#: templates/js/stock.js:989 +#: templates/js/bom.js:195 templates/js/build.js:420 templates/js/stock.js:864 +#: templates/js/stock.js:1103 msgid "Quantity" msgstr "" @@ -381,7 +381,7 @@ msgstr "" #: build/models.py:62 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:11 #: order/templates/order/so_tabs.html:9 part/templates/part/tabs.html:31 -#: templates/InvenTree/settings/tabs.html:28 users/models.py:30 +#: templates/InvenTree/settings/tabs.html:28 users/models.py:32 msgid "Build Orders" msgstr "" @@ -397,15 +397,15 @@ msgstr "" #: build/models.py:116 build/templates/build/detail.html:19 #: company/models.py:359 company/templates/company/detail.html:23 #: company/templates/company/supplier_part_base.html:61 -#: company/templates/company/supplier_part_detail.html:27 +#: company/templates/company/supplier_part_detail.html:27 label/models.py:75 #: order/templates/order/purchase_order_detail.html:161 part/models.py:671 #: part/templates/part/detail.html:51 part/templates/part/set_category.html:14 #: templates/InvenTree/search.html:147 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:180 -#: templates/js/bom.js:517 templates/js/build.js:664 templates/js/company.js:56 -#: templates/js/order.js:175 templates/js/order.js:263 templates/js/part.js:188 +#: templates/js/bom.js:549 templates/js/build.js:664 templates/js/company.js:56 +#: templates/js/order.js:180 templates/js/order.js:274 templates/js/part.js:188 #: templates/js/part.js:271 templates/js/part.js:391 templates/js/part.js:572 -#: templates/js/stock.js:501 templates/js/stock.js:731 +#: templates/js/stock.js:511 templates/js/stock.js:845 msgid "Description" msgstr "" @@ -424,16 +424,16 @@ msgstr "" #: build/models.py:134 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:78 -#: build/templates/build/detail.html:24 order/models.py:623 +#: build/templates/build/detail.html:24 order/models.py:651 #: order/templates/order/order_wizard/select_parts.html:30 #: order/templates/order/purchase_order_detail.html:148 #: order/templates/order/receive_parts.html:19 part/models.py:316 #: part/templates/part/part_app_base.html:7 part/templates/part/related.html:26 #: part/templates/part/set_category.html:13 templates/InvenTree/search.html:133 -#: templates/js/barcode.js:336 templates/js/bom.js:153 templates/js/bom.js:502 +#: templates/js/barcode.js:336 templates/js/bom.js:153 templates/js/bom.js:534 #: templates/js/build.js:669 templates/js/company.js:138 -#: templates/js/part.js:252 templates/js/part.js:357 templates/js/stock.js:475 -#: templates/js/stock.js:1061 +#: templates/js/part.js:252 templates/js/part.js:357 templates/js/stock.js:485 +#: templates/js/stock.js:1175 msgid "Part" msgstr "" @@ -491,7 +491,7 @@ msgstr "" msgid "Build status code" msgstr "" -#: build/models.py:194 stock/models.py:397 +#: build/models.py:194 stock/models.py:412 msgid "Batch Code" msgstr "" @@ -499,7 +499,7 @@ msgstr "" msgid "Batch code for this build output" msgstr "" -#: build/models.py:205 order/models.py:404 +#: build/models.py:205 order/models.py:436 msgid "Target completion date" msgstr "" @@ -507,11 +507,11 @@ msgstr "" #: company/templates/company/supplier_part_base.html:68 #: company/templates/company/supplier_part_detail.html:24 #: part/templates/part/detail.html:80 part/templates/part/part_base.html:102 -#: stock/models.py:391 stock/templates/stock/item_base.html:297 +#: stock/models.py:406 stock/templates/stock/item_base.html:297 msgid "External Link" msgstr "" -#: build/models.py:220 part/models.py:705 stock/models.py:393 +#: build/models.py:220 part/models.py:705 stock/models.py:408 msgid "Link to external URL" msgstr "" @@ -520,9 +520,9 @@ msgstr "" #: order/templates/order/purchase_order_detail.html:213 #: order/templates/order/so_tabs.html:23 part/models.py:831 #: part/templates/part/tabs.html:73 stock/forms.py:313 stock/forms.py:345 -#: stock/forms.py:373 stock/models.py:463 stock/models.py:1512 +#: stock/forms.py:373 stock/models.py:478 stock/models.py:1544 #: stock/templates/stock/tabs.html:26 templates/js/barcode.js:391 -#: templates/js/bom.js:263 templates/js/stock.js:117 templates/js/stock.js:603 +#: templates/js/bom.js:295 templates/js/stock.js:127 templates/js/stock.js:618 msgid "Notes" msgstr "" @@ -564,11 +564,11 @@ msgstr "" msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:971 order/models.py:707 +#: build/models.py:971 order/models.py:735 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:975 order/models.py:710 +#: build/models.py:975 order/models.py:738 msgid "Allocation quantity must be greater than zero" msgstr "" @@ -657,7 +657,7 @@ msgstr "" #: stock/templates/stock/item_base.html:244 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:183 templates/js/barcode.js:337 -#: templates/js/build.js:434 templates/js/stock.js:587 +#: templates/js/build.js:434 templates/js/stock.js:597 msgid "Location" msgstr "" @@ -689,9 +689,12 @@ msgstr "" #: build/templates/build/build_base.html:43 #: build/templates/build/build_base.html:100 +#: order/templates/order/order_base.html:32 +#: order/templates/order/order_base.html:83 #: order/templates/order/sales_order_base.html:41 #: order/templates/order/sales_order_base.html:83 -#: templates/js/table_filters.js:200 templates/js/table_filters.js:232 +#: templates/js/table_filters.js:200 templates/js/table_filters.js:219 +#: templates/js/table_filters.js:236 msgid "Overdue" msgstr "" @@ -720,15 +723,16 @@ msgstr "" #: order/templates/order/receive_parts.html:24 #: stock/templates/stock/item_base.html:343 templates/InvenTree/search.html:175 #: templates/js/barcode.js:42 templates/js/build.js:697 -#: templates/js/order.js:180 templates/js/order.js:268 -#: templates/js/stock.js:574 templates/js/stock.js:997 +#: templates/js/order.js:185 templates/js/order.js:279 +#: templates/js/stock.js:584 templates/js/stock.js:1111 msgid "Status" msgstr "" #: build/templates/build/build_base.html:96 #: build/templates/build/detail.html:100 +#: order/templates/order/order_base.html:121 #: order/templates/order/sales_order_base.html:114 templates/js/build.js:710 -#: templates/js/order.js:281 +#: templates/js/order.js:198 templates/js/order.js:292 msgid "Target Date" msgstr "" @@ -742,13 +746,13 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:120 -#: build/templates/build/detail.html:82 order/models.py:621 +#: build/templates/build/detail.html:82 order/models.py:649 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:33 #: order/templates/order/sales_order_notes.html:10 #: order/templates/order/sales_order_ship.html:25 #: part/templates/part/allocation.html:27 -#: stock/templates/stock/item_base.html:238 templates/js/order.js:229 +#: stock/templates/stock/item_base.html:238 templates/js/order.js:240 msgid "Sales Order" msgstr "" @@ -849,14 +853,14 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:68 -#: stock/templates/stock/item_base.html:262 templates/js/stock.js:582 -#: templates/js/stock.js:1004 templates/js/table_filters.js:80 +#: stock/templates/stock/item_base.html:262 templates/js/stock.js:592 +#: templates/js/stock.js:1118 templates/js/table_filters.js:80 #: templates/js/table_filters.js:161 msgid "Batch" msgstr "" #: build/templates/build/detail.html:95 -#: order/templates/order/order_base.html:98 +#: order/templates/order/order_base.html:108 #: order/templates/order/sales_order_base.html:108 templates/js/build.js:705 msgid "Created" msgstr "" @@ -949,7 +953,7 @@ msgstr "" msgid "Create Build Output" msgstr "" -#: build/views.py:207 stock/models.py:872 stock/views.py:1681 +#: build/views.py:207 stock/models.py:887 stock/views.py:1594 msgid "Serial numbers already exist" msgstr "" @@ -965,7 +969,7 @@ msgstr "" msgid "Confirm unallocation of build stock" msgstr "" -#: build/views.py:303 build/views.py:388 stock/views.py:417 +#: build/views.py:303 build/views.py:388 stock/views.py:330 msgid "Check the confirmation box" msgstr "" @@ -1059,7 +1063,7 @@ msgid "Add Build Order Attachment" msgstr "" #: build/views.py:1060 order/views.py:113 order/views.py:166 part/views.py:170 -#: stock/views.py:180 +#: stock/views.py:179 msgid "Added attachment" msgstr "" @@ -1075,7 +1079,7 @@ msgstr "" msgid "Delete Attachment" msgstr "" -#: build/views.py:1123 order/views.py:242 order/views.py:257 stock/views.py:238 +#: build/views.py:1123 order/views.py:242 order/views.py:257 stock/views.py:237 msgid "Deleted attachment" msgstr "" @@ -1152,7 +1156,7 @@ msgid "Copy category parameter templates when creating a part" msgstr "" #: common/models.py:115 part/templates/part/detail.html:155 stock/forms.py:255 -#: templates/js/table_filters.js:23 templates/js/table_filters.js:266 +#: templates/js/table_filters.js:23 templates/js/table_filters.js:270 msgid "Template" msgstr "" @@ -1161,7 +1165,7 @@ msgid "Parts are templates by default" msgstr "" #: common/models.py:122 part/models.py:794 part/templates/part/detail.html:165 -#: templates/js/table_filters.js:278 +#: templates/js/table_filters.js:282 msgid "Assembly" msgstr "" @@ -1170,7 +1174,7 @@ msgid "Parts can be assembled from other components by default" msgstr "" #: common/models.py:129 part/models.py:800 part/templates/part/detail.html:175 -#: templates/js/table_filters.js:282 +#: templates/js/table_filters.js:286 msgid "Component" msgstr "" @@ -1187,7 +1191,7 @@ msgid "Parts are purchaseable by default" msgstr "" #: common/models.py:143 part/models.py:816 part/templates/part/detail.html:205 -#: templates/js/table_filters.js:290 +#: templates/js/table_filters.js:294 msgid "Salable" msgstr "" @@ -1196,7 +1200,7 @@ msgid "Parts are salable by default" msgstr "" #: common/models.py:150 part/models.py:806 part/templates/part/detail.html:185 -#: templates/js/table_filters.js:31 templates/js/table_filters.js:294 +#: templates/js/table_filters.js:31 templates/js/table_filters.js:298 msgid "Trackable" msgstr "" @@ -1214,107 +1218,115 @@ msgid "Parts are virtual by default" msgstr "" #: common/models.py:164 -msgid "Stock Expiry" +msgid "Show Quantity in Forms" msgstr "" #: common/models.py:165 -msgid "Enable stock expiry functionality" +msgid "Display available part quantity in some forms" msgstr "" #: common/models.py:171 -msgid "Sell Expired Stock" +msgid "Stock Expiry" msgstr "" #: common/models.py:172 -msgid "Allow sale of expired stock" +msgid "Enable stock expiry functionality" msgstr "" #: common/models.py:178 -msgid "Stock Stale Time" +msgid "Sell Expired Stock" msgstr "" #: common/models.py:179 -msgid "Number of days stock items are considered stale before expiring" +msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:181 part/templates/part/detail.html:116 -msgid "days" +#: common/models.py:185 +msgid "Stock Stale Time" msgstr "" #: common/models.py:186 -msgid "Build Expired Stock" +msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:187 -msgid "Allow building with expired stock" +#: common/models.py:188 part/templates/part/detail.html:116 +msgid "days" msgstr "" #: common/models.py:193 -msgid "Build Order Reference Prefix" +msgid "Build Expired Stock" msgstr "" #: common/models.py:194 -msgid "Prefix value for build order reference" -msgstr "" - -#: common/models.py:199 -msgid "Build Order Reference Regex" +msgid "Allow building with expired stock" msgstr "" #: common/models.py:200 +msgid "Build Order Reference Prefix" +msgstr "" + +#: common/models.py:201 +msgid "Prefix value for build order reference" +msgstr "" + +#: common/models.py:206 +msgid "Build Order Reference Regex" +msgstr "" + +#: common/models.py:207 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:204 +#: common/models.py:211 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:205 +#: common/models.py:212 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:210 +#: common/models.py:217 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:211 +#: common/models.py:218 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:434 +#: common/models.py:441 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:436 +#: common/models.py:443 msgid "Settings value" msgstr "" -#: common/models.py:493 +#: common/models.py:500 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:503 +#: common/models.py:510 msgid "Value must be an integer value" msgstr "" -#: common/models.py:517 +#: common/models.py:524 msgid "Key string must be unique" msgstr "" -#: common/models.py:590 company/forms.py:113 +#: common/models.py:597 company/forms.py:113 msgid "Price break quantity" msgstr "" -#: common/models.py:598 company/templates/company/supplier_part_pricing.html:80 +#: common/models.py:605 company/templates/company/supplier_part_pricing.html:80 #: part/templates/part/sale_prices.html:87 templates/js/bom.js:246 msgid "Price" msgstr "" -#: common/models.py:599 +#: common/models.py:606 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:622 +#: common/models.py:629 msgid "Default" msgstr "" @@ -1415,7 +1427,7 @@ msgstr "" msgid "Currency" msgstr "" -#: company/models.py:313 stock/models.py:345 +#: company/models.py:313 stock/models.py:360 #: stock/templates/stock/item_base.html:194 msgid "Base Part" msgstr "" @@ -1427,10 +1439,10 @@ msgstr "" #: company/models.py:323 company/templates/company/detail.html:57 #: company/templates/company/supplier_part_base.html:74 #: company/templates/company/supplier_part_detail.html:21 -#: order/templates/order/order_base.html:79 +#: order/templates/order/order_base.html:89 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:170 #: stock/templates/stock/item_base.html:304 templates/js/company.js:48 -#: templates/js/company.js:164 templates/js/order.js:162 +#: templates/js/company.js:164 templates/js/order.js:167 msgid "Supplier" msgstr "" @@ -1525,9 +1537,9 @@ msgid "Uses default currency" msgstr "" #: company/templates/company/detail.html:62 -#: order/templates/order/sales_order_base.html:89 stock/models.py:380 -#: stock/models.py:381 stock/templates/stock/item_base.html:221 -#: templates/js/company.js:40 templates/js/order.js:250 +#: order/templates/order/sales_order_base.html:89 stock/models.py:395 +#: stock/models.py:396 stock/templates/stock/item_base.html:221 +#: templates/js/company.js:40 templates/js/order.js:261 msgid "Customer" msgstr "" @@ -1542,7 +1554,7 @@ msgstr "" #: company/templates/company/detail_part.html:18 #: order/templates/order/purchase_order_detail.html:68 -#: part/templates/part/supplier.html:14 templates/js/stock.js:881 +#: part/templates/part/supplier.html:14 templates/js/stock.js:995 msgid "New Supplier Part" msgstr "" @@ -1566,7 +1578,7 @@ msgid "Delete Parts" msgstr "" #: company/templates/company/detail_part.html:63 -#: part/templates/part/category.html:116 templates/js/stock.js:875 +#: part/templates/part/category.html:116 templates/js/stock.js:989 msgid "New Part" msgstr "" @@ -1623,7 +1635,7 @@ msgstr "" #: order/templates/order/purchase_orders.html:13 #: part/templates/part/orders.html:9 part/templates/part/tabs.html:48 #: templates/InvenTree/settings/tabs.html:31 templates/navbar.html:33 -#: users/models.py:31 +#: users/models.py:33 msgid "Purchase Orders" msgstr "" @@ -1643,7 +1655,7 @@ msgstr "" #: order/templates/order/sales_orders.html:13 #: part/templates/part/sales_orders.html:9 part/templates/part/tabs.html:56 #: templates/InvenTree/settings/tabs.html:34 templates/navbar.html:42 -#: users/models.py:32 +#: users/models.py:34 msgid "Sales Orders" msgstr "" @@ -1658,7 +1670,7 @@ msgid "New Sales Order" msgstr "" #: company/templates/company/supplier_part_base.html:6 -#: company/templates/company/supplier_part_base.html:19 stock/models.py:354 +#: company/templates/company/supplier_part_base.html:19 stock/models.py:369 #: stock/templates/stock/item_base.html:309 templates/js/company.js:180 msgid "Supplier Part" msgstr "" @@ -1731,8 +1743,7 @@ msgstr "" #: company/templates/company/tabs.html:12 part/templates/part/tabs.html:18 #: stock/templates/stock/location.html:17 templates/InvenTree/search.html:155 #: templates/InvenTree/settings/tabs.html:25 templates/js/part.js:192 -#: templates/js/part.js:418 templates/js/stock.js:509 templates/navbar.html:22 -#: users/models.py:29 +#: templates/js/part.js:418 templates/js/stock.js:519 templates/navbar.html:22 msgid "Stock" msgstr "" @@ -1745,7 +1756,7 @@ msgstr "" #: part/templates/part/cat_link.html:7 part/templates/part/category.html:94 #: part/templates/part/category_tabs.html:6 #: templates/InvenTree/settings/tabs.html:22 templates/navbar.html:19 -#: templates/stats.html:35 templates/stats.html:44 users/models.py:28 +#: templates/stats.html:35 templates/stats.html:44 users/models.py:29 msgid "Parts" msgstr "" @@ -1814,7 +1825,7 @@ msgstr "" msgid "Edit Supplier Part" msgstr "" -#: company/views.py:295 templates/js/stock.js:882 +#: company/views.py:295 templates/js/stock.js:996 msgid "Create new Supplier Part" msgstr "" @@ -1834,39 +1845,59 @@ msgstr "" msgid "Delete Price Break" msgstr "" -#: label/models.py:55 -msgid "Label name" +#: label/api.py:171 +msgid "Must provide valid StockItem(s)" msgstr "" -#: label/models.py:58 -msgid "Label description" +#: label/api.py:185 label/api.py:337 +msgid "Error during label rendering" msgstr "" -#: label/models.py:63 -msgid "Label template file" +#: label/api.py:324 +msgid "Must provide valid StockLocation(s)" msgstr "" #: label/models.py:69 -msgid "Query filters (comma-separated list of key=value pairs" +msgid "Label name" msgstr "" -#: label/models.py:75 -msgid "Label template is enabled" +#: label/models.py:76 +msgid "Label description" msgstr "" -#: label/models.py:76 report/models.py:162 +#: label/models.py:83 stock/forms.py:198 +msgid "Label" +msgstr "" + +#: label/models.py:84 +msgid "Label template file" +msgstr "" + +#: label/models.py:90 report/models.py:162 msgid "Enabled" msgstr "" -#: order/forms.py:25 order/templates/order/order_base.html:39 +#: label/models.py:91 +msgid "Label template is enabled" +msgstr "" + +#: label/models.py:137 label/models.py:190 +msgid "Query filters (comma-separated list of key=value pairs" +msgstr "" + +#: label/models.py:138 label/models.py:191 +msgid "Filters" +msgstr "" + +#: order/forms.py:25 order/templates/order/order_base.html:44 msgid "Place order" msgstr "" -#: order/forms.py:36 order/templates/order/order_base.html:46 +#: order/forms.py:36 order/templates/order/order_base.html:51 msgid "Mark order as complete" msgstr "" -#: order/forms.py:47 order/forms.py:58 order/templates/order/order_base.html:51 +#: order/forms.py:47 order/forms.py:58 order/templates/order/order_base.html:56 #: order/templates/order/sales_order_base.html:56 msgid "Cancel order" msgstr "" @@ -1879,15 +1910,19 @@ msgstr "" msgid "Receive parts to this location" msgstr "" -#: order/forms.py:100 +#: order/forms.py:101 msgid "Purchase Order reference" msgstr "" -#: order/forms.py:128 +#: order/forms.py:107 +msgid "Target date for order delivery. Order will be overdue after this date." +msgstr "" + +#: order/forms.py:134 msgid "Enter sales order number" msgstr "" -#: order/forms.py:134 order/models.py:405 +#: order/forms.py:140 order/models.py:437 msgid "" "Target date for order completion. Order will be overdue after this date." msgstr "" @@ -1908,107 +1943,124 @@ msgstr "" msgid "Order notes" msgstr "" -#: order/models.py:169 order/models.py:398 +#: order/models.py:171 order/models.py:430 msgid "Purchase order status" msgstr "" -#: order/models.py:177 +#: order/models.py:179 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:180 +#: order/models.py:182 msgid "Supplier order reference code" msgstr "" -#: order/models.py:189 +#: order/models.py:193 +msgid "Issue Date" +msgstr "" + +#: order/models.py:194 msgid "Date order was issued" msgstr "" -#: order/models.py:191 +#: order/models.py:199 +msgid "Target Delivery Date" +msgstr "" + +#: order/models.py:200 +msgid "" +"Expected date for order delivery. Order will be overdue after this date." +msgstr "" + +#: order/models.py:205 +msgid "Completion Date" +msgstr "" + +#: order/models.py:206 msgid "Date order was completed" msgstr "" -#: order/models.py:214 order/models.py:296 part/views.py:1504 -#: stock/models.py:251 stock/models.py:856 +#: order/models.py:230 order/models.py:328 part/views.py:1504 +#: stock/models.py:259 stock/models.py:871 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:219 +#: order/models.py:235 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:291 +#: order/models.py:323 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:394 +#: order/models.py:426 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:400 +#: order/models.py:432 msgid "Customer order reference code" msgstr "" -#: order/models.py:462 +#: order/models.py:490 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:549 +#: order/models.py:577 msgid "Item quantity" msgstr "" -#: order/models.py:551 +#: order/models.py:579 msgid "Line item reference" msgstr "" -#: order/models.py:553 +#: order/models.py:581 msgid "Line item notes" msgstr "" -#: order/models.py:579 order/templates/order/order_base.html:9 +#: order/models.py:607 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 -#: stock/templates/stock/item_base.html:276 templates/js/order.js:146 +#: stock/templates/stock/item_base.html:276 templates/js/order.js:145 msgid "Purchase Order" msgstr "" -#: order/models.py:592 +#: order/models.py:620 msgid "Supplier part" msgstr "" -#: order/models.py:595 +#: order/models.py:623 msgid "Number of items received" msgstr "" -#: order/models.py:602 stock/models.py:473 +#: order/models.py:630 stock/models.py:488 #: stock/templates/stock/item_base.html:283 msgid "Purchase Price" msgstr "" -#: order/models.py:603 +#: order/models.py:631 msgid "Unit purchase price" msgstr "" -#: order/models.py:698 +#: order/models.py:726 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:700 +#: order/models.py:728 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:703 +#: order/models.py:731 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:713 +#: order/models.py:741 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:729 +#: order/models.py:757 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:732 +#: order/models.py:760 msgid "Enter stock allocation quantity" msgstr "" @@ -2018,41 +2070,41 @@ msgstr "" msgid "Are you sure you want to delete this attachment?" msgstr "" -#: order/templates/order/order_base.html:35 +#: order/templates/order/order_base.html:40 msgid "Edit order information" msgstr "" -#: order/templates/order/order_base.html:43 +#: order/templates/order/order_base.html:48 msgid "Receive items" msgstr "" -#: order/templates/order/order_base.html:56 +#: order/templates/order/order_base.html:61 msgid "Export order to file" msgstr "" -#: order/templates/order/order_base.html:64 +#: order/templates/order/order_base.html:69 msgid "Purchase Order Details" msgstr "" -#: order/templates/order/order_base.html:69 +#: order/templates/order/order_base.html:74 #: order/templates/order/sales_order_base.html:74 msgid "Order Reference" msgstr "" -#: order/templates/order/order_base.html:74 +#: order/templates/order/order_base.html:79 #: order/templates/order/sales_order_base.html:79 msgid "Order Status" msgstr "" -#: order/templates/order/order_base.html:85 templates/js/order.js:169 +#: order/templates/order/order_base.html:95 templates/js/order.js:175 msgid "Supplier Reference" msgstr "" -#: order/templates/order/order_base.html:104 +#: order/templates/order/order_base.html:114 msgid "Issued" msgstr "" -#: order/templates/order/order_base.html:111 +#: order/templates/order/order_base.html:128 #: order/templates/order/purchase_order_detail.html:193 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:128 @@ -2100,7 +2152,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "" #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:193 templates/js/order.js:291 +#: templates/js/order.js:203 templates/js/order.js:302 msgid "Items" msgstr "" @@ -2138,7 +2190,7 @@ msgstr "" #: order/templates/order/purchase_order_detail.html:39 #: order/templates/order/purchase_order_detail.html:119 #: part/templates/part/category.html:173 part/templates/part/category.html:215 -#: templates/js/stock.js:627 templates/js/stock.js:887 +#: templates/js/stock.js:642 templates/js/stock.js:1001 msgid "New Location" msgstr "" @@ -2207,7 +2259,7 @@ msgstr "" msgid "Sales Order Details" msgstr "" -#: order/templates/order/sales_order_base.html:95 templates/js/order.js:257 +#: order/templates/order/sales_order_base.html:95 templates/js/order.js:268 msgid "Customer Reference" msgstr "" @@ -2223,7 +2275,7 @@ msgid "Sales Order Items" msgstr "" #: order/templates/order/sales_order_detail.html:72 -#: order/templates/order/sales_order_detail.html:154 stock/models.py:385 +#: order/templates/order/sales_order_detail.html:154 stock/models.py:400 #: stock/templates/stock/item_base.html:208 templates/js/build.js:418 msgid "Serial Number" msgstr "" @@ -2334,18 +2386,14 @@ msgstr "" msgid "Confirm order cancellation" msgstr "" -#: order/views.py:435 -msgid "Order cannot be cancelled as either pending or placed" +#: order/views.py:435 order/views.py:462 +msgid "Order cannot be cancelled" msgstr "" #: order/views.py:449 msgid "Cancel sales order" msgstr "" -#: order/views.py:462 -msgid "Order cannot be cancelled" -msgstr "" - #: order/views.py:476 msgid "Issue Order" msgstr "" @@ -2460,123 +2508,123 @@ msgstr "" msgid "Error reading BOM file (incorrect row size)" msgstr "" -#: part/forms.py:61 stock/forms.py:261 +#: part/forms.py:71 stock/forms.py:261 msgid "File Format" msgstr "" -#: part/forms.py:61 stock/forms.py:261 +#: part/forms.py:71 stock/forms.py:261 msgid "Select output file format" msgstr "" -#: part/forms.py:63 +#: part/forms.py:73 msgid "Cascading" msgstr "" -#: part/forms.py:63 +#: part/forms.py:73 msgid "Download cascading / multi-level BOM" msgstr "" -#: part/forms.py:65 +#: part/forms.py:75 msgid "Levels" msgstr "" -#: part/forms.py:65 +#: part/forms.py:75 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "" -#: part/forms.py:67 +#: part/forms.py:77 msgid "Include Parameter Data" msgstr "" -#: part/forms.py:67 +#: part/forms.py:77 msgid "Include part parameters data in exported BOM" msgstr "" -#: part/forms.py:69 +#: part/forms.py:79 msgid "Include Stock Data" msgstr "" -#: part/forms.py:69 +#: part/forms.py:79 msgid "Include part stock data in exported BOM" msgstr "" -#: part/forms.py:71 +#: part/forms.py:81 msgid "Include Supplier Data" msgstr "" -#: part/forms.py:71 +#: part/forms.py:81 msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:92 part/models.py:1781 +#: part/forms.py:102 part/models.py:1781 msgid "Parent Part" msgstr "" -#: part/forms.py:93 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:103 part/templates/part/bom_duplicate.html:7 msgid "Select parent part to copy BOM from" msgstr "" -#: part/forms.py:99 +#: part/forms.py:109 msgid "Clear existing BOM items" msgstr "" -#: part/forms.py:104 +#: part/forms.py:114 msgid "Confirm BOM duplication" msgstr "" -#: part/forms.py:122 +#: part/forms.py:132 msgid "Confirm that the BOM is correct" msgstr "" -#: part/forms.py:134 +#: part/forms.py:144 msgid "Select BOM file to upload" msgstr "" -#: part/forms.py:153 +#: part/forms.py:163 msgid "Related Part" msgstr "" -#: part/forms.py:172 +#: part/forms.py:182 msgid "Select part category" msgstr "" -#: part/forms.py:189 +#: part/forms.py:199 msgid "Duplicate all BOM data for this part" msgstr "" -#: part/forms.py:190 +#: part/forms.py:200 msgid "Copy BOM" msgstr "" -#: part/forms.py:195 +#: part/forms.py:205 msgid "Duplicate all parameter data for this part" msgstr "" -#: part/forms.py:196 +#: part/forms.py:206 msgid "Copy Parameters" msgstr "" -#: part/forms.py:201 +#: part/forms.py:211 msgid "Confirm part creation" msgstr "" -#: part/forms.py:206 +#: part/forms.py:216 msgid "Include category parameter templates" msgstr "" -#: part/forms.py:211 +#: part/forms.py:221 msgid "Include parent categories parameter templates" msgstr "" -#: part/forms.py:291 +#: part/forms.py:301 msgid "Add parameter template to same level categories" msgstr "" -#: part/forms.py:295 +#: part/forms.py:305 msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:339 +#: part/forms.py:349 msgid "Input quantity for price calculation" msgstr "" @@ -2595,6 +2643,7 @@ msgstr "" #: part/models.py:78 part/templates/part/category.html:18 #: part/templates/part/category.html:89 templates/stats.html:39 +#: users/models.py:28 msgid "Part Categories" msgstr "" @@ -2742,7 +2791,7 @@ msgstr "" #: part/models.py:821 part/templates/part/detail.html:222 #: templates/js/table_filters.js:19 templates/js/table_filters.js:55 -#: templates/js/table_filters.js:196 templates/js/table_filters.js:261 +#: templates/js/table_filters.js:196 templates/js/table_filters.js:265 msgid "Active" msgstr "" @@ -2770,7 +2819,7 @@ msgstr "" msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:1690 templates/js/part.js:567 templates/js/stock.js:93 +#: part/models.py:1690 templates/js/part.js:567 templates/js/stock.js:103 msgid "Test Name" msgstr "" @@ -2869,7 +2918,7 @@ msgid "BOM line checksum" msgstr "" #: part/models.py:1963 part/views.py:1510 part/views.py:1562 -#: stock/models.py:241 +#: stock/models.py:249 msgid "Quantity must be integer value for trackable parts" msgstr "" @@ -2881,11 +2930,11 @@ msgstr "" msgid "BOM Item" msgstr "" -#: part/models.py:2092 +#: part/models.py:2098 msgid "Select Related Part" msgstr "" -#: part/models.py:2124 +#: part/models.py:2130 msgid "" "Error creating relationship: check that the part is not related to itself " "and that the relationship is unique" @@ -2908,7 +2957,7 @@ msgstr "" #: stock/templates/stock/item_base.html:72 #: stock/templates/stock/item_base.html:291 #: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:751 -#: templates/js/stock.js:720 templates/js/stock.js:980 +#: templates/js/stock.js:834 templates/js/stock.js:1094 msgid "Stock Item" msgstr "" @@ -3125,7 +3174,7 @@ msgstr "" msgid "Export Data" msgstr "" -#: part/templates/part/category.html:174 templates/js/stock.js:628 +#: part/templates/part/category.html:174 templates/js/stock.js:643 msgid "Create new location" msgstr "" @@ -3141,7 +3190,7 @@ msgstr "" msgid "Create new Part Category" msgstr "" -#: part/templates/part/category.html:216 stock/views.py:1363 +#: part/templates/part/category.html:216 stock/views.py:1276 msgid "Create new Stock Location" msgstr "" @@ -3177,7 +3226,7 @@ msgstr "" msgid "Stock Expiry Time" msgstr "" -#: part/templates/part/detail.html:121 templates/js/order.js:276 +#: part/templates/part/detail.html:121 templates/js/order.js:287 msgid "Creation Date" msgstr "" @@ -3263,17 +3312,17 @@ msgstr "" #: part/templates/part/params.html:15 #: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:41 +#: templates/InvenTree/settings/part.html:42 msgid "New Parameter" msgstr "" -#: part/templates/part/params.html:25 stock/models.py:1499 -#: templates/InvenTree/settings/header.html:8 templates/js/stock.js:113 +#: part/templates/part/params.html:25 stock/models.py:1531 +#: templates/InvenTree/settings/header.html:8 templates/js/stock.js:123 msgid "Value" msgstr "" #: part/templates/part/params.html:41 part/templates/part/related.html:41 -#: part/templates/part/supplier.html:19 users/models.py:152 +#: part/templates/part/supplier.html:19 users/models.py:159 msgid "Delete" msgstr "" @@ -3356,7 +3405,7 @@ msgstr "" msgid "Allocated to Sales Orders" msgstr "" -#: part/templates/part/part_base.html:160 +#: part/templates/part/part_base.html:160 templates/js/bom.js:262 msgid "Can Build" msgstr "" @@ -3546,7 +3595,7 @@ msgstr "" msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:594 templates/js/stock.js:876 +#: part/views.py:594 templates/js/stock.js:990 msgid "Create New Part" msgstr "" @@ -3730,10 +3779,6 @@ msgstr "" msgid "Enter unique serial numbers (or leave blank)" msgstr "" -#: stock/forms.py:198 -msgid "Label" -msgstr "" - #: stock/forms.py:199 stock/forms.py:255 msgid "Select test report template" msgstr "" @@ -3778,7 +3823,7 @@ msgstr "" msgid "Add note (required)" msgstr "" -#: stock/forms.py:377 stock/views.py:935 stock/views.py:1133 +#: stock/forms.py:377 stock/views.py:848 stock/views.py:1046 msgid "Confirm stock adjustment" msgstr "" @@ -3794,237 +3839,237 @@ msgstr "" msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:186 +#: stock/models.py:194 msgid "Created stock item" msgstr "" -#: stock/models.py:222 +#: stock/models.py:230 msgid "StockItem with this serial number already exists" msgstr "" -#: stock/models.py:258 +#: stock/models.py:266 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:268 stock/models.py:277 +#: stock/models.py:276 stock/models.py:285 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:269 +#: stock/models.py:277 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:291 +#: stock/models.py:299 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:297 +#: stock/models.py:305 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:304 +#: stock/models.py:312 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:337 +#: stock/models.py:352 msgid "Parent Stock Item" msgstr "" -#: stock/models.py:346 +#: stock/models.py:361 msgid "Base part" msgstr "" -#: stock/models.py:355 +#: stock/models.py:370 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:360 stock/templates/stock/stock_app_base.html:7 +#: stock/models.py:375 stock/templates/stock/stock_app_base.html:7 msgid "Stock Location" msgstr "" -#: stock/models.py:363 +#: stock/models.py:378 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:368 stock/templates/stock/item_base.html:229 +#: stock/models.py:383 stock/templates/stock/item_base.html:229 msgid "Installed In" msgstr "" -#: stock/models.py:371 +#: stock/models.py:386 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:387 +#: stock/models.py:402 msgid "Serial number for this item" msgstr "" -#: stock/models.py:399 +#: stock/models.py:414 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:403 +#: stock/models.py:418 msgid "Stock Quantity" msgstr "" -#: stock/models.py:412 +#: stock/models.py:427 msgid "Source Build" msgstr "" -#: stock/models.py:414 +#: stock/models.py:429 msgid "Build for this stock item" msgstr "" -#: stock/models.py:425 +#: stock/models.py:440 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:428 +#: stock/models.py:443 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:434 +#: stock/models.py:449 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:440 stock/templates/stock/item_base.html:316 -#: templates/js/stock.js:597 +#: stock/models.py:455 stock/templates/stock/item_base.html:316 +#: templates/js/stock.js:612 msgid "Expiry Date" msgstr "" -#: stock/models.py:441 +#: stock/models.py:456 msgid "" "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:454 +#: stock/models.py:469 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:464 stock/templates/stock/item_notes.html:14 +#: stock/models.py:479 stock/templates/stock/item_notes.html:14 #: stock/templates/stock/item_notes.html:30 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:474 +#: stock/models.py:489 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:574 +#: stock/models.py:589 msgid "Assigned to Customer" msgstr "" -#: stock/models.py:576 +#: stock/models.py:591 msgid "Manually assigned to customer" msgstr "" -#: stock/models.py:589 +#: stock/models.py:604 msgid "Returned from customer" msgstr "" -#: stock/models.py:591 +#: stock/models.py:606 msgid "Returned to location" msgstr "" -#: stock/models.py:716 +#: stock/models.py:731 msgid "Installed into stock item" msgstr "" -#: stock/models.py:724 +#: stock/models.py:739 msgid "Installed stock item" msgstr "" -#: stock/models.py:748 +#: stock/models.py:763 msgid "Uninstalled stock item" msgstr "" -#: stock/models.py:767 +#: stock/models.py:782 msgid "Uninstalled into location" msgstr "" -#: stock/models.py:847 +#: stock/models.py:862 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:853 +#: stock/models.py:868 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:859 +#: stock/models.py:874 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:862 +#: stock/models.py:877 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:865 +#: stock/models.py:880 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:897 +#: stock/models.py:912 msgid "Add serial number" msgstr "" -#: stock/models.py:900 +#: stock/models.py:915 #, python-brace-format msgid "Serialized {n} items" msgstr "" -#: stock/models.py:1011 +#: stock/models.py:1026 msgid "StockItem cannot be moved as it is not in stock" msgstr "" -#: stock/models.py:1400 +#: stock/models.py:1432 msgid "Tracking entry title" msgstr "" -#: stock/models.py:1402 +#: stock/models.py:1434 msgid "Entry notes" msgstr "" -#: stock/models.py:1404 +#: stock/models.py:1436 msgid "Link to external page for further information" msgstr "" -#: stock/models.py:1464 +#: stock/models.py:1496 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1470 +#: stock/models.py:1502 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1487 +#: stock/models.py:1519 msgid "Test" msgstr "" -#: stock/models.py:1488 +#: stock/models.py:1520 msgid "Test name" msgstr "" -#: stock/models.py:1493 +#: stock/models.py:1525 msgid "Result" msgstr "" -#: stock/models.py:1494 templates/js/table_filters.js:172 +#: stock/models.py:1526 templates/js/table_filters.js:172 msgid "Test result" msgstr "" -#: stock/models.py:1500 +#: stock/models.py:1532 msgid "Test output value" msgstr "" -#: stock/models.py:1506 +#: stock/models.py:1538 msgid "Attachment" msgstr "" -#: stock/models.py:1507 +#: stock/models.py:1539 msgid "Test result attachment" msgstr "" -#: stock/models.py:1513 +#: stock/models.py:1545 msgid "Test notes" msgstr "" @@ -4108,15 +4153,15 @@ msgid "Stock adjustment actions" msgstr "" #: stock/templates/stock/item_base.html:141 -#: stock/templates/stock/location.html:41 templates/stock_table.html:23 +#: stock/templates/stock/location.html:41 templates/stock_table.html:24 msgid "Count stock" msgstr "" -#: stock/templates/stock/item_base.html:142 templates/stock_table.html:21 +#: stock/templates/stock/item_base.html:142 templates/stock_table.html:22 msgid "Add stock" msgstr "" -#: stock/templates/stock/item_base.html:143 templates/stock_table.html:22 +#: stock/templates/stock/item_base.html:143 templates/stock_table.html:23 msgid "Remove stock" msgstr "" @@ -4136,7 +4181,7 @@ msgstr "" msgid "Return to stock" msgstr "" -#: stock/templates/stock/item_base.html:158 templates/js/stock.js:1017 +#: stock/templates/stock/item_base.html:158 templates/js/stock.js:1131 msgid "Uninstall stock item" msgstr "" @@ -4266,47 +4311,48 @@ msgstr "" msgid "Check-in Items" msgstr "" -#: stock/templates/stock/location.html:45 +#: stock/templates/stock/location.html:47 msgid "Location actions" msgstr "" -#: stock/templates/stock/location.html:47 +#: stock/templates/stock/location.html:49 msgid "Edit location" msgstr "" -#: stock/templates/stock/location.html:49 +#: stock/templates/stock/location.html:51 msgid "Delete location" msgstr "" -#: stock/templates/stock/location.html:59 +#: stock/templates/stock/location.html:61 msgid "Location Details" msgstr "" -#: stock/templates/stock/location.html:64 +#: stock/templates/stock/location.html:66 msgid "Location Path" msgstr "" -#: stock/templates/stock/location.html:69 +#: stock/templates/stock/location.html:71 msgid "Location Description" msgstr "" -#: stock/templates/stock/location.html:74 +#: stock/templates/stock/location.html:76 msgid "Sublocations" msgstr "" -#: stock/templates/stock/location.html:79 -#: stock/templates/stock/location.html:94 +#: stock/templates/stock/location.html:81 +#: stock/templates/stock/location.html:96 #: templates/InvenTree/search_stock_items.html:6 templates/stats.html:48 -#: templates/stats.html:57 +#: templates/stats.html:57 users/models.py:31 msgid "Stock Items" msgstr "" -#: stock/templates/stock/location.html:84 +#: stock/templates/stock/location.html:86 msgid "Stock Details" msgstr "" -#: stock/templates/stock/location.html:89 +#: stock/templates/stock/location.html:91 #: templates/InvenTree/search_stock_location.html:6 templates/stats.html:52 +#: users/models.py:30 msgid "Stock Locations" msgstr "" @@ -4318,7 +4364,7 @@ msgstr "" msgid "The following stock items will be uninstalled" msgstr "" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1335 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1248 msgid "Convert Stock Item" msgstr "" @@ -4350,205 +4396,197 @@ msgstr "" msgid "Installed Items" msgstr "" -#: stock/views.py:123 +#: stock/views.py:122 msgid "Edit Stock Location" msgstr "" -#: stock/views.py:148 +#: stock/views.py:147 msgid "Stock Location QR code" msgstr "" -#: stock/views.py:167 +#: stock/views.py:166 msgid "Add Stock Item Attachment" msgstr "" -#: stock/views.py:214 +#: stock/views.py:213 msgid "Edit Stock Item Attachment" msgstr "" -#: stock/views.py:231 +#: stock/views.py:230 msgid "Delete Stock Item Attachment" msgstr "" -#: stock/views.py:248 +#: stock/views.py:247 msgid "Assign to Customer" msgstr "" -#: stock/views.py:258 +#: stock/views.py:257 msgid "Customer must be specified" msgstr "" -#: stock/views.py:282 +#: stock/views.py:281 msgid "Return to Stock" msgstr "" -#: stock/views.py:292 +#: stock/views.py:291 msgid "Specify a valid location" msgstr "" -#: stock/views.py:303 +#: stock/views.py:302 msgid "Stock item returned from customer" msgstr "" #: stock/views.py:313 -msgid "Select Label Template" -msgstr "" - -#: stock/views.py:336 -msgid "Select valid label" -msgstr "" - -#: stock/views.py:400 msgid "Delete All Test Data" msgstr "" -#: stock/views.py:416 +#: stock/views.py:329 msgid "Confirm test data deletion" msgstr "" -#: stock/views.py:436 +#: stock/views.py:349 msgid "Add Test Result" msgstr "" -#: stock/views.py:477 +#: stock/views.py:390 msgid "Edit Test Result" msgstr "" -#: stock/views.py:495 +#: stock/views.py:408 msgid "Delete Test Result" msgstr "" -#: stock/views.py:507 +#: stock/views.py:420 msgid "Select Test Report Template" msgstr "" -#: stock/views.py:537 +#: stock/views.py:450 msgid "Select valid template" msgstr "" -#: stock/views.py:590 +#: stock/views.py:503 msgid "Stock Export Options" msgstr "" -#: stock/views.py:712 +#: stock/views.py:625 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:738 +#: stock/views.py:651 msgid "Install Stock Item" msgstr "" -#: stock/views.py:838 +#: stock/views.py:751 msgid "Uninstall Stock Items" msgstr "" -#: stock/views.py:946 +#: stock/views.py:859 msgid "Uninstalled stock items" msgstr "" -#: stock/views.py:971 +#: stock/views.py:884 msgid "Adjust Stock" msgstr "" -#: stock/views.py:1081 +#: stock/views.py:994 msgid "Move Stock Items" msgstr "" -#: stock/views.py:1082 +#: stock/views.py:995 msgid "Count Stock Items" msgstr "" -#: stock/views.py:1083 +#: stock/views.py:996 msgid "Remove From Stock" msgstr "" -#: stock/views.py:1084 +#: stock/views.py:997 msgid "Add Stock Items" msgstr "" -#: stock/views.py:1085 +#: stock/views.py:998 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:1113 +#: stock/views.py:1026 msgid "Must enter integer value" msgstr "" -#: stock/views.py:1118 +#: stock/views.py:1031 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:1125 +#: stock/views.py:1038 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:1204 +#: stock/views.py:1117 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:1219 +#: stock/views.py:1132 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:1232 +#: stock/views.py:1145 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:1260 +#: stock/views.py:1173 msgid "No items were moved" msgstr "" -#: stock/views.py:1263 +#: stock/views.py:1176 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:1282 +#: stock/views.py:1195 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:1294 +#: stock/views.py:1207 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:1385 +#: stock/views.py:1298 msgid "Serialize Stock" msgstr "" -#: stock/views.py:1479 templates/js/build.js:210 +#: stock/views.py:1392 templates/js/build.js:210 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:1587 +#: stock/views.py:1500 msgid "Duplicate Stock Item" msgstr "" -#: stock/views.py:1664 +#: stock/views.py:1577 msgid "Quantity cannot be negative" msgstr "" -#: stock/views.py:1750 +#: stock/views.py:1663 msgid "Delete Stock Location" msgstr "" -#: stock/views.py:1764 +#: stock/views.py:1677 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:1776 +#: stock/views.py:1689 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:1795 +#: stock/views.py:1708 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:1805 +#: stock/views.py:1718 msgid "Add Stock Tracking Entry" msgstr "" @@ -4596,6 +4634,10 @@ msgstr "" msgid "Outstanding Purchase Orders" msgstr "" +#: templates/InvenTree/po_overdue.html:7 +msgid "Overdue Purchase Orders" +msgstr "" + #: templates/InvenTree/required_stock_build.html:7 msgid "Require Stock To Complete Build" msgstr "" @@ -4612,11 +4654,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:191 templates/js/stock.js:290 +#: templates/InvenTree/search.html:191 templates/js/stock.js:300 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:194 templates/js/stock.js:300 +#: templates/InvenTree/search.html:194 templates/js/stock.js:310 msgid "No stock location set" msgstr "" @@ -4645,12 +4687,12 @@ msgid "Default Value" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:78 +#: templates/InvenTree/settings/part.html:79 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:79 +#: templates/InvenTree/settings/part.html:80 msgid "Delete Template" msgstr "" @@ -4670,11 +4712,11 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:37 +#: templates/InvenTree/settings/part.html:38 msgid "Part Parameter Templates" msgstr "" -#: templates/InvenTree/settings/part.html:58 +#: templates/InvenTree/settings/part.html:59 msgid "No part parameter templates found" msgstr "" @@ -4854,7 +4896,7 @@ msgstr "" msgid "Enter barcode data" msgstr "" -#: templates/js/barcode.js:42 +#: templates/js/barcode.js:42 templates/js/modals.js:856 msgid "Invalid server response" msgstr "" @@ -4931,39 +4973,39 @@ msgstr "" msgid "No pricing available" msgstr "" -#: templates/js/bom.js:272 templates/js/build.js:571 +#: templates/js/bom.js:304 templates/js/build.js:571 msgid "Actions" msgstr "" -#: templates/js/bom.js:280 +#: templates/js/bom.js:312 msgid "Validate BOM Item" msgstr "" -#: templates/js/bom.js:282 +#: templates/js/bom.js:314 msgid "This line has been validated" msgstr "" -#: templates/js/bom.js:284 +#: templates/js/bom.js:316 msgid "Edit BOM Item" msgstr "" -#: templates/js/bom.js:286 +#: templates/js/bom.js:318 msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:363 templates/js/build.js:305 +#: templates/js/bom.js:395 templates/js/build.js:305 msgid "No BOM items found" msgstr "" -#: templates/js/bom.js:509 +#: templates/js/bom.js:541 msgid "INACTIVE" msgstr "" -#: templates/js/bom.js:523 +#: templates/js/bom.js:555 msgid "Uses" msgstr "" -#: templates/js/bom.js:534 +#: templates/js/bom.js:566 msgid "No matching parts found" msgstr "" @@ -4999,7 +5041,7 @@ msgstr "" msgid "Build stock" msgstr "" -#: templates/js/build.js:582 templates/stock_table.html:25 +#: templates/js/build.js:582 templates/stock_table.html:26 msgid "Order stock" msgstr "" @@ -5043,23 +5085,153 @@ msgstr "" msgid "Assembled part" msgstr "" +#: templates/js/label.js:10 +msgid "Select Stock Items" +msgstr "" + +#: templates/js/label.js:11 +msgid "Stock item(s) must be selected before printing labels" +msgstr "" + +#: templates/js/label.js:29 templates/js/label.js:79 +msgid "No Labels Found" +msgstr "" + +#: templates/js/label.js:30 +msgid "No labels found which match selected stock item(s)" +msgstr "" + +#: templates/js/label.js:61 +msgid "Select Stock Locations" +msgstr "" + +#: templates/js/label.js:62 +msgid "Stock location(s) must be selected before printing labels" +msgstr "" + +#: templates/js/label.js:80 +msgid "No labels found which match selected stock location(s)" +msgstr "" + +#: templates/js/label.js:141 +msgid "Select Label" +msgstr "" + +#: templates/js/label.js:156 +msgid "Select Label Template" +msgstr "" + +#: templates/js/modals.js:406 +msgid "Show Error Information" +msgstr "" + +#: templates/js/modals.js:473 +msgid "Accept" +msgstr "" + +#: templates/js/modals.js:474 +msgid "Cancel" +msgstr "" + +#: templates/js/modals.js:538 +msgid "Loading Data" +msgstr "" + +#: templates/js/modals.js:549 templates/js/modals.js:807 +#: templates/modals.html:19 templates/modals.html:41 +msgid "Submit" +msgstr "" + +#: templates/js/modals.js:550 templates/js/modals.js:808 +#: templates/modals.html:18 templates/modals.html:40 +msgid "Close" +msgstr "" + +#: templates/js/modals.js:759 +msgid "Invalid response from server" +msgstr "" + +#: templates/js/modals.js:759 +msgid "Form data missing from server response" +msgstr "" + +#: templates/js/modals.js:772 +msgid "Error posting form data" +msgstr "" + +#: templates/js/modals.js:856 +msgid "JSON response missing form data" +msgstr "" + +#: templates/js/modals.js:866 +msgid "No Response" +msgstr "" + +#: templates/js/modals.js:867 +msgid "No response from the InvenTree server" +msgstr "" + +#: templates/js/modals.js:871 +msgid "Error 400: Bad Request" +msgstr "" + +#: templates/js/modals.js:872 +msgid "Server returned error code 400" +msgstr "" + +#: templates/js/modals.js:876 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/modals.js:877 +msgid "Authentication credentials not supplied" +msgstr "" + +#: templates/js/modals.js:881 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/modals.js:882 +msgid "You do not have the required permissions to access this function" +msgstr "" + +#: templates/js/modals.js:886 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/modals.js:887 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/modals.js:891 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/modals.js:892 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/modals.js:895 +msgid "Error requesting form data" +msgstr "" + #: templates/js/order.js:135 msgid "No purchase orders found" msgstr "" -#: templates/js/order.js:188 templates/js/stock.js:702 -msgid "Date" -msgstr "" - -#: templates/js/order.js:218 -msgid "No sales orders found" -msgstr "" - -#: templates/js/order.js:241 +#: templates/js/order.js:159 templates/js/order.js:252 msgid "Order is overdue" msgstr "" -#: templates/js/order.js:286 +#: templates/js/order.js:193 templates/js/stock.js:816 +msgid "Date" +msgstr "" + +#: templates/js/order.js:229 +msgid "No sales orders found" +msgstr "" + +#: templates/js/order.js:297 msgid "Shipment Date" msgstr "" @@ -5087,8 +5259,8 @@ msgstr "" msgid "No parts found" msgstr "" -#: templates/js/part.js:343 templates/js/stock.js:463 -#: templates/js/stock.js:1049 +#: templates/js/part.js:343 templates/js/stock.js:473 +#: templates/js/stock.js:1163 msgid "Select" msgstr "" @@ -5096,7 +5268,7 @@ msgstr "" msgid "No category" msgstr "" -#: templates/js/part.js:429 templates/js/table_filters.js:274 +#: templates/js/part.js:429 templates/js/table_filters.js:278 msgid "Low stock" msgstr "" @@ -5116,11 +5288,11 @@ msgstr "" msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:604 templates/js/stock.js:64 +#: templates/js/part.js:604 templates/js/stock.js:74 msgid "Edit test result" msgstr "" -#: templates/js/part.js:605 templates/js/stock.js:65 +#: templates/js/part.js:605 templates/js/stock.js:75 msgid "Delete test result" msgstr "" @@ -5128,111 +5300,131 @@ msgstr "" msgid "This test is defined for a parent part" msgstr "" -#: templates/js/stock.js:27 +#: templates/js/stock.js:37 msgid "PASS" msgstr "" -#: templates/js/stock.js:29 +#: templates/js/stock.js:39 msgid "FAIL" msgstr "" -#: templates/js/stock.js:34 +#: templates/js/stock.js:44 msgid "NO RESULT" msgstr "" -#: templates/js/stock.js:60 +#: templates/js/stock.js:70 msgid "Add test result" msgstr "" -#: templates/js/stock.js:79 +#: templates/js/stock.js:89 msgid "No test results found" msgstr "" -#: templates/js/stock.js:121 +#: templates/js/stock.js:131 msgid "Test Date" msgstr "" -#: templates/js/stock.js:282 +#: templates/js/stock.js:292 msgid "In production" msgstr "" -#: templates/js/stock.js:286 +#: templates/js/stock.js:296 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:304 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:314 +#: templates/js/stock.js:324 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:431 +#: templates/js/stock.js:441 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:525 +#: templates/js/stock.js:535 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:530 +#: templates/js/stock.js:540 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:533 +#: templates/js/stock.js:543 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:537 +#: templates/js/stock.js:547 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:539 +#: templates/js/stock.js:549 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:543 +#: templates/js/stock.js:553 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:547 +#: templates/js/stock.js:557 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:555 +#: templates/js/stock.js:565 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:559 +#: templates/js/stock.js:569 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:562 +#: templates/js/stock.js:572 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:566 templates/js/table_filters.js:106 +#: templates/js/stock.js:576 templates/js/table_filters.js:106 msgid "Depleted" msgstr "" -#: templates/js/stock.js:768 +#: templates/js/stock.js:605 +msgid "Stocktake" +msgstr "" + +#: templates/js/stock.js:732 +msgid "Stock Status" +msgstr "" + +#: templates/js/stock.js:747 +msgid "Set Stock Status" +msgstr "" + +#: templates/js/stock.js:761 +msgid "Select Status Code" +msgstr "" + +#: templates/js/stock.js:762 +msgid "Status code must be selected" +msgstr "" + +#: templates/js/stock.js:882 msgid "No user information" msgstr "" -#: templates/js/stock.js:888 +#: templates/js/stock.js:1002 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:987 +#: templates/js/stock.js:1101 msgid "Serial" msgstr "" -#: templates/js/stock.js:1080 templates/js/table_filters.js:131 +#: templates/js/stock.js:1194 templates/js/table_filters.js:131 msgid "Installed" msgstr "" -#: templates/js/stock.js:1105 +#: templates/js/stock.js:1219 msgid "Install item" msgstr "" @@ -5273,7 +5465,7 @@ msgstr "" msgid "Batch code" msgstr "" -#: templates/js/table_filters.js:91 templates/js/table_filters.js:241 +#: templates/js/table_filters.js:91 templates/js/table_filters.js:245 msgid "Active parts" msgstr "" @@ -5341,43 +5533,43 @@ msgstr "" msgid "Build status" msgstr "" -#: templates/js/table_filters.js:210 templates/js/table_filters.js:223 +#: templates/js/table_filters.js:210 templates/js/table_filters.js:227 msgid "Order status" msgstr "" -#: templates/js/table_filters.js:215 templates/js/table_filters.js:228 +#: templates/js/table_filters.js:215 templates/js/table_filters.js:232 msgid "Outstanding" msgstr "" -#: templates/js/table_filters.js:251 +#: templates/js/table_filters.js:255 msgid "Include subcategories" msgstr "" -#: templates/js/table_filters.js:252 +#: templates/js/table_filters.js:256 msgid "Include parts in subcategories" msgstr "" -#: templates/js/table_filters.js:256 +#: templates/js/table_filters.js:260 msgid "Has IPN" msgstr "" -#: templates/js/table_filters.js:257 +#: templates/js/table_filters.js:261 msgid "Part has internal part number" msgstr "" -#: templates/js/table_filters.js:262 +#: templates/js/table_filters.js:266 msgid "Show active parts" msgstr "" -#: templates/js/table_filters.js:270 +#: templates/js/table_filters.js:274 msgid "Stock available" msgstr "" -#: templates/js/table_filters.js:286 +#: templates/js/table_filters.js:290 msgid "Starred" msgstr "" -#: templates/js/table_filters.js:298 +#: templates/js/table_filters.js:302 msgid "Purchasable" msgstr "" @@ -5385,14 +5577,6 @@ msgstr "" msgid "Form errors exist" msgstr "" -#: templates/modals.html:18 templates/modals.html:40 -msgid "Close" -msgstr "" - -#: templates/modals.html:19 templates/modals.html:41 -msgid "Submit" -msgstr "" - #: templates/navbar.html:29 msgid "Buy" msgstr "" @@ -5453,94 +5637,106 @@ msgstr "" msgid "Export Stock Information" msgstr "" -#: templates/stock_table.html:21 -msgid "Add to selected stock items" +#: templates/stock_table.html:20 +msgid "Print labels" msgstr "" #: templates/stock_table.html:22 -msgid "Remove from selected stock items" +msgid "Add to selected stock items" msgstr "" #: templates/stock_table.html:23 +msgid "Remove from selected stock items" +msgstr "" + +#: templates/stock_table.html:24 msgid "Stocktake selected stock items" msgstr "" -#: templates/stock_table.html:24 +#: templates/stock_table.html:25 msgid "Move selected stock items" msgstr "" -#: templates/stock_table.html:24 +#: templates/stock_table.html:25 msgid "Move stock" msgstr "" -#: templates/stock_table.html:25 +#: templates/stock_table.html:26 msgid "Order selected items" msgstr "" -#: templates/stock_table.html:28 +#: templates/stock_table.html:27 +msgid "Change status" +msgstr "" + +#: templates/stock_table.html:27 +msgid "Change stock status" +msgstr "" + +#: templates/stock_table.html:30 msgid "Delete selected items" msgstr "" -#: templates/stock_table.html:28 +#: templates/stock_table.html:30 msgid "Delete Stock" msgstr "" -#: users/admin.py:62 +#: users/admin.py:64 msgid "Users" msgstr "" -#: users/admin.py:63 +#: users/admin.py:65 msgid "Select which users are assigned to this group" msgstr "" -#: users/admin.py:178 +#: users/admin.py:187 msgid "The following users are members of multiple groups:" msgstr "" -#: users/admin.py:201 +#: users/admin.py:210 msgid "Personal info" msgstr "" -#: users/admin.py:202 +#: users/admin.py:211 msgid "Permissions" msgstr "" -#: users/admin.py:205 +#: users/admin.py:214 msgid "Important dates" msgstr "" -#: users/models.py:135 +#: users/models.py:142 msgid "Permission set" msgstr "" -#: users/models.py:143 +#: users/models.py:150 msgid "Group" msgstr "" -#: users/models.py:146 +#: users/models.py:153 msgid "View" msgstr "" -#: users/models.py:146 +#: users/models.py:153 msgid "Permission to view items" msgstr "" -#: users/models.py:148 +#: users/models.py:155 msgid "Add" msgstr "" -#: users/models.py:148 +#: users/models.py:155 msgid "Permission to add items" msgstr "" -#: users/models.py:150 +#: users/models.py:157 msgid "Change" msgstr "" -#: users/models.py:150 +#: users/models.py:157 msgid "Permissions to edit items" msgstr "" -#: users/models.py:152 +#: users/models.py:159 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py index 972ff16f9c..ce75a47697 100644 --- a/InvenTree/order/api.py +++ b/InvenTree/order/api.py @@ -80,6 +80,17 @@ class POList(generics.ListCreateAPIView): else: queryset = queryset.exclude(status__in=PurchaseOrderStatus.OPEN) + # Filter by 'overdue' status + overdue = params.get('overdue', None) + + if overdue is not None: + overdue = str2bool(overdue) + + if overdue: + queryset = queryset.filter(PurchaseOrder.OVERDUE_FILTER) + else: + queryset = queryset.exclude(PurchaseOrder.OVERDUE_FILTER) + # Special filtering for 'status' field status = params.get('status', None) diff --git a/InvenTree/order/fixtures/order.yaml b/InvenTree/order/fixtures/order.yaml index 4ceaf3d482..8943b36061 100644 --- a/InvenTree/order/fixtures/order.yaml +++ b/InvenTree/order/fixtures/order.yaml @@ -7,6 +7,7 @@ reference: '0001' description: "Ordering some screws" supplier: 1 + status: 10 # Pending # Ordering some screws from Zerg Corp - model: order.purchaseorder @@ -15,6 +16,39 @@ reference: '0002' description: "Ordering some more screws" supplier: 3 + status: 10 # Pending + +- model: order.purchaseorder + pk: 3 + fields: + reference: '0003' + description: 'Another PO' + supplier: 3 + status: 20 # Placed + +- model: order.purchaseorder + pk: 4 + fields: + reference: '0004' + description: 'Another PO' + supplier: 3 + status: 20 # Placed + +- model: order.purchaseorder + pk: 5 + fields: + reference: '0005' + description: 'Another PO' + supplier: 3 + status: 30 # Complete + +- model: order.purchaseorder + pk: 6 + fields: + reference: '0006' + description: 'Another PO' + supplier: 3 + status: 40 # Cancelled # Add some line items against PO 0001 diff --git a/InvenTree/order/fixtures/sales_order.yaml b/InvenTree/order/fixtures/sales_order.yaml new file mode 100644 index 0000000000..e80119fa3e --- /dev/null +++ b/InvenTree/order/fixtures/sales_order.yaml @@ -0,0 +1,39 @@ +- model: order.salesorder + pk: 1 + fields: + reference: 'ABC123' + description: "One sales order, please" + customer: 4 + status: 10 # Pending + +- model: order.salesorder + pk: 2 + fields: + reference: 'ABC124' + description: "One sales order, please" + customer: 4 + status: 10 # Pending + +- model: order.salesorder + pk: 3 + fields: + reference: 'ABC125' + description: "One sales order, please" + customer: 4 + status: 10 # Pending + +- model: order.salesorder + pk: 4 + fields: + reference: 'ABC126' + description: "One sales order, please" + customer: 5 + status: 20 # Shipped + +- model: order.salesorder + pk: 5 + fields: + reference: 'ABC127' + description: "One sales order, please" + customer: 5 + status: 60 # Returned diff --git a/InvenTree/order/forms.py b/InvenTree/order/forms.py index 6db51b55e6..808ab7ed29 100644 --- a/InvenTree/order/forms.py +++ b/InvenTree/order/forms.py @@ -94,6 +94,7 @@ class EditPurchaseOrderForm(HelperForm): self.field_prefix = { 'reference': 'PO', 'link': 'fa-link', + 'target_date': 'fa-calendar-alt', } self.field_placeholder = { @@ -102,6 +103,10 @@ class EditPurchaseOrderForm(HelperForm): super().__init__(*args, **kwargs) + target_date = DatePickerFormField( + help_text=_('Target date for order delivery. Order will be overdue after this date.'), + ) + class Meta: model = PurchaseOrder fields = [ @@ -109,6 +114,7 @@ class EditPurchaseOrderForm(HelperForm): 'supplier', 'supplier_reference', 'description', + 'target_date', 'link', ] diff --git a/InvenTree/order/migrations/0041_auto_20210114_1728.py b/InvenTree/order/migrations/0041_auto_20210114_1728.py new file mode 100644 index 0000000000..09be471433 --- /dev/null +++ b/InvenTree/order/migrations/0041_auto_20210114_1728.py @@ -0,0 +1,28 @@ +# Generated by Django 3.0.7 on 2021-01-14 06:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0040_salesorder_target_date'), + ] + + operations = [ + migrations.AddField( + model_name='purchaseorder', + name='target_date', + field=models.DateField(blank=True, help_text='Expected date for order delivery. Order will be overdue after this date.', null=True, verbose_name='Target Delivery Date'), + ), + migrations.AlterField( + model_name='purchaseorder', + name='complete_date', + field=models.DateField(blank=True, help_text='Date order was completed', null=True, verbose_name='Completion Date'), + ), + migrations.AlterField( + model_name='purchaseorder', + name='issue_date', + field=models.DateField(blank=True, help_text='Date order was issued', null=True, verbose_name='Issue Date'), + ), + ] diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index 184452f24e..84f6aeb6f0 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -119,8 +119,11 @@ class PurchaseOrder(Order): supplier: Reference to the company supplying the goods in the order supplier_reference: Optional field for supplier order reference code received_by: User that received the goods + target_date: Expected delivery target date for PurchaseOrder completion (optional) """ + OVERDUE_FILTER = Q(status__in=PurchaseOrderStatus.OPEN) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date()) + @staticmethod def filterByDate(queryset, min_date, max_date): """ @@ -132,7 +135,7 @@ class PurchaseOrder(Order): To be "interesting": - A "received" order where the received date lies within the date range - - TODO: A "pending" order where the target date lies within the date range + - A "pending" order where the target date lies within the date range - TODO: An "overdue" order where the target date is in the past """ @@ -149,13 +152,12 @@ class PurchaseOrder(Order): # Construct a queryset for "received" orders within the range received = Q(status=PurchaseOrderStatus.COMPLETE) & Q(complete_date__gte=min_date) & Q(complete_date__lte=max_date) - # TODO - Construct a queryset for "pending" orders within the range + # Construct a queryset for "pending" orders within the range + pending = Q(status__in=PurchaseOrderStatus.OPEN) & ~Q(target_date=None) & Q(target_date__gte=min_date) & Q(target_date__lte=max_date) # TODO - Construct a queryset for "overdue" orders within the range - flt = received - - queryset = queryset.filter(flt) + queryset = queryset.filter(received | pending) return queryset @@ -186,9 +188,23 @@ class PurchaseOrder(Order): related_name='+' ) - issue_date = models.DateField(blank=True, null=True, help_text=_('Date order was issued')) + issue_date = models.DateField( + blank=True, null=True, + verbose_name=_('Issue Date'), + help_text=_('Date order was issued') + ) - complete_date = models.DateField(blank=True, null=True, help_text=_('Date order was completed')) + target_date = models.DateField( + blank=True, null=True, + verbose_name=_('Target Delivery Date'), + help_text=_('Expected date for order delivery. Order will be overdue after this date.'), + ) + + complete_date = models.DateField( + blank=True, null=True, + verbose_name=_('Completion Date'), + help_text=_('Date order was completed') + ) def get_absolute_url(self): return reverse('po-detail', kwargs={'pk': self.id}) @@ -256,8 +272,24 @@ class PurchaseOrder(Order): self.complete_date = datetime.now().date() self.save() + def is_overdue(self): + """ + Returns True if this PurchaseOrder is "overdue" + + Makes use of the OVERDUE_FILTER to avoid code duplication. + """ + + query = PurchaseOrder.objects.filter(pk=self.pk) + query = query.filter(PurchaseOrder.OVERDUE_FILTER) + + return query.exists() + def can_cancel(self): - return self.status not in [ + """ + A PurchaseOrder can only be cancelled under the following circumstances: + """ + + return self.status in [ PurchaseOrderStatus.PLACED, PurchaseOrderStatus.PENDING ] @@ -419,17 +451,13 @@ class SalesOrder(Order): """ Returns true if this SalesOrder is "overdue": - - Not completed - - Target date is "in the past" + Makes use of the OVERDUE_FILTER to avoid code duplication. """ - # Order cannot be deemed overdue if target_date is not set - if self.target_date is None: - return False + query = SalesOrder.objects.filter(pk=self.pk) + query = query.filer(SalesOrder.OVERDUE_FILTER) - today = datetime.now().date() - - return self.is_pending and self.target_date < today + return query.exists() @property def is_pending(self): diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py index 5463feb26f..a04798c303 100644 --- a/InvenTree/order/serializers.py +++ b/InvenTree/order/serializers.py @@ -40,12 +40,24 @@ class POSerializer(InvenTreeModelSerializer): def annotate_queryset(queryset): """ Add extra information to the queryset + + - Number of liens in the PurchaseOrder + - Overdue status of the PurchaseOrder """ queryset = queryset.annotate( line_items=SubqueryCount('lines') ) + queryset = queryset.annotate( + overdue=Case( + When( + PurchaseOrder.OVERDUE_FILTER, then=Value(True, output_field=BooleanField()), + ), + default=Value(False, output_field=BooleanField()) + ) + ) + return queryset supplier_detail = CompanyBriefSerializer(source='supplier', many=False, read_only=True) @@ -54,6 +66,8 @@ class POSerializer(InvenTreeModelSerializer): status_text = serializers.CharField(source='get_status_display', read_only=True) + overdue = serializers.BooleanField(required=False, read_only=True) + class Meta: model = PurchaseOrder @@ -65,12 +79,14 @@ class POSerializer(InvenTreeModelSerializer): 'description', 'line_items', 'link', + 'overdue', 'reference', 'supplier', 'supplier_detail', 'supplier_reference', 'status', 'status_text', + 'target_date', 'notes', ] diff --git a/InvenTree/order/templates/order/order_base.html b/InvenTree/order/templates/order/order_base.html index d3e1e02437..4e67325e48 100644 --- a/InvenTree/order/templates/order/order_base.html +++ b/InvenTree/order/templates/order/order_base.html @@ -26,7 +26,12 @@ src="{% static 'img/blank_image.png' %}" {% endif %} -

{% purchase_order_status_label order.status large=True %}

+

+ {% purchase_order_status_label order.status large=True %} + {% if order.is_overdue %} + {% trans "Overdue" %} + {% endif %} +


{{ order.description }}

@@ -47,7 +52,7 @@ src="{% static 'img/blank_image.png' %}" {% endif %} - {% if order.status == PurchaseOrderStatus.PENDING or order.status == PurchaseOrderStatus.PLACED %} + {% if order.can_cancel %} @@ -72,7 +77,12 @@ src="{% static 'img/blank_image.png' %}" {% trans "Order Status" %} - {% purchase_order_status_label order.status %} + + {% purchase_order_status_label order.status %} + {% if order.is_overdue %} + {% trans "Overdue" %} + {% endif %} + @@ -105,6 +115,13 @@ src="{% static 'img/blank_image.png' %}" {{ order.issue_date }} {% endif %} + {% if order.target_date %} + + + {% trans "Target Date" %} + {{ order.target_date }} + + {% endif %} {% if order.status == PurchaseOrderStatus.COMPLETE %} diff --git a/InvenTree/order/templates/order/purchase_orders.html b/InvenTree/order/templates/order/purchase_orders.html index d05e8fbf86..52314df833 100644 --- a/InvenTree/order/templates/order/purchase_orders.html +++ b/InvenTree/order/templates/order/purchase_orders.html @@ -70,6 +70,8 @@ InvenTree | {% trans "Purchase Orders" %} if (order.complete_date) { date = order.complete_date; + } else if (order.target_date) { + date = order.target_date; } var title = `${prefix}${order.reference} - ${order.supplier_detail.name}`; diff --git a/InvenTree/order/test_api.py b/InvenTree/order/test_api.py index 46c6f19277..58599f1eb3 100644 --- a/InvenTree/order/test_api.py +++ b/InvenTree/order/test_api.py @@ -2,12 +2,16 @@ Tests for the Order API """ +from datetime import datetime, timedelta + from rest_framework.test import APITestCase from rest_framework import status from django.urls import reverse from django.contrib.auth import get_user_model +from .models import PurchaseOrder, SalesOrder + class OrderTest(APITestCase): @@ -18,6 +22,8 @@ class OrderTest(APITestCase): 'location', 'supplier_part', 'stock', + 'order', + 'sales_order', ] def setUp(self): @@ -26,21 +32,80 @@ class OrderTest(APITestCase): get_user_model().objects.create_user('testuser', 'test@testing.com', 'password') self.client.login(username='testuser', password='password') - def doGet(self, url, options=''): + def doGet(self, url, data={}): - return self.client.get(url + "?" + options, format='json') + return self.client.get(url, data=data, format='json') + + def doPost(self, url, data={}): + return self.client.post(url, data=data, format='json') + + def filter(self, filters, count): + """ + Test API filters + """ + + response = self.doGet( + self.LIST_URL, + filters + ) + + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.data), count) + + return response + + +class PurchaseOrderTest(OrderTest): + """ + Tests for the PurchaseOrder API + """ + + LIST_URL = reverse('api-po-list') def test_po_list(self): - - url = reverse('api-po-list') - # List all order items + # List *ALL* PO items + self.filter({}, 6) + + # Filter by supplier + self.filter({'supplier': 1}, 1) + self.filter({'supplier': 3}, 5) + + # Filter by "outstanding" + self.filter({'outstanding': True}, 4) + self.filter({'outstanding': False}, 2) + + # Filter by "status" + self.filter({'status': 10}, 2) + self.filter({'status': 40}, 1) + + def test_overdue(self): + """ + Test "overdue" status + """ + + self.filter({'overdue': True}, 0) + self.filter({'overdue': False}, 6) + + order = PurchaseOrder.objects.get(pk=1) + order.target_date = datetime.now().date() - timedelta(days=10) + order.save() + + self.filter({'overdue': True}, 1) + self.filter({'overdue': False}, 5) + + def test_po_detail(self): + + url = '/api/order/po/1/' + response = self.doGet(url) - self.assertEqual(response.status_code, status.HTTP_200_OK) + + self.assertEqual(response.status_code, 200) - # Filter by stuff - response = self.doGet(url, 'status=10&part=1&supplier_part=1') - self.assertEqual(response.status_code, status.HTTP_200_OK) + data = response.data + + self.assertEqual(data['pk'], 1) + self.assertEqual(data['description'], 'Ordering some screws') def test_po_attachments(self): @@ -50,6 +115,60 @@ class OrderTest(APITestCase): self.assertEqual(response.status_code, status.HTTP_200_OK) + +class SalesOrderTest(OrderTest): + """ + Tests for the SalesOrder API + """ + + LIST_URL = reverse('api-so-list') + + def test_so_list(self): + + # All orders + self.filter({}, 5) + + # Filter by customer + self.filter({'customer': 4}, 3) + self.filter({'customer': 5}, 2) + + # Filter by outstanding + self.filter({'outstanding': True}, 3) + self.filter({'outstanding': False}, 2) + + # Filter by status + self.filter({'status': 10}, 3) # PENDING + self.filter({'status': 20}, 1) # SHIPPED + self.filter({'status': 99}, 0) # Invalid + + def test_overdue(self): + """ + Test "overdue" status + """ + + self.filter({'overdue': True}, 0) + self.filter({'overdue': False}, 5) + + for pk in [1, 2]: + order = SalesOrder.objects.get(pk=pk) + order.target_date = datetime.now().date() - timedelta(days=10) + order.save() + + self.filter({'overdue': True}, 2) + self.filter({'overdue': False}, 3) + + def test_so_detail(self): + + url = '/api/order/so/1/' + + response = self.doGet(url) + + self.assertEqual(response.status_code, 200) + + data = response.data + + self.assertEqual(data['pk'], 1) + def test_so_attachments(self): url = reverse('api-so-attachment-list') diff --git a/InvenTree/order/tests.py b/InvenTree/order/tests.py index 47dfe63d0f..7f60b1445b 100644 --- a/InvenTree/order/tests.py +++ b/InvenTree/order/tests.py @@ -41,7 +41,7 @@ class OrderTest(TestCase): next_ref = PurchaseOrder.getNextOrderNumber() - self.assertEqual(next_ref, '0003') + self.assertEqual(next_ref, '0007') def test_on_order(self): """ There should be 3 separate items on order for the M2x4 LPHS part """ diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index bd758e39fb..091b11e825 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -432,7 +432,7 @@ class PurchaseOrderCancel(AjaxUpdateView): form.add_error('confirm', _('Confirm order cancellation')) if not order.can_cancel(): - form.add_error(None, _('Order cannot be cancelled as either pending or placed')) + form.add_error(None, _('Order cannot be cancelled')) def save(self, order, form, **kwargs): """ diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index 1ac62161a5..16518937ae 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -13,6 +13,8 @@ from mptt.fields import TreeNodeChoiceField from django import forms from django.utils.translation import ugettext as _ +import common.models + from .models import Part, PartCategory, PartAttachment, PartRelated from .models import BomItem from .models import PartParameterTemplate, PartParameter @@ -23,8 +25,16 @@ from .models import PartSellPriceBreak class PartModelChoiceField(forms.ModelChoiceField): """ Extending string representation of Part instance with available stock """ + def label_from_instance(self, part): - return f'{part} - {part.available_stock}' + + label = str(part) + + # Optionally display available part quantity + if common.models.InvenTreeSetting.get_setting('PART_SHOW_QUANTITY_IN_FORMS'): + label += f" - {part.available_stock}" + + return label class PartImageForm(HelperForm): diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 8c88adf747..a45220c7ab 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -1990,7 +1990,13 @@ class BomItem(models.Model): Return the available stock items for the referenced sub_part """ - query = self.sub_part.stock_items.filter(StockModels.StockItem.IN_STOCK_FILTER).aggregate( + query = self.sub_part.stock_items.all() + + query = query.prefetch_related([ + 'sub_part__stock_items', + ]) + + query = query.filter(StockModels.StockItem.IN_STOCK_FILTER).aggregate( available=Coalesce(Sum('quantity'), 0) ) diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 807d6644ca..0fa4247cd1 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -32,6 +32,7 @@ from InvenTree import helpers import common.models import report.models +import label.models from InvenTree.status_codes import StockStatus from InvenTree.models import InvenTreeTree, InvenTreeAttachment @@ -63,6 +64,13 @@ class StockLocation(InvenTreeTree): **kwargs ) + @property + def barcode(self): + """ + Brief payload data (e.g. for labels) + """ + return self.format_barcode(brief=True) + def get_stock_items(self, cascade=True): """ Return a queryset for all stock items under this category. @@ -330,6 +338,13 @@ class StockItem(MPTTModel): **kwargs ) + @property + def barcode(self): + """ + Brief payload data (e.g. for labels) + """ + return self.format_barcode(brief=True) + uid = models.CharField(blank=True, max_length=128, help_text=("Unique identifier field")) parent = TreeForeignKey( @@ -1333,14 +1348,31 @@ class StockItem(MPTTModel): return len(self.available_test_reports()) > 0 + def available_labels(self): + """ + Return a list of Label objects which match this StockItem + """ + + labels = [] + + item_query = StockItem.objects.filter(pk=self.pk) + + for lbl in label.models.StockItemLabel.objects.filter(enabled=True): + + filters = helpers.validateFilterString(lbl.filters) + + if item_query.filter(**filters).exists(): + labels.append(lbl) + + return labels + @property def has_labels(self): """ Return True if there are any label templates available for this stock item """ - # TODO - Implement this - return True + return len(self.available_labels()) > 0 @receiver(pre_delete, sender=StockItem, dispatch_uid='stock_item_pre_delete_log') diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index bea7057351..8e4693cbc1 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -403,12 +403,7 @@ $("#stock-test-report").click(function() { }); $("#print-label").click(function() { - launchModalForm( - "{% url 'stock-item-label-select' item.id %}", - { - follow: true, - } - ) + printStockItemLabels([{{ item.pk }}]); }); $("#stock-duplicate").click(function() { diff --git a/InvenTree/stock/templates/stock/location.html b/InvenTree/stock/templates/stock/location.html index 765a4bd903..d613a26b22 100644 --- a/InvenTree/stock/templates/stock/location.html +++ b/InvenTree/stock/templates/stock/location.html @@ -29,7 +29,7 @@
@@ -205,6 +205,15 @@ } }); }); + + $('#print-label').click(function() { + + var locs = [{{ location.pk }}]; + + printStockLocationLabels(locs); + + }); + {% endif %} $('#show-qr-code').click(function() { diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index 7ad8bc4f7f..6aeb1f5b73 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -30,7 +30,6 @@ stock_item_detail_urls = [ url(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'), url(r'^test-report-select/', views.StockItemTestReportSelect.as_view(), name='stock-item-test-report-select'), - url(r'^label-select/', views.StockItemSelectLabels.as_view(), name='stock-item-label-select'), 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'), @@ -64,7 +63,6 @@ stock_urls = [ url(r'^item/uninstall/', views.StockItemUninstall.as_view(), name='stock-item-uninstall'), url(r'^item/test-report-download/', views.StockItemTestReportDownload.as_view(), name='stock-item-test-report-download'), - url(r'^item/print-stock-labels/', views.StockItemPrintLabels.as_view(), name='stock-item-print-labels'), # URLs for StockItem attachments url(r'^item/attachment/', include([ diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 5d505b5280..163d1ed112 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -31,7 +31,6 @@ from datetime import datetime, timedelta from company.models import Company, SupplierPart from part.models import Part from report.models import TestReport -from label.models import StockItemLabel from .models import StockItem, StockLocation, StockItemTracking, StockItemAttachment, StockItemTestResult import common.settings @@ -304,92 +303,6 @@ class StockItemReturnToStock(AjaxUpdateView): } -class StockItemSelectLabels(AjaxView): - """ - View for selecting a template for printing labels for one (or more) StockItem objects - """ - - model = StockItem - ajax_form_title = _('Select Label Template') - role_required = 'stock.view' - - def get_form(self): - - item = StockItem.objects.get(pk=self.kwargs['pk']) - - labels = [] - - # Construct a list of StockItemLabel objects which are enabled, and the filters match the selected StockItem - for label in StockItemLabel.objects.filter(enabled=True): - if label.matches_stock_item(item): - labels.append(label) - - return StockForms.StockItemLabelSelectForm(labels) - - def post(self, request, *args, **kwargs): - - label = request.POST.get('label', None) - - try: - label = StockItemLabel.objects.get(pk=label) - except (ValueError, StockItemLabel.DoesNotExist): - raise ValidationError({'label': _("Select valid label")}) - - stock_item = StockItem.objects.get(pk=self.kwargs['pk']) - - url = reverse('stock-item-print-labels') - - url += '?label={pk}'.format(pk=label.pk) - url += '&items[]={pk}'.format(pk=stock_item.pk) - - data = { - 'form_valid': True, - 'url': url, - } - - return self.renderJsonResponse(request, self.get_form(), data=data) - - -class StockItemPrintLabels(AjaxView): - """ - View for printing labels and returning a PDF - - Requires the following arguments to be passed as URL params: - - items: List of valid StockItem pk values - label: Valid pk of a StockItemLabel template - """ - - role_required = 'stock.view' - - def get(self, request, *args, **kwargs): - - label = request.GET.get('label', None) - - try: - label = StockItemLabel.objects.get(pk=label) - except (ValueError, StockItemLabel.DoesNotExist): - raise ValidationError({'label': 'Invalid label ID'}) - - item_pks = request.GET.getlist('items[]') - - items = [] - - for pk in item_pks: - try: - item = StockItem.objects.get(pk=pk) - items.append(item) - except (ValueError, StockItem.DoesNotExist): - pass - - if len(items) == 0: - raise ValidationError({'items': 'Must provide valid stockitems'}) - - pdf = label.render(items).getbuffer() - - return DownloadFile(pdf, 'stock_labels.pdf', content_type='application/pdf') - - class StockItemDeleteTestData(AjaxUpdateView): """ View for deleting all test data diff --git a/InvenTree/templates/InvenTree/index.html b/InvenTree/templates/InvenTree/index.html index 1b9a492a22..36e4f8bc49 100644 --- a/InvenTree/templates/InvenTree/index.html +++ b/InvenTree/templates/InvenTree/index.html @@ -35,6 +35,7 @@ InvenTree | {% trans "Index" %} {% if roles.purchase_order.view %} {% include "InvenTree/po_outstanding.html" with collapse_id="po_outstanding" %} {% endif %} + {% include "InvenTree/po_overdue.html" with collapse_id="po_overdue" %} {% if roles.sales_order.view %} {% include "InvenTree/so_outstanding.html" with collapse_id="so_outstanding" %} {% include "InvenTree/so_overdue.html" with collapse_id="so_overdue" %} @@ -130,6 +131,14 @@ loadPurchaseOrderTable("#po-outstanding-table", { } }); +loadPurchaseOrderTable("#po-overdue-table", { + url: "{% url 'api-po-list' %}", + params: { + supplier_detail: true, + overdue: true, + } +}); + loadSalesOrderTable("#so-outstanding-table", { url: "{% url 'api-so-list' %}", params: { @@ -158,6 +167,7 @@ loadSalesOrderTable("#so-overdue-table", { {% include "InvenTree/index/on_load.html" with label="stock-to-build" %} {% include "InvenTree/index/on_load.html" with label="po-outstanding" %} +{% include "InvenTree/index/on_load.html" with label="po-overdue" %} {% include "InvenTree/index/on_load.html" with label="so-outstanding" %} {% include "InvenTree/index/on_load.html" with label="so-overdue" %} diff --git a/InvenTree/templates/InvenTree/po_overdue.html b/InvenTree/templates/InvenTree/po_overdue.html new file mode 100644 index 0000000000..99e3e7d40f --- /dev/null +++ b/InvenTree/templates/InvenTree/po_overdue.html @@ -0,0 +1,15 @@ +{% extends "collapse_index.html" %} + +{% load i18n %} + +{% block collapse_title %} + +{% trans "Overdue Purchase Orders" %} +{% endblock %} + +{% block collapse_content %} + + +
+ +{% endblock %} \ No newline at end of file diff --git a/InvenTree/templates/InvenTree/settings/part.html b/InvenTree/templates/InvenTree/settings/part.html index fe46911dae..9174b2f127 100644 --- a/InvenTree/templates/InvenTree/settings/part.html +++ b/InvenTree/templates/InvenTree/settings/part.html @@ -18,6 +18,7 @@ {% include "InvenTree/settings/setting.html" with key="PART_IPN_REGEX" %} {% include "InvenTree/settings/setting.html" with key="PART_ALLOW_DUPLICATE_IPN" %} + {% include "InvenTree/settings/setting.html" with key="PART_SHOW_QUANTITY_IN_FORMS" icon="fa-hashtag" %} {% include "InvenTree/settings/setting.html" with key="PART_TEMPLATE" icon="fa-clone" %} {% include "InvenTree/settings/setting.html" with key="PART_ASSEMBLY" icon="fa-tools" %} diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html index c025919936..36f4974816 100644 --- a/InvenTree/templates/base.html +++ b/InvenTree/templates/base.html @@ -112,7 +112,6 @@ InvenTree - @@ -120,6 +119,8 @@ InvenTree + + diff --git a/InvenTree/templates/js/label.js b/InvenTree/templates/js/label.js new file mode 100644 index 0000000000..93eb1c60c5 --- /dev/null +++ b/InvenTree/templates/js/label.js @@ -0,0 +1,173 @@ +{% load i18n %} + +function printStockItemLabels(items, options={}) { + /** + * Print stock item labels for the given stock items + */ + + if (items.length == 0) { + showAlertDialog( + '{% trans "Select Stock Items" %}', + '{% trans "Stock item(s) must be selected before printing labels" %}' + ); + + return; + } + + // Request available labels from the server + inventreeGet( + '{% url "api-stockitem-label-list" %}', + { + enabled: true, + items: items, + }, + { + success: function(response) { + + if (response.length == 0) { + showAlertDialog( + '{% trans "No Labels Found" %}', + '{% trans "No labels found which match selected stock item(s)" %}', + ); + + return; + } + + // Select label to print + selectLabel( + response, + items, + { + success: function(pk) { + var href = `/api/label/stock/${pk}/print/?`; + + items.forEach(function(item) { + href += `items[]=${item}&`; + }); + + window.location.href = href; + } + } + ); + } + } + ); +} + +function printStockLocationLabels(locations, options={}) { + + if (locations.length == 0) { + showAlertDialog( + '{% trans "Select Stock Locations" %}', + '{% trans "Stock location(s) must be selected before printing labels" %}' + ); + + return; + } + + // Request available labels from the server + inventreeGet( + '{% url "api-stocklocation-label-list" %}', + { + enabled: true, + locations: locations, + }, + { + success: function(response) { + if (response.length == 0) { + showAlertDialog( + '{% trans "No Labels Found" %}', + '{% trans "No labels found which match selected stock location(s)" %}', + ); + + return; + } + + // Select label to print + selectLabel( + response, + locations, + { + success: function(pk) { + var href = `/api/label/location/${pk}/print/?`; + + locations.forEach(function(location) { + href += `locations[]=${location}&`; + }); + + window.location.href = href; + } + } + ); + } + } + ) +} + + +function selectLabel(labels, items, options={}) { + /** + * Present the user with the available labels, + * and allow them to select which label to print. + * + * The intent is that the available labels have been requested + * (via AJAX) from the server. + */ + + var modal = options.modal || '#modal-form'; + + var label_list = makeOptionsList( + labels, + function(item) { + var text = item.name; + + if (item.description) { + text += ` - ${item.description}`; + } + + return text; + }, + function(item) { + return item.pk; + } + ); + + // Construct form + var html = ` + +
+
+ +
+ +
+
+
`; + + openModal({ + modal: modal, + }); + + modalEnable(modal, true); + modalSetTitle(modal, '{% trans "Select Label Template" %}'); + modalSetContent(modal, html); + + attachSelect(modal); + + modalSubmit(modal, function() { + + var label = $(modal).find('#id_label'); + + var pk = label.val(); + + closeModal(modal); + + if (options.success) { + options.success(pk); + } + }); +} \ No newline at end of file diff --git a/InvenTree/InvenTree/static/script/inventree/modals.js b/InvenTree/templates/js/modals.js similarity index 92% rename from InvenTree/InvenTree/static/script/inventree/modals.js rename to InvenTree/templates/js/modals.js index 12a496c481..33be851d83 100644 --- a/InvenTree/InvenTree/static/script/inventree/modals.js +++ b/InvenTree/templates/js/modals.js @@ -1,3 +1,5 @@ +{% load i18n %} + function makeOption(text, value, title) { /* Format an option for a select element */ @@ -164,6 +166,15 @@ function setFieldValue(fieldName, value, options={}) { field.val(value); } +function getFieldValue(fieldName, options={}) { + + var modal = options.modal || '#modal-form'; + + var field = getFieldByName(modal, fieldName); + + return field.val(); +} + function partialMatcher(params, data) { /* Replacement function for the 'matcher' parameter for a select2 dropdown. @@ -392,7 +403,7 @@ function renderErrorMessage(xhr) {
@@ -459,8 +470,8 @@ function showQuestionDialog(title, content, options={}) { modalSetTitle(modal, title); modalSetContent(modal, content); - var accept_text = options.accept_text || 'Accept'; - var cancel_text = options.cancel_text || 'Cancel'; + var accept_text = options.accept_text || '{% trans "Accept" %}'; + var cancel_text = options.cancel_text || '{% trans "Cancel" %}'; $(modal).find('#modal-form-cancel').html(cancel_text); $(modal).find('#modal-form-accept').html(accept_text); @@ -524,7 +535,7 @@ function openModal(options) { if (options.title) { modalSetTitle(modal, options.title); } else { - modalSetTitle(modal, 'Loading Data...'); + modalSetTitle(modal, '{% trans "Loading Data" %}...'); } // Unless the content is explicitly set, display loading message @@ -535,8 +546,8 @@ function openModal(options) { } // Default labels for 'Submit' and 'Close' buttons in the form - var submit_text = options.submit_text || 'Submit'; - var close_text = options.close_text || 'Close'; + var submit_text = options.submit_text || '{% trans "Submit" %}'; + var close_text = options.close_text || '{% trans "Close" %}'; modalSetButtonText(modal, submit_text, close_text); @@ -745,7 +756,7 @@ function handleModalForm(url, options) { } else { $(modal).modal('hide'); - showAlertDialog('Invalid response from server', 'Form data missing from server response'); + showAlertDialog('{% trans "Invalid response from server" %}', '{% trans "Form data missing from server response" %}'); } } } @@ -758,7 +769,7 @@ function handleModalForm(url, options) { // There was an error submitting form data via POST $(modal).modal('hide'); - showAlertDialog('Error posting form data', renderErrorMessage(xhr)); + showAlertDialog('{% trans "Error posting form data" %}', renderErrorMessage(xhr)); }, complete: function(xhr) { //TODO @@ -793,8 +804,8 @@ function launchModalForm(url, options = {}) { var modal = options.modal || '#modal-form'; // Default labels for 'Submit' and 'Close' buttons in the form - var submit_text = options.submit_text || 'Submit'; - var close_text = options.close_text || 'Close'; + var submit_text = options.submit_text || '{% trans "Submit" %}'; + var close_text = options.close_text || '{% trans "Close" %}'; // Form the ajax request to retrieve the django form data ajax_data = { @@ -842,7 +853,7 @@ function launchModalForm(url, options = {}) { } else { $(modal).modal('hide'); - showAlertDialog('Invalid server response', 'JSON response missing form data'); + showAlertDialog('{% trans "Invalid server response" %}', '{% trans "JSON response missing form data" %}'); } }, error: function (xhr, ajaxOptions, thrownError) { @@ -852,36 +863,36 @@ function launchModalForm(url, options = {}) { if (xhr.status == 0) { // No response from the server showAlertDialog( - "No Response", - "No response from the InvenTree server", + '{% trans "No Response" %}', + '{% trans "No response from the InvenTree server" %}', ); } else if (xhr.status == 400) { showAlertDialog( - "Error 400: Bad Request", - "Server returned error code 400" + '{% trans "Error 400: Bad Request" %}', + '{% trans "Server returned error code 400" %}', ); } else if (xhr.status == 401) { showAlertDialog( - "Error 401: Not Authenticated", - "Authentication credentials not supplied" + '{% trans "Error 401: Not Authenticated" %}', + '{% trans "Authentication credentials not supplied" %}', ); } else if (xhr.status == 403) { showAlertDialog( - "Error 403: Permission Denied", - "You do not have the required permissions to access this function" + '{% trans "Error 403: Permission Denied" %}', + '{% trans "You do not have the required permissions to access this function" %}', ); } else if (xhr.status == 404) { showAlertDialog( - "Error 404: Resource Not Found", - "The requested resource could not be located on the server" + '{% trans "Error 404: Resource Not Found" %}', + '{% trans "The requested resource could not be located on the server" %}', ); } else if (xhr.status == 408) { showAlertDialog( - "Error 408: Timeout", - "Connection timeout while requesting data from server" + '{% trans "Error 408: Timeout" %}', + '{% trans "Connection timeout while requesting data from server" %}', ); } else { - showAlertDialog('Error requesting form data', renderErrorMessage(xhr)); + showAlertDialog('{% trans "Error requesting form data" %}', renderErrorMessage(xhr)); } console.log("Modal form error: " + xhr.status); diff --git a/InvenTree/templates/js/order.js b/InvenTree/templates/js/order.js index 18c315d17e..53063cd709 100644 --- a/InvenTree/templates/js/order.js +++ b/InvenTree/templates/js/order.js @@ -141,9 +141,9 @@ function loadPurchaseOrderTable(table, options) { switchable: false, }, { - sortable: true, field: 'reference', title: '{% trans "Purchase Order" %}', + sortable: true, switchable: false, formatter: function(value, row, index, field) { @@ -153,13 +153,19 @@ function loadPurchaseOrderTable(table, options) { value = `${prefix}${value}`; } - return renderLink(value, `/order/purchase-order/${row.pk}/`); + var html = renderLink(value, `/order/purchase-order/${row.pk}/`); + + if (row.overdue) { + html += makeIconBadge('fa-calendar-times icon-red', '{% trans "Order is overdue" %}'); + } + + return html; } }, { - sortable: true, field: 'supplier_detail', title: '{% trans "Supplier" %}', + sortable: true, formatter: function(value, row, index, field) { return imageHoverIcon(row.supplier_detail.image) + renderLink(row.supplier_detail.name, `/company/${row.supplier}/purchase-orders/`); } @@ -170,27 +176,32 @@ function loadPurchaseOrderTable(table, options) { sortable: true, }, { - sortable: true, field: 'description', title: '{% trans "Description" %}', + sortable: true, }, { - sortable: true, field: 'status', title: '{% trans "Status" %}', + sortable: true, formatter: function(value, row, index, field) { return purchaseOrderStatusDisplay(row.status, row.status_text); } }, { - sortable: true, field: 'creation_date', title: '{% trans "Date" %}', + sortable: true, }, { + field: 'target_date', + title: '{% trans "Target Date" %}', sortable: true, + }, + { field: 'line_items', - title: '{% trans "Items" %}' + title: '{% trans "Items" %}', + sortable: true, }, ], }); diff --git a/InvenTree/templates/js/stock.js b/InvenTree/templates/js/stock.js index e9cb5e2696..836fa0e242 100644 --- a/InvenTree/templates/js/stock.js +++ b/InvenTree/templates/js/stock.js @@ -660,6 +660,18 @@ function loadStockTable(table, options) { } // Automatically link button callbacks + $('#multi-item-print-label').click(function() { + var selections = $('#stock-table').bootstrapTable('getSelections'); + + var items = []; + + selections.forEach(function(item) { + items.push(item.pk); + }); + + printStockItemLabels(items); + }); + $('#multi-item-stocktake').click(function() { stockAdjustment('count'); }); diff --git a/InvenTree/templates/js/table_filters.js b/InvenTree/templates/js/table_filters.js index 84aa12c139..81f72fb26d 100644 --- a/InvenTree/templates/js/table_filters.js +++ b/InvenTree/templates/js/table_filters.js @@ -214,6 +214,10 @@ function getAvailableTableFilters(tableKey) { type: 'bool', title: '{% trans "Outstanding" %}', }, + overdue: { + type: 'bool', + title: '{% trans "Overdue" %}', + }, }; } diff --git a/InvenTree/templates/stock_table.html b/InvenTree/templates/stock_table.html index f39f9c733a..6731f8f69c 100644 --- a/InvenTree/templates/stock_table.html +++ b/InvenTree/templates/stock_table.html @@ -17,6 +17,7 @@