From 446c744462189291c9c3c2c7d3a0925bac659b19 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 8 Jan 2021 22:19:52 +1100 Subject: [PATCH 01/32] Expose stock items labels to the API --- InvenTree/InvenTree/urls.py | 2 ++ InvenTree/label/api.py | 43 ++++++++++++++++++++++++++++++++++ InvenTree/label/serializers.py | 26 ++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 InvenTree/label/api.py create mode 100644 InvenTree/label/serializers.py diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index 79c662182e..019f939f60 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)), diff --git a/InvenTree/label/api.py b/InvenTree/label/api.py new file mode 100644 index 0000000000..539851285a --- /dev/null +++ b/InvenTree/label/api.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.conf.urls import url, include + +from django_filters.rest_framework import DjangoFilterBackend + +from rest_framework import generics, filters + +from .models import StockItemLabel +from .serializers import StockItemLabelSerializer + + +class StockItemLabelList(generics.ListAPIView): + """ + API endpoint for viewing list of StockItemLabel objects. + """ + + queryset = StockItemLabel.objects.all() + serializer_class = StockItemLabelSerializer + + filter_backends = [ + DjangoFilterBackend, + filters.SearchFilter + ] + + filter_fields = [ + 'enabled', + ] + + search_fields = [ + 'name', + 'description', + ] + + +label_api_urls = [ + + # Stock item labels + url(r'stock/', include([ + url(r'^.*$', StockItemLabelList.as_view(), name='api-stock-label-list'), + ])), +] diff --git a/InvenTree/label/serializers.py b/InvenTree/label/serializers.py new file mode 100644 index 0000000000..ca998d14bd --- /dev/null +++ b/InvenTree/label/serializers.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from InvenTree.serializers import InvenTreeModelSerializer +from InvenTree.serializers import InvenTreeAttachmentSerializerField + +from .models import StockItemLabel + + +class StockItemLabelSerializer(InvenTreeModelSerializer): + """ + Serializes a StockItemLabel object. + """ + + label = InvenTreeAttachmentSerializerField(required=True) + + class Meta: + model = StockItemLabel + fields = [ + 'pk', + 'name', + 'description', + 'label', + 'filters', + 'enabled', + ] From 80c7ee6dab8f64310c99b6963f560c77aa4eeea0 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 8 Jan 2021 22:47:47 +1100 Subject: [PATCH 02/32] Add ability to filter label by StockItem --- InvenTree/label/api.py | 90 +++++++++++++++++++++++++++++++++++++++ InvenTree/label/models.py | 6 ++- 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/InvenTree/label/api.py b/InvenTree/label/api.py index 539851285a..c56bae59ca 100644 --- a/InvenTree/label/api.py +++ b/InvenTree/label/api.py @@ -7,6 +7,10 @@ from django_filters.rest_framework import DjangoFilterBackend from rest_framework import generics, filters +import InvenTree.helpers + +from stock.models import StockItem + from .models import StockItemLabel from .serializers import StockItemLabelSerializer @@ -14,11 +18,97 @@ from .serializers import StockItemLabelSerializer class StockItemLabelList(generics.ListAPIView): """ 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 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 + + 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 StockItem label + 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 + + # Matched all items + if matches: + valid_label_ids.add(label.pk) + else: + continue + + # Reduce queryset to only valid matches + queryset = queryset.filter(pk__in=[id for id in valid_label_ids]) + + return queryset + filter_backends = [ DjangoFilterBackend, filters.SearchFilter diff --git a/InvenTree/label/models.py b/InvenTree/label/models.py index 49b07572a8..8d4f2cd2f4 100644 --- a/InvenTree/label/models.py +++ b/InvenTree/label/models.py @@ -55,7 +55,11 @@ class LabelTemplate(models.Model): 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, + help_text=_('Label description'), + ) label = models.FileField( upload_to=rename_label, From f0fa092c662314d3e7b931851ef196de7403738c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 8 Jan 2021 23:08:00 +1100 Subject: [PATCH 03/32] Add model for StockLocation label --- InvenTree/label/admin.py | 7 ++-- .../migrations/0003_stocklocationlabel.py | 30 +++++++++++++++ InvenTree/label/models.py | 38 ++++++++++++++++++- 3 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 InvenTree/label/migrations/0003_stocklocationlabel.py 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/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/models.py b/InvenTree/label/models.py index 8d4f2cd2f4..85499ca46d 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 +from stock.models import StockItem, StockLocation def rename_label(instance, filename): @@ -157,3 +157,39 @@ class StockItemLabel(LabelTemplate): }) return records + + +class StockLocationLabel(LabelTemplate): + """ + Template for printing StockLocation labels + """ + + SUBDIR = "stocklocation" + + def matches_stock_location(self, location): + """ + Test if this label template matches a given StockLocation object + """ + + filters = validateFilterString(self.filters) + + locs = 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': location, + }) + + return records From 7c7a67fcc6ac2d4f2589f0e58f520075c10cd3ad Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 8 Jan 2021 23:08:30 +1100 Subject: [PATCH 04/32] Add filterable API for StockLocation labels --- InvenTree/label/api.py | 144 ++++++++++++++++++++++++++++----- InvenTree/label/serializers.py | 21 ++++- 2 files changed, 145 insertions(+), 20 deletions(-) diff --git a/InvenTree/label/api.py b/InvenTree/label/api.py index c56bae59ca..714fceebec 100644 --- a/InvenTree/label/api.py +++ b/InvenTree/label/api.py @@ -9,13 +9,33 @@ from rest_framework import generics, filters import InvenTree.helpers -from stock.models import StockItem +from stock.models import StockItem, StockLocation -from .models import StockItemLabel -from .serializers import StockItemLabelSerializer +from .models import StockItemLabel, StockLocationLabel +from .serializers import StockItemLabelSerializer, StockLocationLabelSerializer -class StockItemLabelList(generics.ListAPIView): +class LabelListView(generics.ListAPIView): + """ + Generic API class for label templates + """ + + filter_backends = [ + DjangoFilterBackend, + filters.SearchFilter + ] + + filter_fields = [ + 'enabled', + ] + + search_fields = [ + 'name', + 'description', + ] + + +class StockItemLabelList(LabelListView): """ API endpoint for viewing list of StockItemLabel objects. @@ -23,7 +43,7 @@ class StockItemLabelList(generics.ListAPIView): - enabled: Filter by enabled / disabled status - item: Filter by single stock item - - items[]: Filter by list of stock items + - items: Filter by list of stock items """ @@ -88,7 +108,7 @@ class StockItemLabelList(generics.ListAPIView): matches = True - # Filter string defined for the StockItem label + # Filter string defined for the StockItemLabel object filters = InvenTree.helpers.validateFilterString(label.filters) for item in items: @@ -97,6 +117,7 @@ class StockItemLabelList(generics.ListAPIView): if not item_query.filter(**filters).exists(): matches = False + break # Matched all items if matches: @@ -105,29 +126,114 @@ class StockItemLabelList(generics.ListAPIView): continue # Reduce queryset to only valid matches - queryset = queryset.filter(pk__in=[id for id in valid_label_ids]) + queryset = queryset.filter(pk__in=[pk for pk in valid_label_ids]) return queryset - filter_backends = [ - DjangoFilterBackend, - filters.SearchFilter - ] - filter_fields = [ - 'enabled', - ] +class StockLocationLabelList(LabelListView): + """ + API endpoint for viewiing list of StockLocationLabel objects. - search_fields = [ - 'name', - 'description', - ] + 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 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(item)) + except (ValueError): + pass + + # List of StockLocation objects which match provided values + valid_locations = StockLocation.objects.filter(pk__in=valid_ids) + + return valid_locations + + 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 label_api_urls = [ # Stock item labels url(r'stock/', include([ - url(r'^.*$', StockItemLabelList.as_view(), name='api-stock-label-list'), + url(r'^.*$', StockItemLabelList.as_view(), name='api-stockitem-label-list'), + ])), + + # Stock location labels + url(r'location/', include([ + url(r'^.*$', StockLocationLabelList.as_view(), name='api-stocklocation-label-list'), ])), ] diff --git a/InvenTree/label/serializers.py b/InvenTree/label/serializers.py index ca998d14bd..c9d487af23 100644 --- a/InvenTree/label/serializers.py +++ b/InvenTree/label/serializers.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals from InvenTree.serializers import InvenTreeModelSerializer from InvenTree.serializers import InvenTreeAttachmentSerializerField -from .models import StockItemLabel +from .models import StockItemLabel, StockLocationLabel class StockItemLabelSerializer(InvenTreeModelSerializer): @@ -24,3 +24,22 @@ class StockItemLabelSerializer(InvenTreeModelSerializer): 'filters', 'enabled', ] + + +class StockLocationLabelSerializer(InvenTreeModelSerializer): + """ + Serializes a StockLocationLabel object + """ + + label = InvenTreeAttachmentSerializerField(required=True) + + class Meta: + model = StockLocationLabel + fields = [ + 'pk', + 'name', + 'description', + 'label', + 'filters', + 'enabled', + ] From a0d1f9517125aa0562ed05870fb69e7515111412 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 9 Jan 2021 08:10:04 +1100 Subject: [PATCH 05/32] Add exception for new database table --- InvenTree/users/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/InvenTree/users/models.py b/InvenTree/users/models.py index b54cddf7c4..2f47362f1c 100644 --- a/InvenTree/users/models.py +++ b/InvenTree/users/models.py @@ -106,6 +106,7 @@ class RuleSet(models.Model): 'common_inventreesetting', 'company_contact', 'label_stockitemlabel', + 'label_stocklocationlabel', 'report_reportasset', 'report_testreport', 'part_partstar', From 44e60a705e4d3776d8745f9f673a7e2eaf9c0457 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 9 Jan 2021 08:20:29 +1100 Subject: [PATCH 06/32] Add detail endpoints for the StockItemLabel and StockLocationLabel models --- InvenTree/label/api.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/InvenTree/label/api.py b/InvenTree/label/api.py index 714fceebec..8f3828410e 100644 --- a/InvenTree/label/api.py +++ b/InvenTree/label/api.py @@ -131,6 +131,15 @@ class StockItemLabelList(LabelListView): return queryset +class StockItemLabelDetail(generics.RetrieveUpdateDestroyAPIView): + """ + API endpoint for a single StockItemLabel object + """ + + queryset = StockItemLabel.objects.all() + serializer_class = StockItemLabelSerializer + + class StockLocationLabelList(LabelListView): """ API endpoint for viewiing list of StockLocationLabel objects. @@ -225,15 +234,36 @@ class StockLocationLabelList(LabelListView): return queryset +class StockLocationLabelDetail(generics.RetrieveUpdateDestroyAPIView): + """ + API endpoint for a single StockLocationLabel object + """ + + queryset = StockLocationLabel.objects.all() + seiralizer_class = StockLocationLabelSerializer + + label_api_urls = [ # Stock item labels url(r'stock/', include([ + # Detail views + url(r'^(?P\d+)/', include([ + 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'^.*$', StockLocationLabelDetail.as_view(), name='api-stocklocation-label-detail'), + ])), + + # List view url(r'^.*$', StockLocationLabelList.as_view(), name='api-stocklocation-label-list'), ])), ] From bdc7367e293ea9570a4d8131a9b4ac908099a201 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 9 Jan 2021 20:43:48 +1100 Subject: [PATCH 07/32] Add endpoint for printing labels --- InvenTree/InvenTree/urls.py | 2 + InvenTree/label/api.py | 84 +++++++++++++++---- InvenTree/templates/base.html | 3 +- InvenTree/templates/js/label.js | 52 ++++++++++++ .../inventree => templates/js}/modals.js | 50 +++++------ InvenTree/templates/js/stock.js | 33 ++++++++ InvenTree/templates/stock_table.html | 1 + 7 files changed, 184 insertions(+), 41 deletions(-) create mode 100644 InvenTree/templates/js/label.js rename InvenTree/{InvenTree/static/script/inventree => templates/js}/modals.js (92%) diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index 019f939f60..d8a64708a9 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -92,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'), @@ -99,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/label/api.py b/InvenTree/label/api.py index 8f3828410e..e3367ad894 100644 --- a/InvenTree/label/api.py +++ b/InvenTree/label/api.py @@ -1,11 +1,15 @@ # -*- 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 @@ -35,21 +39,11 @@ class LabelListView(generics.ListAPIView): ] -class StockItemLabelList(LabelListView): +class 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 - + Mixin for extracting stock items from query params """ - queryset = StockItemLabel.objects.all() - serializer_class = StockItemLabelSerializer - def get_items(self): """ Return a list of requested stock items @@ -59,8 +53,8 @@ class StockItemLabelList(LabelListView): params = self.request.query_params - if 'items' in params: - items = params.getlist('items', []) + if 'items[]' in params: + items = params.getlist('items[]', []) elif 'item' in params: items = [params.get('item', None)] @@ -80,6 +74,22 @@ class StockItemLabelList(LabelListView): 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. @@ -140,6 +150,47 @@ class StockItemLabelDetail(generics.RetrieveUpdateDestroyAPIView): 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 printing'), + 'message': str(e), + } + + return Response(data, status=400) + + return InvenTree.helpers.DownloadFile(pdf.getbuffer(), 'stock_item_labels.pdf', content_type='application/pdf') + + class StockLocationLabelList(LabelListView): """ API endpoint for viewiing list of StockLocationLabel objects. @@ -163,7 +214,7 @@ class StockLocationLabelList(LabelListView): params = self.request.query_params - if 'locations' in params: + if 'locations[]' in params: locations = params.getlist('locations', []) elif 'location' in params: locations = [params.get('location', None)] @@ -175,7 +226,7 @@ class StockLocationLabelList(LabelListView): for loc in locations: try: - valid_ids.append(int(item)) + valid_ids.append(int(loc)) except (ValueError): pass @@ -249,6 +300,7 @@ label_api_urls = [ 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'), ])), 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..28a377df8b --- /dev/null +++ b/InvenTree/templates/js/label.js @@ -0,0 +1,52 @@ +{% load i18n %} + +function selectLabel(labels, 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); +} \ 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..08306352b4 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 */ @@ -392,7 +394,7 @@ function renderErrorMessage(xhr) {
@@ -459,8 +461,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 +526,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 +537,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 +747,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 +760,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 +795,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 +844,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 +854,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/stock.js b/InvenTree/templates/js/stock.js index e3f124d252..1b448aa957 100644 --- a/InvenTree/templates/js/stock.js +++ b/InvenTree/templates/js/stock.js @@ -645,6 +645,39 @@ 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); + }); + + // 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; + } + + var label = selectLabel(response); + } + } + ); + }); + $('#multi-item-stocktake').click(function() { stockAdjustment('count'); }); diff --git a/InvenTree/templates/stock_table.html b/InvenTree/templates/stock_table.html index 51f7c277db..220abc7dc7 100644 --- a/InvenTree/templates/stock_table.html +++ b/InvenTree/templates/stock_table.html @@ -17,6 +17,7 @@
+ \ No newline at end of file From 01e27a0d59729552e5c6e9c881fdafa78f77cf1c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 12 Jan 2021 00:22:58 +1100 Subject: [PATCH 18/32] Add simplified 'barcode' function for StockItem --- InvenTree/stock/models.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index d5f72a981a..0fa4247cd1 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -338,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( From e561b3a4fcf94c5a93b4c9353f9738796e948f95 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 13 Jan 2021 21:51:55 +1100 Subject: [PATCH 19/32] Add StockItemLabel templates --- InvenTree/label/apps.py | 65 ++++++++++++++++++++- InvenTree/label/templates/stockitem/qr.html | 16 +++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 InvenTree/label/templates/stockitem/qr.html diff --git a/InvenTree/label/apps.py b/InvenTree/label/apps.py index 6f7e25bd9f..74db58fe92 100644 --- a/InvenTree/label/apps.py +++ b/InvenTree/label/apps.py @@ -27,7 +27,70 @@ class LabelConfig(AppConfig): if they do not already exist """ - pass + 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) + + # 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']}'") + + try: + StockItemLabel.objects.create( + name=label['name'], + description=label['description'], + label=filename, + filters='', + enabled=True + ) + except IntegrityError: + pass def create_stock_location_labels(self): """ 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 @@ + + + From 4e2d3b7da2c41fef7913a252712d0127d61218b9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 13 Jan 2021 21:52:16 +1100 Subject: [PATCH 20/32] Improvement for existing StockItemLabel template --- InvenTree/label/templates/stocklocation/qr_and_text.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/InvenTree/label/templates/stocklocation/qr_and_text.html b/InvenTree/label/templates/stocklocation/qr_and_text.html index 33e684b13d..9a555aca15 100644 --- a/InvenTree/label/templates/stocklocation/qr_and_text.html +++ b/InvenTree/label/templates/stocklocation/qr_and_text.html @@ -14,6 +14,12 @@ float: right; display: inline; font-size: 125%; + position: absolute; + top: 0mm; + left: 23mm; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .qr { From 80c88b4fccec38a62fd7777f0abf7fda966b756d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 13 Jan 2021 21:53:11 +1100 Subject: [PATCH 21/32] Update translations --- InvenTree/locale/de/LC_MESSAGES/django.po | 208 ++++++++++++---------- InvenTree/locale/en/LC_MESSAGES/django.po | 200 +++++++++++---------- InvenTree/locale/es/LC_MESSAGES/django.po | 200 +++++++++++---------- 3 files changed, 338 insertions(+), 270 deletions(-) diff --git a/InvenTree/locale/de/LC_MESSAGES/django.po b/InvenTree/locale/de/LC_MESSAGES/django.po index ee1b230dbf..87f2621bc5 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-09 22:22+1100\n" +"POT-Creation-Date: 2021-01-13 21:52+1100\n" "PO-Revision-Date: 2020-05-03 11:32+0200\n" "Last-Translator: Christian Schlüter \n" "Language-Team: C \n" @@ -109,7 +109,7 @@ msgstr "Datei-Kommentar" msgid "User" msgstr "Benutzer" -#: InvenTree/models.py:106 part/models.py:647 +#: InvenTree/models.py:106 label/models.py:54 part/models.py:647 #: part/templates/part/params.html:24 templates/js/part.js:129 msgid "Name" msgstr "Name" @@ -455,7 +455,7 @@ 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:61 #: 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 @@ -561,7 +561,7 @@ msgstr "Bau-Status" msgid "Build status code" msgstr "Bau-Statuscode" -#: build/models.py:194 stock/models.py:398 +#: build/models.py:194 stock/models.py:412 msgid "Batch Code" msgstr "Losnummer" @@ -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:392 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:394 +#: build/models.py:220 part/models.py:705 stock/models.py:408 msgid "Link to external URL" msgstr "Link zu einer externen URL" @@ -590,7 +590,7 @@ 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:464 stock/models.py:1530 +#: 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 msgid "Notes" @@ -1114,7 +1114,7 @@ msgstr "Lagerbestand dem Bau zuweisen" msgid "Create Build Output" msgstr "Bau-Ausgabe" -#: build/views.py:207 stock/models.py:873 stock/views.py:1594 +#: build/views.py:207 stock/models.py:887 stock/views.py:1594 #, fuzzy #| msgid "Serial numbers already exist: " msgid "Serial numbers already exist" @@ -1696,7 +1696,7 @@ msgstr "Produziert diese Firma Teile?" msgid "Currency" msgstr "Währung bearbeiten" -#: company/models.py:313 stock/models.py:346 +#: company/models.py:313 stock/models.py:360 #: stock/templates/stock/item_base.html:194 msgid "Base Part" msgstr "Basisteil" @@ -1814,8 +1814,8 @@ 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:381 -#: stock/models.py:382 stock/templates/stock/item_base.html:221 +#: 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:250 msgid "Customer" msgstr "Kunde" @@ -1952,7 +1952,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:355 +#: 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" @@ -2142,38 +2142,52 @@ msgstr "Preisstaffel löschen" msgid "Must provide valid StockItem(s)" msgstr "Lagerobjekte bewegen" -#: label/api.py:185 -msgid "Error during label printing" +#: label/api.py:185 label/api.py:337 +msgid "Error during label rendering" msgstr "" +#: label/api.py:324 +#, fuzzy +#| msgid "Move Stock Items" +msgid "Must provide valid StockLocation(s)" +msgstr "Lagerobjekte bewegen" + #: label/models.py:55 #, fuzzy #| msgid "Part name" msgid "Label name" msgstr "Name des Teils" -#: label/models.py:61 +#: label/models.py:62 #, fuzzy #| msgid "Part description" msgid "Label description" msgstr "Beschreibung des Teils" -#: label/models.py:67 +#: label/models.py:69 stock/forms.py:198 +msgid "Label" +msgstr "" + +#: label/models.py:70 msgid "Label template file" msgstr "" -#: label/models.py:73 +#: label/models.py:76 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:79 -msgid "Label template is enabled" +#: label/models.py:77 +msgid "Filters" msgstr "" -#: label/models.py:80 report/models.py:162 +#: label/models.py:83 report/models.py:162 msgid "Enabled" msgstr "" +#: label/models.py:84 +msgid "Label template is enabled" +msgstr "" + #: order/forms.py:25 order/templates/order/order_base.html:39 msgid "Place order" msgstr "Bestellung aufgeben" @@ -2253,7 +2267,7 @@ 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:252 stock/models.py:857 +#: stock/models.py:259 stock/models.py:871 msgid "Quantity must be greater than zero" msgstr "Anzahl muss größer Null sein" @@ -2303,7 +2317,7 @@ msgstr "Zulieferer-Teil" msgid "Number of items received" msgstr "Empfangene Objekt-Anzahl" -#: order/models.py:602 stock/models.py:474 +#: order/models.py:602 stock/models.py:488 #: stock/templates/stock/item_base.html:283 #, fuzzy #| msgid "Purchase Order" @@ -2568,7 +2582,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:386 +#: 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" @@ -3288,7 +3302,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:242 +#: stock/models.py:249 #, fuzzy #| msgid "Overage must be an integer value or a percentage" msgid "Quantity must be integer value for trackable parts" @@ -3768,7 +3782,7 @@ msgstr "Parameter hinzufügen" msgid "New Parameter" msgstr "Neuer Parameter" -#: part/templates/part/params.html:25 stock/models.py:1517 +#: part/templates/part/params.html:25 stock/models.py:1531 #: templates/InvenTree/settings/header.html:8 templates/js/stock.js:113 msgid "Value" msgstr "Wert" @@ -4309,10 +4323,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" @@ -4391,272 +4401,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:187 +#: stock/models.py:194 #, fuzzy #| msgid "Created new stock item" msgid "Created stock item" msgstr "Neues Lagerobjekt erstellt" -#: stock/models.py:223 +#: 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:259 +#: stock/models.py:266 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "Teile-Typ ('{pf}') muss {pe} sein" -#: stock/models.py:269 stock/models.py:278 +#: 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:270 +#: 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:292 +#: stock/models.py:299 msgid "Item cannot belong to itself" msgstr "Teil kann nicht zu sich selbst gehören" -#: stock/models.py:298 +#: stock/models.py:305 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:305 +#: stock/models.py:312 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:338 +#: stock/models.py:352 msgid "Parent Stock Item" msgstr "Eltern-Lagerobjekt" -#: stock/models.py:347 +#: stock/models.py:361 msgid "Base part" msgstr "Basis-Teil" -#: stock/models.py:356 +#: 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:361 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:364 +#: stock/models.py:378 msgid "Where is this stock item located?" msgstr "Wo wird dieses Teil normalerweise gelagert?" -#: stock/models.py:369 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:372 +#: stock/models.py:386 msgid "Is this item installed in another item?" msgstr "Ist dieses Teil in einem anderen verbaut?" -#: stock/models.py:388 +#: stock/models.py:402 msgid "Serial number for this item" msgstr "Seriennummer für dieses Teil" -#: stock/models.py:400 +#: stock/models.py:414 msgid "Batch code for this stock item" msgstr "Losnummer für dieses Lagerobjekt" -#: stock/models.py:404 +#: stock/models.py:418 msgid "Stock Quantity" msgstr "Bestand" -#: stock/models.py:413 +#: stock/models.py:427 msgid "Source Build" msgstr "Quellbau" -#: stock/models.py:415 +#: stock/models.py:429 msgid "Build for this stock item" msgstr "Bau für dieses Lagerobjekt" -#: stock/models.py:426 +#: stock/models.py:440 msgid "Source Purchase Order" msgstr "Quellbestellung" -#: stock/models.py:429 +#: stock/models.py:443 msgid "Purchase order for this stock item" msgstr "Bestellung für dieses Teil" -#: stock/models.py:435 +#: stock/models.py:449 msgid "Destination Sales Order" msgstr "Zielauftrag" -#: stock/models.py:441 stock/templates/stock/item_base.html:316 +#: stock/models.py:455 stock/templates/stock/item_base.html:316 #: templates/js/stock.js:597 #, fuzzy #| msgid "Export" msgid "Expiry Date" msgstr "Exportieren" -#: stock/models.py:442 +#: stock/models.py:456 msgid "" "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:455 +#: stock/models.py:469 msgid "Delete this Stock Item when stock is depleted" msgstr "Objekt löschen wenn Lagerbestand aufgebraucht" -#: stock/models.py:465 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:475 +#: stock/models.py:489 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:575 +#: stock/models.py:589 #, fuzzy #| msgid "Item assigned to customer?" msgid "Assigned to Customer" msgstr "Ist dieses Objekt einem Kunden zugeteilt?" -#: stock/models.py:577 +#: 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:590 +#: stock/models.py:604 #, fuzzy #| msgid "Item assigned to customer?" msgid "Returned from customer" msgstr "Ist dieses Objekt einem Kunden zugeteilt?" -#: stock/models.py:592 +#: stock/models.py:606 #, fuzzy #| msgid "Create new stock location" msgid "Returned to location" msgstr "Neuen Lagerort anlegen" -#: stock/models.py:717 +#: stock/models.py:731 #, fuzzy #| msgid "Installed in Stock Item" msgid "Installed into stock item" msgstr "In Lagerobjekt installiert" -#: stock/models.py:725 +#: stock/models.py:739 #, fuzzy #| msgid "Installed in Stock Item" msgid "Installed stock item" msgstr "In Lagerobjekt installiert" -#: stock/models.py:749 +#: stock/models.py:763 #, fuzzy #| msgid "Installed in Stock Item" msgid "Uninstalled stock item" msgstr "In Lagerobjekt installiert" -#: stock/models.py:768 +#: stock/models.py:782 #, fuzzy #| msgid "Include sublocations" msgid "Uninstalled into location" msgstr "Unterlagerorte einschließen" -#: stock/models.py:848 +#: 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:854 +#: stock/models.py:868 msgid "Quantity must be integer" msgstr "Anzahl muss eine Ganzzahl sein" -#: stock/models.py:860 +#: 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:863 +#: stock/models.py:877 msgid "Serial numbers must be a list of integers" msgstr "Seriennummern muss eine Liste von Ganzzahlen sein" -#: stock/models.py:866 +#: stock/models.py:880 msgid "Quantity does not match serial numbers" msgstr "Anzahl stimmt nicht mit den Seriennummern überein" -#: stock/models.py:898 +#: stock/models.py:912 msgid "Add serial number" msgstr "Seriennummer hinzufügen" -#: stock/models.py:901 +#: stock/models.py:915 #, python-brace-format msgid "Serialized {n} items" msgstr "{n} Teile serialisiert" -#: stock/models.py:1012 +#: 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:1418 +#: stock/models.py:1432 msgid "Tracking entry title" msgstr "Name des Eintrags-Trackings" -#: stock/models.py:1420 +#: stock/models.py:1434 msgid "Entry notes" msgstr "Eintrags-Notizen" -#: stock/models.py:1422 +#: stock/models.py:1436 msgid "Link to external page for further information" msgstr "Link auf externe Seite für weitere Informationen" -#: stock/models.py:1482 +#: 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:1488 +#: stock/models.py:1502 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1505 +#: stock/models.py:1519 msgid "Test" msgstr "" -#: stock/models.py:1506 +#: stock/models.py:1520 #, fuzzy #| msgid "Part name" msgid "Test name" msgstr "Name des Teils" -#: stock/models.py:1511 +#: stock/models.py:1525 #, fuzzy #| msgid "Search Results" msgid "Result" msgstr "Suchergebnisse" -#: stock/models.py:1512 templates/js/table_filters.js:172 +#: stock/models.py:1526 templates/js/table_filters.js:172 msgid "Test result" msgstr "" -#: stock/models.py:1518 +#: stock/models.py:1532 msgid "Test output value" msgstr "" -#: stock/models.py:1524 +#: stock/models.py:1538 #, fuzzy #| msgid "Attachments" msgid "Attachment" msgstr "Anhänge" -#: stock/models.py:1525 +#: stock/models.py:1539 #, fuzzy #| msgid "Delete attachment" msgid "Test result attachment" msgstr "Anhang löschen" -#: stock/models.py:1531 +#: stock/models.py:1545 #, fuzzy #| msgid "Edit notes" msgid "Test notes" @@ -5918,10 +5928,10 @@ msgstr "Lagerobjekte löschen" #: templates/js/label.js:11 #, fuzzy #| msgid "StockItem has been allocated" -msgid "Stock items must be selected before printing labels" +msgid "Stock item(s) must be selected before printing labels" msgstr "Lagerobjekt wurde zugewiesen" -#: templates/js/label.js:29 +#: templates/js/label.js:29 templates/js/label.js:79 #, fuzzy #| msgid "No parts found" msgid "No Labels Found" @@ -5933,13 +5943,31 @@ msgstr "Keine Teile gefunden" msgid "No labels found which match selected stock item(s)" msgstr "Ausgewählte Stücklistenpositionen entfernen" -#: templates/js/label.js:77 +#: templates/js/label.js:61 +#, fuzzy +#| msgid "Delete Stock Location" +msgid "Select Stock Locations" +msgstr "Standort löschen" + +#: templates/js/label.js:62 +#, fuzzy +#| msgid "StockItem has been allocated" +msgid "Stock location(s) must be selected before printing labels" +msgstr "Lagerobjekt wurde zugewiesen" + +#: templates/js/label.js:80 +#, fuzzy +#| msgid "Remove selected BOM items" +msgid "No labels found which match selected stock location(s)" +msgstr "Ausgewählte Stücklistenpositionen entfernen" + +#: 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:92 +#: templates/js/label.js:156 #, fuzzy #| msgid "Select valid part" msgid "Select Label Template" diff --git a/InvenTree/locale/en/LC_MESSAGES/django.po b/InvenTree/locale/en/LC_MESSAGES/django.po index 9e2347f35b..0bebe68adb 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-09 22:22+1100\n" +"POT-Creation-Date: 2021-01-13 21:52+1100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -99,7 +99,7 @@ msgstr "" msgid "User" msgstr "" -#: InvenTree/models.py:106 part/models.py:647 +#: InvenTree/models.py:106 label/models.py:54 part/models.py:647 #: part/templates/part/params.html:24 templates/js/part.js:129 msgid "Name" msgstr "" @@ -397,7 +397,7 @@ 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:61 #: 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 @@ -491,7 +491,7 @@ msgstr "" msgid "Build status code" msgstr "" -#: build/models.py:194 stock/models.py:398 +#: build/models.py:194 stock/models.py:412 msgid "Batch Code" 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:392 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:394 +#: build/models.py:220 part/models.py:705 stock/models.py:408 msgid "Link to external URL" msgstr "" @@ -520,7 +520,7 @@ 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:464 stock/models.py:1530 +#: 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 msgid "Notes" @@ -949,7 +949,7 @@ msgstr "" msgid "Create Build Output" msgstr "" -#: build/views.py:207 stock/models.py:873 stock/views.py:1594 +#: build/views.py:207 stock/models.py:887 stock/views.py:1594 msgid "Serial numbers already exist" msgstr "" @@ -1415,7 +1415,7 @@ msgstr "" msgid "Currency" msgstr "" -#: company/models.py:313 stock/models.py:346 +#: company/models.py:313 stock/models.py:360 #: stock/templates/stock/item_base.html:194 msgid "Base Part" msgstr "" @@ -1525,8 +1525,8 @@ msgid "Uses default currency" msgstr "" #: company/templates/company/detail.html:62 -#: order/templates/order/sales_order_base.html:89 stock/models.py:381 -#: stock/models.py:382 stock/templates/stock/item_base.html:221 +#: 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:250 msgid "Customer" msgstr "" @@ -1658,7 +1658,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:355 +#: 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 "" @@ -1838,34 +1838,46 @@ msgstr "" msgid "Must provide valid StockItem(s)" msgstr "" -#: label/api.py:185 -msgid "Error during label printing" +#: 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:55 msgid "Label name" msgstr "" -#: label/models.py:61 +#: label/models.py:62 msgid "Label description" msgstr "" -#: label/models.py:67 +#: label/models.py:69 stock/forms.py:198 +msgid "Label" +msgstr "" + +#: label/models.py:70 msgid "Label template file" msgstr "" -#: label/models.py:73 +#: label/models.py:76 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:79 -msgid "Label template is enabled" +#: label/models.py:77 +msgid "Filters" msgstr "" -#: label/models.py:80 report/models.py:162 +#: label/models.py:83 report/models.py:162 msgid "Enabled" msgstr "" +#: label/models.py:84 +msgid "Label template is enabled" +msgstr "" + #: order/forms.py:25 order/templates/order/order_base.html:39 msgid "Place order" msgstr "" @@ -1937,7 +1949,7 @@ msgid "Date order was completed" msgstr "" #: order/models.py:214 order/models.py:296 part/views.py:1504 -#: stock/models.py:252 stock/models.py:857 +#: stock/models.py:259 stock/models.py:871 msgid "Quantity must be greater than zero" msgstr "" @@ -1987,7 +1999,7 @@ msgstr "" msgid "Number of items received" msgstr "" -#: order/models.py:602 stock/models.py:474 +#: order/models.py:602 stock/models.py:488 #: stock/templates/stock/item_base.html:283 msgid "Purchase Price" msgstr "" @@ -2231,7 +2243,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:386 +#: 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 "" @@ -2877,7 +2889,7 @@ msgid "BOM line checksum" msgstr "" #: part/models.py:1963 part/views.py:1510 part/views.py:1562 -#: stock/models.py:242 +#: stock/models.py:249 msgid "Quantity must be integer value for trackable parts" msgstr "" @@ -3275,7 +3287,7 @@ msgstr "" msgid "New Parameter" msgstr "" -#: part/templates/part/params.html:25 stock/models.py:1517 +#: part/templates/part/params.html:25 stock/models.py:1531 #: templates/InvenTree/settings/header.html:8 templates/js/stock.js:113 msgid "Value" msgstr "" @@ -3738,10 +3750,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 "" @@ -3802,237 +3810,237 @@ msgstr "" msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:187 +#: stock/models.py:194 msgid "Created stock item" msgstr "" -#: stock/models.py:223 +#: stock/models.py:230 msgid "StockItem with this serial number already exists" msgstr "" -#: stock/models.py:259 +#: stock/models.py:266 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:269 stock/models.py:278 +#: stock/models.py:276 stock/models.py:285 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:270 +#: stock/models.py:277 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:292 +#: stock/models.py:299 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:298 +#: stock/models.py:305 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:305 +#: stock/models.py:312 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:338 +#: stock/models.py:352 msgid "Parent Stock Item" msgstr "" -#: stock/models.py:347 +#: stock/models.py:361 msgid "Base part" msgstr "" -#: stock/models.py:356 +#: stock/models.py:370 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:361 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:364 +#: stock/models.py:378 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:369 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:372 +#: stock/models.py:386 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:388 +#: stock/models.py:402 msgid "Serial number for this item" msgstr "" -#: stock/models.py:400 +#: stock/models.py:414 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:404 +#: stock/models.py:418 msgid "Stock Quantity" msgstr "" -#: stock/models.py:413 +#: stock/models.py:427 msgid "Source Build" msgstr "" -#: stock/models.py:415 +#: stock/models.py:429 msgid "Build for this stock item" msgstr "" -#: stock/models.py:426 +#: stock/models.py:440 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:429 +#: stock/models.py:443 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:435 +#: stock/models.py:449 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:441 stock/templates/stock/item_base.html:316 +#: stock/models.py:455 stock/templates/stock/item_base.html:316 #: templates/js/stock.js:597 msgid "Expiry Date" msgstr "" -#: stock/models.py:442 +#: stock/models.py:456 msgid "" "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:455 +#: stock/models.py:469 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:465 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:475 +#: stock/models.py:489 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:575 +#: stock/models.py:589 msgid "Assigned to Customer" msgstr "" -#: stock/models.py:577 +#: stock/models.py:591 msgid "Manually assigned to customer" msgstr "" -#: stock/models.py:590 +#: stock/models.py:604 msgid "Returned from customer" msgstr "" -#: stock/models.py:592 +#: stock/models.py:606 msgid "Returned to location" msgstr "" -#: stock/models.py:717 +#: stock/models.py:731 msgid "Installed into stock item" msgstr "" -#: stock/models.py:725 +#: stock/models.py:739 msgid "Installed stock item" msgstr "" -#: stock/models.py:749 +#: stock/models.py:763 msgid "Uninstalled stock item" msgstr "" -#: stock/models.py:768 +#: stock/models.py:782 msgid "Uninstalled into location" msgstr "" -#: stock/models.py:848 +#: stock/models.py:862 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:854 +#: stock/models.py:868 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:860 +#: stock/models.py:874 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:863 +#: stock/models.py:877 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:866 +#: stock/models.py:880 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:898 +#: stock/models.py:912 msgid "Add serial number" msgstr "" -#: stock/models.py:901 +#: stock/models.py:915 #, python-brace-format msgid "Serialized {n} items" msgstr "" -#: stock/models.py:1012 +#: stock/models.py:1026 msgid "StockItem cannot be moved as it is not in stock" msgstr "" -#: stock/models.py:1418 +#: stock/models.py:1432 msgid "Tracking entry title" msgstr "" -#: stock/models.py:1420 +#: stock/models.py:1434 msgid "Entry notes" msgstr "" -#: stock/models.py:1422 +#: stock/models.py:1436 msgid "Link to external page for further information" msgstr "" -#: stock/models.py:1482 +#: stock/models.py:1496 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1488 +#: stock/models.py:1502 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1505 +#: stock/models.py:1519 msgid "Test" msgstr "" -#: stock/models.py:1506 +#: stock/models.py:1520 msgid "Test name" msgstr "" -#: stock/models.py:1511 +#: stock/models.py:1525 msgid "Result" msgstr "" -#: stock/models.py:1512 templates/js/table_filters.js:172 +#: stock/models.py:1526 templates/js/table_filters.js:172 msgid "Test result" msgstr "" -#: stock/models.py:1518 +#: stock/models.py:1532 msgid "Test output value" msgstr "" -#: stock/models.py:1524 +#: stock/models.py:1538 msgid "Attachment" msgstr "" -#: stock/models.py:1525 +#: stock/models.py:1539 msgid "Test result attachment" msgstr "" -#: stock/models.py:1531 +#: stock/models.py:1545 msgid "Test notes" msgstr "" @@ -5048,10 +5056,10 @@ msgid "Select Stock Items" msgstr "" #: templates/js/label.js:11 -msgid "Stock items must be selected before printing labels" +msgid "Stock item(s) must be selected before printing labels" msgstr "" -#: templates/js/label.js:29 +#: templates/js/label.js:29 templates/js/label.js:79 msgid "No Labels Found" msgstr "" @@ -5059,11 +5067,23 @@ msgstr "" msgid "No labels found which match selected stock item(s)" msgstr "" -#: templates/js/label.js:77 +#: 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:92 +#: templates/js/label.js:156 msgid "Select Label Template" msgstr "" diff --git a/InvenTree/locale/es/LC_MESSAGES/django.po b/InvenTree/locale/es/LC_MESSAGES/django.po index 9e2347f35b..0bebe68adb 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-09 22:22+1100\n" +"POT-Creation-Date: 2021-01-13 21:52+1100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -99,7 +99,7 @@ msgstr "" msgid "User" msgstr "" -#: InvenTree/models.py:106 part/models.py:647 +#: InvenTree/models.py:106 label/models.py:54 part/models.py:647 #: part/templates/part/params.html:24 templates/js/part.js:129 msgid "Name" msgstr "" @@ -397,7 +397,7 @@ 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:61 #: 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 @@ -491,7 +491,7 @@ msgstr "" msgid "Build status code" msgstr "" -#: build/models.py:194 stock/models.py:398 +#: build/models.py:194 stock/models.py:412 msgid "Batch Code" 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:392 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:394 +#: build/models.py:220 part/models.py:705 stock/models.py:408 msgid "Link to external URL" msgstr "" @@ -520,7 +520,7 @@ 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:464 stock/models.py:1530 +#: 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 msgid "Notes" @@ -949,7 +949,7 @@ msgstr "" msgid "Create Build Output" msgstr "" -#: build/views.py:207 stock/models.py:873 stock/views.py:1594 +#: build/views.py:207 stock/models.py:887 stock/views.py:1594 msgid "Serial numbers already exist" msgstr "" @@ -1415,7 +1415,7 @@ msgstr "" msgid "Currency" msgstr "" -#: company/models.py:313 stock/models.py:346 +#: company/models.py:313 stock/models.py:360 #: stock/templates/stock/item_base.html:194 msgid "Base Part" msgstr "" @@ -1525,8 +1525,8 @@ msgid "Uses default currency" msgstr "" #: company/templates/company/detail.html:62 -#: order/templates/order/sales_order_base.html:89 stock/models.py:381 -#: stock/models.py:382 stock/templates/stock/item_base.html:221 +#: 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:250 msgid "Customer" msgstr "" @@ -1658,7 +1658,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:355 +#: 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 "" @@ -1838,34 +1838,46 @@ msgstr "" msgid "Must provide valid StockItem(s)" msgstr "" -#: label/api.py:185 -msgid "Error during label printing" +#: 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:55 msgid "Label name" msgstr "" -#: label/models.py:61 +#: label/models.py:62 msgid "Label description" msgstr "" -#: label/models.py:67 +#: label/models.py:69 stock/forms.py:198 +msgid "Label" +msgstr "" + +#: label/models.py:70 msgid "Label template file" msgstr "" -#: label/models.py:73 +#: label/models.py:76 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:79 -msgid "Label template is enabled" +#: label/models.py:77 +msgid "Filters" msgstr "" -#: label/models.py:80 report/models.py:162 +#: label/models.py:83 report/models.py:162 msgid "Enabled" msgstr "" +#: label/models.py:84 +msgid "Label template is enabled" +msgstr "" + #: order/forms.py:25 order/templates/order/order_base.html:39 msgid "Place order" msgstr "" @@ -1937,7 +1949,7 @@ msgid "Date order was completed" msgstr "" #: order/models.py:214 order/models.py:296 part/views.py:1504 -#: stock/models.py:252 stock/models.py:857 +#: stock/models.py:259 stock/models.py:871 msgid "Quantity must be greater than zero" msgstr "" @@ -1987,7 +1999,7 @@ msgstr "" msgid "Number of items received" msgstr "" -#: order/models.py:602 stock/models.py:474 +#: order/models.py:602 stock/models.py:488 #: stock/templates/stock/item_base.html:283 msgid "Purchase Price" msgstr "" @@ -2231,7 +2243,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:386 +#: 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 "" @@ -2877,7 +2889,7 @@ msgid "BOM line checksum" msgstr "" #: part/models.py:1963 part/views.py:1510 part/views.py:1562 -#: stock/models.py:242 +#: stock/models.py:249 msgid "Quantity must be integer value for trackable parts" msgstr "" @@ -3275,7 +3287,7 @@ msgstr "" msgid "New Parameter" msgstr "" -#: part/templates/part/params.html:25 stock/models.py:1517 +#: part/templates/part/params.html:25 stock/models.py:1531 #: templates/InvenTree/settings/header.html:8 templates/js/stock.js:113 msgid "Value" msgstr "" @@ -3738,10 +3750,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 "" @@ -3802,237 +3810,237 @@ msgstr "" msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:187 +#: stock/models.py:194 msgid "Created stock item" msgstr "" -#: stock/models.py:223 +#: stock/models.py:230 msgid "StockItem with this serial number already exists" msgstr "" -#: stock/models.py:259 +#: stock/models.py:266 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:269 stock/models.py:278 +#: stock/models.py:276 stock/models.py:285 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:270 +#: stock/models.py:277 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:292 +#: stock/models.py:299 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:298 +#: stock/models.py:305 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:305 +#: stock/models.py:312 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:338 +#: stock/models.py:352 msgid "Parent Stock Item" msgstr "" -#: stock/models.py:347 +#: stock/models.py:361 msgid "Base part" msgstr "" -#: stock/models.py:356 +#: stock/models.py:370 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:361 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:364 +#: stock/models.py:378 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:369 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:372 +#: stock/models.py:386 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:388 +#: stock/models.py:402 msgid "Serial number for this item" msgstr "" -#: stock/models.py:400 +#: stock/models.py:414 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:404 +#: stock/models.py:418 msgid "Stock Quantity" msgstr "" -#: stock/models.py:413 +#: stock/models.py:427 msgid "Source Build" msgstr "" -#: stock/models.py:415 +#: stock/models.py:429 msgid "Build for this stock item" msgstr "" -#: stock/models.py:426 +#: stock/models.py:440 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:429 +#: stock/models.py:443 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:435 +#: stock/models.py:449 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:441 stock/templates/stock/item_base.html:316 +#: stock/models.py:455 stock/templates/stock/item_base.html:316 #: templates/js/stock.js:597 msgid "Expiry Date" msgstr "" -#: stock/models.py:442 +#: stock/models.py:456 msgid "" "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:455 +#: stock/models.py:469 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:465 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:475 +#: stock/models.py:489 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:575 +#: stock/models.py:589 msgid "Assigned to Customer" msgstr "" -#: stock/models.py:577 +#: stock/models.py:591 msgid "Manually assigned to customer" msgstr "" -#: stock/models.py:590 +#: stock/models.py:604 msgid "Returned from customer" msgstr "" -#: stock/models.py:592 +#: stock/models.py:606 msgid "Returned to location" msgstr "" -#: stock/models.py:717 +#: stock/models.py:731 msgid "Installed into stock item" msgstr "" -#: stock/models.py:725 +#: stock/models.py:739 msgid "Installed stock item" msgstr "" -#: stock/models.py:749 +#: stock/models.py:763 msgid "Uninstalled stock item" msgstr "" -#: stock/models.py:768 +#: stock/models.py:782 msgid "Uninstalled into location" msgstr "" -#: stock/models.py:848 +#: stock/models.py:862 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:854 +#: stock/models.py:868 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:860 +#: stock/models.py:874 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:863 +#: stock/models.py:877 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:866 +#: stock/models.py:880 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:898 +#: stock/models.py:912 msgid "Add serial number" msgstr "" -#: stock/models.py:901 +#: stock/models.py:915 #, python-brace-format msgid "Serialized {n} items" msgstr "" -#: stock/models.py:1012 +#: stock/models.py:1026 msgid "StockItem cannot be moved as it is not in stock" msgstr "" -#: stock/models.py:1418 +#: stock/models.py:1432 msgid "Tracking entry title" msgstr "" -#: stock/models.py:1420 +#: stock/models.py:1434 msgid "Entry notes" msgstr "" -#: stock/models.py:1422 +#: stock/models.py:1436 msgid "Link to external page for further information" msgstr "" -#: stock/models.py:1482 +#: stock/models.py:1496 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1488 +#: stock/models.py:1502 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1505 +#: stock/models.py:1519 msgid "Test" msgstr "" -#: stock/models.py:1506 +#: stock/models.py:1520 msgid "Test name" msgstr "" -#: stock/models.py:1511 +#: stock/models.py:1525 msgid "Result" msgstr "" -#: stock/models.py:1512 templates/js/table_filters.js:172 +#: stock/models.py:1526 templates/js/table_filters.js:172 msgid "Test result" msgstr "" -#: stock/models.py:1518 +#: stock/models.py:1532 msgid "Test output value" msgstr "" -#: stock/models.py:1524 +#: stock/models.py:1538 msgid "Attachment" msgstr "" -#: stock/models.py:1525 +#: stock/models.py:1539 msgid "Test result attachment" msgstr "" -#: stock/models.py:1531 +#: stock/models.py:1545 msgid "Test notes" msgstr "" @@ -5048,10 +5056,10 @@ msgid "Select Stock Items" msgstr "" #: templates/js/label.js:11 -msgid "Stock items must be selected before printing labels" +msgid "Stock item(s) must be selected before printing labels" msgstr "" -#: templates/js/label.js:29 +#: templates/js/label.js:29 templates/js/label.js:79 msgid "No Labels Found" msgstr "" @@ -5059,11 +5067,23 @@ msgstr "" msgid "No labels found which match selected stock item(s)" msgstr "" -#: templates/js/label.js:77 +#: 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:92 +#: templates/js/label.js:156 msgid "Select Label Template" msgstr "" From 6e4cf7c09213f177e6760678280e97d22a8f90d6 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 13 Jan 2021 22:07:30 +1100 Subject: [PATCH 22/32] Catch db integrity errors --- InvenTree/label/apps.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/InvenTree/label/apps.py b/InvenTree/label/apps.py index 74db58fe92..f93d6b7acc 100644 --- a/InvenTree/label/apps.py +++ b/InvenTree/label/apps.py @@ -75,13 +75,13 @@ class LabelConfig(AppConfig): logger.info(f"Copying label template '{dst_file}'") shutil.copyfile(src_file, dst_file) - # 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']}'") - 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'], @@ -89,7 +89,7 @@ class LabelConfig(AppConfig): filters='', enabled=True ) - except IntegrityError: + except: pass def create_stock_location_labels(self): @@ -151,13 +151,13 @@ class LabelConfig(AppConfig): logger.info(f"Copying label template '{dst_file}'") shutil.copyfile(src_file, dst_file) - # 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']}'") - 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'], @@ -165,5 +165,5 @@ class LabelConfig(AppConfig): filters='', enabled=True ) - except IntegrityError: + except: pass From 88a7b3251d96513111e20282e840d5e0f68aa9c8 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 14 Jan 2021 08:14:32 +1100 Subject: [PATCH 23/32] Remove unused import --- InvenTree/label/apps.py | 1 - 1 file changed, 1 deletion(-) diff --git a/InvenTree/label/apps.py b/InvenTree/label/apps.py index f93d6b7acc..321047a551 100644 --- a/InvenTree/label/apps.py +++ b/InvenTree/label/apps.py @@ -2,7 +2,6 @@ import os import shutil import logging -from django.db.utils import IntegrityError from django.apps import AppConfig from django.conf import settings From 9884fe5c5e733effe39292429ef4f0fa3fb9b8aa Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 14 Jan 2021 08:15:05 +1100 Subject: [PATCH 24/32] Improve validators for 'filters' field --- InvenTree/InvenTree/helpers.py | 13 ++++++- .../migrations/0005_auto_20210113_2302.py | 24 ++++++++++++ InvenTree/label/models.py | 37 +++++++++++++++---- 3 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 InvenTree/label/migrations/0005_auto_20210113_2302.py diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 37a8bf82e1..e65e67951e 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: + query = model.objects.filter(**results) + except FieldError as e: + raise ValidationError( + str(e), + ) + return results 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 3e693b1e50..a34aa3831d 100644 --- a/InvenTree/label/models.py +++ b/InvenTree/label/models.py @@ -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. @@ -71,13 +85,6 @@ class LabelTemplate(models.Model): validators=[FileExtensionValidator(allowed_extensions=['html'])], ) - filters = models.CharField( - blank=True, max_length=250, - help_text=_('Query filters (comma-separated list of key=value pairs'), - verbose_name=_('Filters'), - validators=[validateFilterString] - ) - enabled = models.BooleanField( default=True, verbose_name=_('Enabled'), @@ -125,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 @@ -170,6 +185,14 @@ class StockLocationLabel(LabelTemplate): 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 From b7bbc972182a4e4660ee3eece7f5812abf450c47 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 14 Jan 2021 08:32:37 +1100 Subject: [PATCH 25/32] Add unit test --- InvenTree/InvenTree/helpers.py | 2 +- InvenTree/label/tests.py | 75 +++++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index e65e67951e..6b76c7d41b 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -467,7 +467,7 @@ def validateFilterString(value, model=None): # If a model is provided, verify that the provided filters can be used against it if model is not None: try: - query = model.objects.filter(**results) + model.objects.filter(**results) except FieldError as e: raise ValidationError( str(e), diff --git a/InvenTree/label/tests.py b/InvenTree/label/tests.py index a39b155ac3..442fdb53aa 100644 --- a/InvenTree/label/tests.py +++ b/InvenTree/label/tests.py @@ -1 +1,74 @@ -# 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): + + 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) + + 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) From df335b683c4f4641ef29dd643b0a100f523fbaae Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 14 Jan 2021 10:54:34 +1100 Subject: [PATCH 26/32] Add #TODO --- InvenTree/label/tests.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/InvenTree/label/tests.py b/InvenTree/label/tests.py index 442fdb53aa..dcb051c929 100644 --- a/InvenTree/label/tests.py +++ b/InvenTree/label/tests.py @@ -17,6 +17,7 @@ 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 @@ -30,6 +31,7 @@ class LabelTest(TestCase): 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 From a70416abac6bb9e8ef62a90c442f9fdf1f7f6ae8 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Jan 2021 00:04:31 +1100 Subject: [PATCH 27/32] Update translations --- InvenTree/locale/de/LC_MESSAGES/django.po | 656 +++++++++++++--------- InvenTree/locale/en/LC_MESSAGES/django.po | 626 +++++++++++++-------- InvenTree/locale/es/LC_MESSAGES/django.po | 626 +++++++++++++-------- 3 files changed, 1166 insertions(+), 742 deletions(-) diff --git a/InvenTree/locale/de/LC_MESSAGES/django.po b/InvenTree/locale/de/LC_MESSAGES/django.po index dd0eb2089c..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-14 17:54+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:233 order/models.py:331 -#: 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:861 +#: 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" @@ -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:852 -#: templates/js/stock.js:1091 +#: templates/js/bom.js:195 templates/js/build.js:420 templates/js/stock.js:864 +#: templates/js/stock.js:1103 msgid "Quantity" msgstr "Anzahl" @@ -455,7 +455,7 @@ 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 @@ -463,7 +463,7 @@ msgstr "Referenz" #: 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:511 templates/js/stock.js:833 +#: templates/js/stock.js:511 templates/js/stock.js:845 msgid "Description" msgstr "Beschreibung" @@ -484,7 +484,7 @@ 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:652 +#: 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 @@ -493,7 +493,7 @@ msgstr "Bestellung, die diesem Bau zugwiesen ist" #: 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:485 -#: templates/js/stock.js:1163 +#: 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:437 +#: 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,7 +590,7 @@ 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:295 templates/js/stock.js:127 templates/js/stock.js:618 msgid "Notes" @@ -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:736 +#: 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:739 +#: build/models.py:975 order/models.py:738 msgid "Allocation quantity must be greater than zero" msgstr "Anzahl muss größer null sein" @@ -837,7 +837,7 @@ msgstr "Bau-Status" #: 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:185 templates/js/order.js:279 -#: templates/js/stock.js:584 templates/js/stock.js:1099 +#: templates/js/stock.js:584 templates/js/stock.js:1111 msgid "Status" msgstr "Status" @@ -861,7 +861,7 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:120 -#: build/templates/build/detail.html:82 order/models.py:650 +#: 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 @@ -1002,7 +1002,7 @@ 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:592 -#: templates/js/stock.js:1106 templates/js/table_filters.js:80 +#: templates/js/stock.js:1118 templates/js/table_filters.js:80 #: templates/js/table_filters.js:161 msgid "Batch" msgstr "Los" @@ -1118,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" @@ -1140,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" @@ -1266,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" @@ -1282,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" @@ -1710,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" @@ -1828,8 +1828,8 @@ 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 +#: 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" @@ -1845,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:983 +#: part/templates/part/supplier.html:14 templates/js/stock.js:995 msgid "New Supplier Part" msgstr "Neues Zulieferer-Teil" @@ -1873,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:977 +#: part/templates/part/category.html:116 templates/js/stock.js:989 msgid "New Part" msgstr "Neues Teil" @@ -1966,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" @@ -2127,7 +2127,7 @@ msgstr "Firma gelöscht" msgid "Edit Supplier Part" msgstr "Zuliefererteil bearbeiten" -#: company/views.py:295 templates/js/stock.js:984 +#: company/views.py:295 templates/js/stock.js:996 msgid "Create new Supplier Part" msgstr "Neues Zuliefererteil anlegen" @@ -2149,32 +2149,54 @@ 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" +#: label/models.py:90 report/models.py:162 +msgid "Enabled" msgstr "" -#: label/models.py:75 +#: label/models.py:91 msgid "Label template is enabled" msgstr "" -#: label/models.py:76 report/models.py:162 -msgid "Enabled" +#: 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 @@ -2214,7 +2236,7 @@ msgstr "" msgid "Enter sales order number" msgstr "Auftrag stornieren" -#: order/forms.py:140 order/models.py:438 +#: order/forms.py:140 order/models.py:437 msgid "" "Target date for order completion. Order will be overdue after this date." msgstr "" @@ -2235,138 +2257,138 @@ msgstr "Link auf externe Seite" msgid "Order notes" msgstr "Bestell-Notizen" -#: order/models.py:172 order/models.py:431 +#: order/models.py:171 order/models.py:430 #, fuzzy #| msgid "Purchase Order Details" msgid "Purchase order status" msgstr "Bestelldetails" -#: order/models.py:180 +#: order/models.py:179 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:183 +#: order/models.py:182 msgid "Supplier order reference code" msgstr "Bestellreferenz" -#: order/models.py:194 +#: order/models.py:193 #, fuzzy #| msgid "Issue Order" msgid "Issue Date" msgstr "Bestellung aufgeben" -#: order/models.py:195 +#: order/models.py:194 msgid "Date order was issued" msgstr "" -#: order/models.py:200 +#: order/models.py:199 #, fuzzy #| msgid "Shipment Date" msgid "Target Delivery Date" msgstr "Versanddatum" -#: order/models.py:201 +#: order/models.py:200 msgid "" "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:206 +#: order/models.py:205 #, fuzzy #| msgid "Creation Date" msgid "Completion Date" msgstr "Erstelldatum" -#: order/models.py:207 +#: order/models.py:206 #, fuzzy #| msgid "Mark order as complete" msgid "Date order was completed" msgstr "Bestellung als vollständig markieren" -#: order/models.py:231 order/models.py:329 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:236 +#: order/models.py:235 msgid "Part supplier must match PO supplier" msgstr "Teile-Zulieferer muss dem Zulieferer des Kaufvertrags entsprechen" -#: order/models.py:324 +#: 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:427 +#: order/models.py:426 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:433 +#: order/models.py:432 msgid "Customer order reference code" msgstr "Bestellreferenz" -#: order/models.py:491 +#: 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:578 +#: order/models.py:577 msgid "Item quantity" msgstr "Anzahl" -#: order/models.py:580 +#: order/models.py:579 msgid "Line item reference" msgstr "Position - Referenz" -#: order/models.py:582 +#: order/models.py:581 msgid "Line item notes" msgstr "Position - Notizen" -#: order/models.py:608 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:145 msgid "Purchase Order" msgstr "Kaufvertrag" -#: order/models.py:621 +#: order/models.py:620 msgid "Supplier part" msgstr "Zulieferer-Teil" -#: order/models.py:624 +#: order/models.py:623 msgid "Number of items received" msgstr "Empfangene Objekt-Anzahl" -#: order/models.py:631 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:632 +#: order/models.py:631 #, fuzzy #| msgid "Purchase Order" msgid "Unit purchase price" msgstr "Kaufvertrag" -#: order/models.py:727 +#: 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:729 +#: 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:732 +#: order/models.py:731 msgid "Allocation quantity cannot exceed stock quantity" msgstr "zugewiesene Anzahl darf nicht die verfügbare Anzahl überschreiten" -#: order/models.py:742 +#: 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:758 +#: order/models.py:757 msgid "Select stock item to allocate" msgstr "Lagerobjekt für Zuordnung auswählen" -#: order/models.py:761 +#: order/models.py:760 msgid "Enter stock allocation quantity" msgstr "Zuordnungsanzahl eingeben" @@ -2509,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:642 templates/js/stock.js:989 +#: templates/js/stock.js:642 templates/js/stock.js:1001 msgid "New Location" msgstr "Neuer Standort" @@ -2598,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" @@ -3315,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" @@ -3362,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:822 templates/js/stock.js:1082 +#: templates/js/stock.js:834 templates/js/stock.js:1094 msgid "Stock Item" msgstr "Lagerobjekt" @@ -3649,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" @@ -3795,13 +3817,13 @@ msgstr "Parameter hinzufügen" msgid "New Parameter" msgstr "Neuer Parameter" -#: part/templates/part/params.html:25 stock/models.py:1499 +#: 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:158 +#: part/templates/part/supplier.html:19 users/models.py:159 msgid "Delete" msgstr "Löschen" @@ -4126,7 +4148,7 @@ msgstr "Teil kopiert" msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:594 templates/js/stock.js:978 +#: part/views.py:594 templates/js/stock.js:990 msgid "Create New Part" msgstr "Neues Teil anlegen" @@ -4336,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" @@ -4400,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" @@ -4418,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 +#: 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" @@ -4785,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" @@ -4821,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:1119 +#: stock/templates/stock/item_base.html:158 templates/js/stock.js:1131 #, fuzzy #| msgid "Installed in Stock Item" msgid "Uninstall stock item" @@ -5048,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" @@ -5086,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" @@ -5720,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 "" @@ -5905,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" @@ -5955,6 +5961,162 @@ 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" @@ -5965,7 +6127,7 @@ msgstr "Keine Bestellungen gefunden" msgid "Order is overdue" msgstr "Bau-Zuweisung ist vollständig" -#: templates/js/order.js:193 templates/js/stock.js:804 +#: templates/js/order.js:193 templates/js/stock.js:816 msgid "Date" msgstr "Datum" @@ -6008,7 +6170,7 @@ msgid "No parts found" msgstr "Keine Teile gefunden" #: templates/js/part.js:343 templates/js/stock.js:473 -#: templates/js/stock.js:1151 +#: templates/js/stock.js:1163 msgid "Select" msgstr "Auswählen" @@ -6182,51 +6344,51 @@ msgstr "Löschen" msgid "Stocktake" msgstr "Letzte Inventur" -#: templates/js/stock.js:720 +#: templates/js/stock.js:732 #, fuzzy #| msgid "Stock status" msgid "Stock Status" msgstr "Bestandsstatus" -#: templates/js/stock.js:735 +#: templates/js/stock.js:747 #, fuzzy #| msgid "Stock status" msgid "Set Stock Status" msgstr "Bestandsstatus" -#: templates/js/stock.js:749 +#: 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:750 +#: 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:870 +#: templates/js/stock.js:882 msgid "No user information" msgstr "Keine Benutzerinformation" -#: templates/js/stock.js:990 +#: templates/js/stock.js:1002 msgid "Create New Location" msgstr "Neuen Standort anlegen" -#: templates/js/stock.js:1089 +#: templates/js/stock.js:1101 #, fuzzy #| msgid "Serial Number" msgid "Serial" msgstr "Seriennummer" -#: templates/js/stock.js:1182 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:1207 +#: templates/js/stock.js:1219 #, fuzzy #| msgid "Installed In" msgid "Install item" @@ -6415,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" @@ -6491,59 +6643,63 @@ 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:26 +#: templates/stock_table.html:27 #, fuzzy #| msgid "Settings" msgid "Change status" msgstr "Einstellungen" -#: templates/stock_table.html:26 +#: templates/stock_table.html:27 #, fuzzy #| msgid "Stock status" msgid "Change stock status" msgstr "Bestandsstatus" -#: templates/stock_table.html:29 +#: templates/stock_table.html:30 #, fuzzy #| msgid "Delete line item" msgid "Delete selected items" msgstr "Position löschen" -#: templates/stock_table.html:29 +#: templates/stock_table.html:30 msgid "Delete Stock" msgstr "Bestand löschen" @@ -6579,41 +6735,41 @@ msgstr "Revision" msgid "Important dates" msgstr "Stückliste importieren" -#: users/models.py:141 +#: users/models.py:142 msgid "Permission set" msgstr "" -#: users/models.py:149 +#: users/models.py:150 msgid "Group" msgstr "" -#: users/models.py:152 +#: users/models.py:153 msgid "View" msgstr "" -#: users/models.py:152 +#: users/models.py:153 msgid "Permission to view items" msgstr "" -#: users/models.py:154 +#: users/models.py:155 #, fuzzy #| msgid "Address" msgid "Add" msgstr "Adresse" -#: users/models.py:154 +#: users/models.py:155 msgid "Permission to add items" msgstr "" -#: users/models.py:156 +#: users/models.py:157 msgid "Change" msgstr "" -#: users/models.py:156 +#: users/models.py:157 msgid "Permissions to edit items" msgstr "" -#: users/models.py:158 +#: 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 e5967684a0..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-14 17:54+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:233 order/models.py:331 -#: 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:861 +#: 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 "" @@ -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:852 -#: templates/js/stock.js:1091 +#: templates/js/bom.js:195 templates/js/build.js:420 templates/js/stock.js:864 +#: templates/js/stock.js:1103 msgid "Quantity" msgstr "" @@ -397,7 +397,7 @@ 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 @@ -405,7 +405,7 @@ msgstr "" #: 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:511 templates/js/stock.js:833 +#: templates/js/stock.js:511 templates/js/stock.js:845 msgid "Description" msgstr "" @@ -424,7 +424,7 @@ 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:652 +#: 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 @@ -433,7 +433,7 @@ msgstr "" #: 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:485 -#: templates/js/stock.js:1163 +#: 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:437 +#: 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,7 +520,7 @@ 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:295 templates/js/stock.js:127 templates/js/stock.js:618 msgid "Notes" @@ -564,11 +564,11 @@ msgstr "" msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:971 order/models.py:736 +#: build/models.py:971 order/models.py:735 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:975 order/models.py:739 +#: build/models.py:975 order/models.py:738 msgid "Allocation quantity must be greater than zero" msgstr "" @@ -724,7 +724,7 @@ msgstr "" #: 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:185 templates/js/order.js:279 -#: templates/js/stock.js:584 templates/js/stock.js:1099 +#: templates/js/stock.js:584 templates/js/stock.js:1111 msgid "Status" msgstr "" @@ -746,7 +746,7 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:120 -#: build/templates/build/detail.html:82 order/models.py:650 +#: 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 @@ -854,7 +854,7 @@ msgstr "" #: build/templates/build/detail.html:68 #: stock/templates/stock/item_base.html:262 templates/js/stock.js:592 -#: templates/js/stock.js:1106 templates/js/table_filters.js:80 +#: templates/js/stock.js:1118 templates/js/table_filters.js:80 #: templates/js/table_filters.js:161 msgid "Batch" msgstr "" @@ -953,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 "" @@ -969,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 "" @@ -1063,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 "" @@ -1079,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 "" @@ -1427,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 "" @@ -1537,8 +1537,8 @@ 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 +#: 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 "" @@ -1554,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:983 +#: part/templates/part/supplier.html:14 templates/js/stock.js:995 msgid "New Supplier Part" msgstr "" @@ -1578,7 +1578,7 @@ msgid "Delete Parts" msgstr "" #: company/templates/company/detail_part.html:63 -#: part/templates/part/category.html:116 templates/js/stock.js:977 +#: part/templates/part/category.html:116 templates/js/stock.js:989 msgid "New Part" msgstr "" @@ -1670,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 "" @@ -1825,7 +1825,7 @@ msgstr "" msgid "Edit Supplier Part" msgstr "" -#: company/views.py:295 templates/js/stock.js:984 +#: company/views.py:295 templates/js/stock.js:996 msgid "Create new Supplier Part" msgstr "" @@ -1845,28 +1845,48 @@ 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 +#: label/models.py:76 +msgid "Label description" +msgstr "" + +#: 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 "" + +#: label/models.py:91 msgid "Label template is enabled" msgstr "" -#: label/models.py:76 report/models.py:162 -msgid "Enabled" +#: 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 @@ -1902,7 +1922,7 @@ msgstr "" msgid "Enter sales order number" msgstr "" -#: order/forms.py:140 order/models.py:438 +#: order/forms.py:140 order/models.py:437 msgid "" "Target date for order completion. Order will be overdue after this date." msgstr "" @@ -1923,124 +1943,124 @@ msgstr "" msgid "Order notes" msgstr "" -#: order/models.py:172 order/models.py:431 +#: order/models.py:171 order/models.py:430 msgid "Purchase order status" msgstr "" -#: order/models.py:180 +#: order/models.py:179 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:183 +#: order/models.py:182 msgid "Supplier order reference code" msgstr "" -#: order/models.py:194 +#: order/models.py:193 msgid "Issue Date" msgstr "" -#: order/models.py:195 +#: order/models.py:194 msgid "Date order was issued" msgstr "" -#: order/models.py:200 +#: order/models.py:199 msgid "Target Delivery Date" msgstr "" -#: order/models.py:201 +#: order/models.py:200 msgid "" "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:206 +#: order/models.py:205 msgid "Completion Date" msgstr "" -#: order/models.py:207 +#: order/models.py:206 msgid "Date order was completed" msgstr "" -#: order/models.py:231 order/models.py:329 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:236 +#: order/models.py:235 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:324 +#: order/models.py:323 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:427 +#: order/models.py:426 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:433 +#: order/models.py:432 msgid "Customer order reference code" msgstr "" -#: order/models.py:491 +#: order/models.py:490 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:578 +#: order/models.py:577 msgid "Item quantity" msgstr "" -#: order/models.py:580 +#: order/models.py:579 msgid "Line item reference" msgstr "" -#: order/models.py:582 +#: order/models.py:581 msgid "Line item notes" msgstr "" -#: order/models.py:608 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:145 msgid "Purchase Order" msgstr "" -#: order/models.py:621 +#: order/models.py:620 msgid "Supplier part" msgstr "" -#: order/models.py:624 +#: order/models.py:623 msgid "Number of items received" msgstr "" -#: order/models.py:631 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:632 +#: order/models.py:631 msgid "Unit purchase price" msgstr "" -#: order/models.py:727 +#: order/models.py:726 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:729 +#: order/models.py:728 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:732 +#: order/models.py:731 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:742 +#: order/models.py:741 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:758 +#: order/models.py:757 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:761 +#: order/models.py:760 msgid "Enter stock allocation quantity" msgstr "" @@ -2170,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:642 templates/js/stock.js:989 +#: templates/js/stock.js:642 templates/js/stock.js:1001 msgid "New Location" msgstr "" @@ -2255,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 "" @@ -2898,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 "" @@ -2937,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:822 templates/js/stock.js:1082 +#: templates/js/stock.js:834 templates/js/stock.js:1094 msgid "Stock Item" msgstr "" @@ -3170,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 "" @@ -3296,13 +3316,13 @@ msgstr "" msgid "New Parameter" msgstr "" -#: part/templates/part/params.html:25 stock/models.py:1499 +#: 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:158 +#: part/templates/part/supplier.html:19 users/models.py:159 msgid "Delete" msgstr "" @@ -3575,7 +3595,7 @@ msgstr "" msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:594 templates/js/stock.js:978 +#: part/views.py:594 templates/js/stock.js:990 msgid "Create New Part" msgstr "" @@ -3759,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 "" @@ -3807,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 "" @@ -3823,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 +#: 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 "" @@ -4137,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 "" @@ -4165,7 +4181,7 @@ msgstr "" msgid "Return to stock" msgstr "" -#: stock/templates/stock/item_base.html:158 templates/js/stock.js:1119 +#: stock/templates/stock/item_base.html:158 templates/js/stock.js:1131 msgid "Uninstall stock item" msgstr "" @@ -4348,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 "" @@ -4380,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 "" @@ -4888,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 "" @@ -5033,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 "" @@ -5077,6 +5085,136 @@ 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 "" @@ -5085,7 +5223,7 @@ msgstr "" msgid "Order is overdue" msgstr "" -#: templates/js/order.js:193 templates/js/stock.js:804 +#: templates/js/order.js:193 templates/js/stock.js:816 msgid "Date" msgstr "" @@ -5122,7 +5260,7 @@ msgid "No parts found" msgstr "" #: templates/js/part.js:343 templates/js/stock.js:473 -#: templates/js/stock.js:1151 +#: templates/js/stock.js:1163 msgid "Select" msgstr "" @@ -5254,39 +5392,39 @@ msgstr "" msgid "Stocktake" msgstr "" -#: templates/js/stock.js:720 +#: templates/js/stock.js:732 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:735 +#: templates/js/stock.js:747 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:749 +#: templates/js/stock.js:761 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:750 +#: templates/js/stock.js:762 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:870 +#: templates/js/stock.js:882 msgid "No user information" msgstr "" -#: templates/js/stock.js:990 +#: templates/js/stock.js:1002 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1089 +#: templates/js/stock.js:1101 msgid "Serial" msgstr "" -#: templates/js/stock.js:1182 templates/js/table_filters.js:131 +#: templates/js/stock.js:1194 templates/js/table_filters.js:131 msgid "Installed" msgstr "" -#: templates/js/stock.js:1207 +#: templates/js/stock.js:1219 msgid "Install item" msgstr "" @@ -5439,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 "" @@ -5507,43 +5637,47 @@ 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:26 +#: templates/stock_table.html:27 msgid "Change status" msgstr "" -#: templates/stock_table.html:26 +#: templates/stock_table.html:27 msgid "Change stock status" msgstr "" -#: templates/stock_table.html:29 +#: templates/stock_table.html:30 msgid "Delete selected items" msgstr "" -#: templates/stock_table.html:29 +#: templates/stock_table.html:30 msgid "Delete Stock" msgstr "" @@ -5571,38 +5705,38 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:141 +#: users/models.py:142 msgid "Permission set" msgstr "" -#: users/models.py:149 +#: users/models.py:150 msgid "Group" msgstr "" -#: users/models.py:152 +#: users/models.py:153 msgid "View" msgstr "" -#: users/models.py:152 +#: users/models.py:153 msgid "Permission to view items" msgstr "" -#: users/models.py:154 +#: users/models.py:155 msgid "Add" msgstr "" -#: users/models.py:154 +#: users/models.py:155 msgid "Permission to add items" msgstr "" -#: users/models.py:156 +#: users/models.py:157 msgid "Change" msgstr "" -#: users/models.py:156 +#: users/models.py:157 msgid "Permissions to edit items" msgstr "" -#: users/models.py:158 +#: 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 e5967684a0..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-14 17:54+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:233 order/models.py:331 -#: 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:861 +#: 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 "" @@ -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:852 -#: templates/js/stock.js:1091 +#: templates/js/bom.js:195 templates/js/build.js:420 templates/js/stock.js:864 +#: templates/js/stock.js:1103 msgid "Quantity" msgstr "" @@ -397,7 +397,7 @@ 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 @@ -405,7 +405,7 @@ msgstr "" #: 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:511 templates/js/stock.js:833 +#: templates/js/stock.js:511 templates/js/stock.js:845 msgid "Description" msgstr "" @@ -424,7 +424,7 @@ 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:652 +#: 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 @@ -433,7 +433,7 @@ msgstr "" #: 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:485 -#: templates/js/stock.js:1163 +#: 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:437 +#: 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,7 +520,7 @@ 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:295 templates/js/stock.js:127 templates/js/stock.js:618 msgid "Notes" @@ -564,11 +564,11 @@ msgstr "" msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:971 order/models.py:736 +#: build/models.py:971 order/models.py:735 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:975 order/models.py:739 +#: build/models.py:975 order/models.py:738 msgid "Allocation quantity must be greater than zero" msgstr "" @@ -724,7 +724,7 @@ msgstr "" #: 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:185 templates/js/order.js:279 -#: templates/js/stock.js:584 templates/js/stock.js:1099 +#: templates/js/stock.js:584 templates/js/stock.js:1111 msgid "Status" msgstr "" @@ -746,7 +746,7 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:120 -#: build/templates/build/detail.html:82 order/models.py:650 +#: 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 @@ -854,7 +854,7 @@ msgstr "" #: build/templates/build/detail.html:68 #: stock/templates/stock/item_base.html:262 templates/js/stock.js:592 -#: templates/js/stock.js:1106 templates/js/table_filters.js:80 +#: templates/js/stock.js:1118 templates/js/table_filters.js:80 #: templates/js/table_filters.js:161 msgid "Batch" msgstr "" @@ -953,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 "" @@ -969,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 "" @@ -1063,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 "" @@ -1079,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 "" @@ -1427,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 "" @@ -1537,8 +1537,8 @@ 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 +#: 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 "" @@ -1554,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:983 +#: part/templates/part/supplier.html:14 templates/js/stock.js:995 msgid "New Supplier Part" msgstr "" @@ -1578,7 +1578,7 @@ msgid "Delete Parts" msgstr "" #: company/templates/company/detail_part.html:63 -#: part/templates/part/category.html:116 templates/js/stock.js:977 +#: part/templates/part/category.html:116 templates/js/stock.js:989 msgid "New Part" msgstr "" @@ -1670,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 "" @@ -1825,7 +1825,7 @@ msgstr "" msgid "Edit Supplier Part" msgstr "" -#: company/views.py:295 templates/js/stock.js:984 +#: company/views.py:295 templates/js/stock.js:996 msgid "Create new Supplier Part" msgstr "" @@ -1845,28 +1845,48 @@ 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 +#: label/models.py:76 +msgid "Label description" +msgstr "" + +#: 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 "" + +#: label/models.py:91 msgid "Label template is enabled" msgstr "" -#: label/models.py:76 report/models.py:162 -msgid "Enabled" +#: 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 @@ -1902,7 +1922,7 @@ msgstr "" msgid "Enter sales order number" msgstr "" -#: order/forms.py:140 order/models.py:438 +#: order/forms.py:140 order/models.py:437 msgid "" "Target date for order completion. Order will be overdue after this date." msgstr "" @@ -1923,124 +1943,124 @@ msgstr "" msgid "Order notes" msgstr "" -#: order/models.py:172 order/models.py:431 +#: order/models.py:171 order/models.py:430 msgid "Purchase order status" msgstr "" -#: order/models.py:180 +#: order/models.py:179 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:183 +#: order/models.py:182 msgid "Supplier order reference code" msgstr "" -#: order/models.py:194 +#: order/models.py:193 msgid "Issue Date" msgstr "" -#: order/models.py:195 +#: order/models.py:194 msgid "Date order was issued" msgstr "" -#: order/models.py:200 +#: order/models.py:199 msgid "Target Delivery Date" msgstr "" -#: order/models.py:201 +#: order/models.py:200 msgid "" "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:206 +#: order/models.py:205 msgid "Completion Date" msgstr "" -#: order/models.py:207 +#: order/models.py:206 msgid "Date order was completed" msgstr "" -#: order/models.py:231 order/models.py:329 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:236 +#: order/models.py:235 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:324 +#: order/models.py:323 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:427 +#: order/models.py:426 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:433 +#: order/models.py:432 msgid "Customer order reference code" msgstr "" -#: order/models.py:491 +#: order/models.py:490 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:578 +#: order/models.py:577 msgid "Item quantity" msgstr "" -#: order/models.py:580 +#: order/models.py:579 msgid "Line item reference" msgstr "" -#: order/models.py:582 +#: order/models.py:581 msgid "Line item notes" msgstr "" -#: order/models.py:608 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:145 msgid "Purchase Order" msgstr "" -#: order/models.py:621 +#: order/models.py:620 msgid "Supplier part" msgstr "" -#: order/models.py:624 +#: order/models.py:623 msgid "Number of items received" msgstr "" -#: order/models.py:631 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:632 +#: order/models.py:631 msgid "Unit purchase price" msgstr "" -#: order/models.py:727 +#: order/models.py:726 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:729 +#: order/models.py:728 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:732 +#: order/models.py:731 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:742 +#: order/models.py:741 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:758 +#: order/models.py:757 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:761 +#: order/models.py:760 msgid "Enter stock allocation quantity" msgstr "" @@ -2170,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:642 templates/js/stock.js:989 +#: templates/js/stock.js:642 templates/js/stock.js:1001 msgid "New Location" msgstr "" @@ -2255,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 "" @@ -2898,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 "" @@ -2937,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:822 templates/js/stock.js:1082 +#: templates/js/stock.js:834 templates/js/stock.js:1094 msgid "Stock Item" msgstr "" @@ -3170,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 "" @@ -3296,13 +3316,13 @@ msgstr "" msgid "New Parameter" msgstr "" -#: part/templates/part/params.html:25 stock/models.py:1499 +#: 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:158 +#: part/templates/part/supplier.html:19 users/models.py:159 msgid "Delete" msgstr "" @@ -3575,7 +3595,7 @@ msgstr "" msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:594 templates/js/stock.js:978 +#: part/views.py:594 templates/js/stock.js:990 msgid "Create New Part" msgstr "" @@ -3759,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 "" @@ -3807,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 "" @@ -3823,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 +#: 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 "" @@ -4137,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 "" @@ -4165,7 +4181,7 @@ msgstr "" msgid "Return to stock" msgstr "" -#: stock/templates/stock/item_base.html:158 templates/js/stock.js:1119 +#: stock/templates/stock/item_base.html:158 templates/js/stock.js:1131 msgid "Uninstall stock item" msgstr "" @@ -4348,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 "" @@ -4380,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 "" @@ -4888,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 "" @@ -5033,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 "" @@ -5077,6 +5085,136 @@ 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 "" @@ -5085,7 +5223,7 @@ msgstr "" msgid "Order is overdue" msgstr "" -#: templates/js/order.js:193 templates/js/stock.js:804 +#: templates/js/order.js:193 templates/js/stock.js:816 msgid "Date" msgstr "" @@ -5122,7 +5260,7 @@ msgid "No parts found" msgstr "" #: templates/js/part.js:343 templates/js/stock.js:473 -#: templates/js/stock.js:1151 +#: templates/js/stock.js:1163 msgid "Select" msgstr "" @@ -5254,39 +5392,39 @@ msgstr "" msgid "Stocktake" msgstr "" -#: templates/js/stock.js:720 +#: templates/js/stock.js:732 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:735 +#: templates/js/stock.js:747 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:749 +#: templates/js/stock.js:761 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:750 +#: templates/js/stock.js:762 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:870 +#: templates/js/stock.js:882 msgid "No user information" msgstr "" -#: templates/js/stock.js:990 +#: templates/js/stock.js:1002 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1089 +#: templates/js/stock.js:1101 msgid "Serial" msgstr "" -#: templates/js/stock.js:1182 templates/js/table_filters.js:131 +#: templates/js/stock.js:1194 templates/js/table_filters.js:131 msgid "Installed" msgstr "" -#: templates/js/stock.js:1207 +#: templates/js/stock.js:1219 msgid "Install item" msgstr "" @@ -5439,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 "" @@ -5507,43 +5637,47 @@ 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:26 +#: templates/stock_table.html:27 msgid "Change status" msgstr "" -#: templates/stock_table.html:26 +#: templates/stock_table.html:27 msgid "Change stock status" msgstr "" -#: templates/stock_table.html:29 +#: templates/stock_table.html:30 msgid "Delete selected items" msgstr "" -#: templates/stock_table.html:29 +#: templates/stock_table.html:30 msgid "Delete Stock" msgstr "" @@ -5571,38 +5705,38 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:141 +#: users/models.py:142 msgid "Permission set" msgstr "" -#: users/models.py:149 +#: users/models.py:150 msgid "Group" msgstr "" -#: users/models.py:152 +#: users/models.py:153 msgid "View" msgstr "" -#: users/models.py:152 +#: users/models.py:153 msgid "Permission to view items" msgstr "" -#: users/models.py:154 +#: users/models.py:155 msgid "Add" msgstr "" -#: users/models.py:154 +#: users/models.py:155 msgid "Permission to add items" msgstr "" -#: users/models.py:156 +#: users/models.py:157 msgid "Change" msgstr "" -#: users/models.py:156 +#: users/models.py:157 msgid "Permissions to edit items" msgstr "" -#: users/models.py:158 +#: users/models.py:159 msgid "Permission to delete items" msgstr "" From 85bce24e307c33a6930a96e8e0ca26736735c616 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Jan 2021 12:32:27 +1100 Subject: [PATCH 28/32] Limit matches to the 5 "most matchy" ones --- InvenTree/part/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 26cf93e56d..6367921fbf 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -655,7 +655,9 @@ class PartCreate(AjaxCreateView): matches = match_part_names(name) if len(matches) > 0: - context['matches'] = matches + + # Limit to the top 5 matches (to prevent clutter) + context['matches'] = matches[:5] # Enforce display of the checkbox form.fields['confirm_creation'].widget = CheckboxInput() From ef3ac43c4acca3081e12f45fc9d3a6fcf2d54950 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Jan 2021 15:27:40 +1100 Subject: [PATCH 29/32] Add "last updated" date to stock table --- InvenTree/stock/serializers.py | 1 + InvenTree/templates/js/stock.js | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index 6048d5e248..b8e71ff58c 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -213,6 +213,7 @@ class StockItemSerializer(InvenTreeModelSerializer): 'supplier_part_detail', 'tracking_items', 'uid', + 'updated', ] """ These fields are read-only in this context. diff --git a/InvenTree/templates/js/stock.js b/InvenTree/templates/js/stock.js index 836fa0e242..276be131f0 100644 --- a/InvenTree/templates/js/stock.js +++ b/InvenTree/templates/js/stock.js @@ -613,6 +613,11 @@ function loadStockTable(table, options) { sortable: true, }, {% endif %} + { + field: 'updated', + title: '{% trans "Last Updated" %}', + sortable: true, + }, { field: 'notes', title: '{% trans "Notes" %}', From fc32d99327904a62d18de6bddb437d5ea0185cc7 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Jan 2021 16:39:50 +1100 Subject: [PATCH 30/32] Add "updated_before" and "updated_after" filter for stock API --- InvenTree/stock/api.py | 53 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 9f0a4278f5..c8211aaeca 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -644,7 +644,7 @@ class StockList(generics.ListCreateAPIView): queryset = queryset.filter(Q(sales_order_allocations__isnull=True) & Q(allocations__isnull=True)) # Do we wish to filter by "active parts" - active = self.request.query_params.get('active', None) + active = params.get('active', None) if active is not None: active = str2bool(active) @@ -683,7 +683,7 @@ class StockList(generics.ListCreateAPIView): raise ValidationError({"part": "Invalid Part ID specified"}) # Does the client wish to filter by the 'ancestor'? - anc_id = self.request.query_params.get('ancestor', None) + anc_id = params.get('ancestor', None) if anc_id: try: @@ -696,9 +696,9 @@ class StockList(generics.ListCreateAPIView): raise ValidationError({"ancestor": "Invalid ancestor ID specified"}) # Does the client wish to filter by stock location? - loc_id = self.request.query_params.get('location', None) + loc_id = params.get('location', None) - cascade = str2bool(self.request.query_params.get('cascade', True)) + cascade = str2bool(params.get('cascade', True)) if loc_id is not None: @@ -718,7 +718,7 @@ class StockList(generics.ListCreateAPIView): pass # Does the client wish to filter by part category? - cat_id = self.request.query_params.get('category', None) + cat_id = params.get('category', None) if cat_id: try: @@ -729,35 +729,68 @@ class StockList(generics.ListCreateAPIView): raise ValidationError({"category": "Invalid category id specified"}) # Filter by StockItem status - status = self.request.query_params.get('status', None) + status = params.get('status', None) if status: queryset = queryset.filter(status=status) # Filter by supplier_part ID - supplier_part_id = self.request.query_params.get('supplier_part', None) + supplier_part_id = params.get('supplier_part', None) if supplier_part_id: queryset = queryset.filter(supplier_part=supplier_part_id) # Filter by company (either manufacturer or supplier) - company = self.request.query_params.get('company', None) + company = params.get('company', None) if company is not None: queryset = queryset.filter(Q(supplier_part__supplier=company) | Q(supplier_part__manufacturer=company)) # Filter by supplier - supplier = self.request.query_params.get('supplier', None) + supplier = params.get('supplier', None) if supplier is not None: queryset = queryset.filter(supplier_part__supplier=supplier) # Filter by manufacturer - manufacturer = self.request.query_params.get('manufacturer', None) + manufacturer = params.get('manufacturer', None) if manufacturer is not None: queryset = queryset.filter(supplier_part__manufacturer=manufacturer) + """ + Filter by the 'last updated' date of the stock item(s): + + - updated_before=? : Filter stock items which were last updated *before* the provided date + - updated_after=? : Filter stock items which were last updated *after* the provided date + """ + + date_fmt = '%Y-%m-%d' # ISO format date string + + updated_before = params.get('updated_before', None) + updated_after = params.get('updated_after', None) + + if updated_before: + try: + updated_before = datetime.strptime(str(updated_before), date_fmt).date() + queryset = queryset.filter(updated__lte=updated_before) + + print("Before:", updated_before.isoformat()) + except (ValueError, TypeError): + # Account for improperly formatted date string + print("After before:", str(updated_before)) + pass + + if updated_after: + try: + updated_after = datetime.strptime(str(updated_after), date_fmt).date() + queryset = queryset.filter(updated__gte=updated_after) + print("After:", updated_after.isoformat()) + except (ValueError, TypeError): + # Account for improperly formatted date string + print("After error:", str(updated_after)) + pass + # Also ensure that we pre-fecth all the related items queryset = queryset.prefetch_related( 'part', From 4952c95c33fb2d7412d92cad2e20b3a1175a5666 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Jan 2021 16:51:34 +1100 Subject: [PATCH 31/32] Extra check to prevent JS crash --- InvenTree/InvenTree/static/script/inventree/tables.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/static/script/inventree/tables.js b/InvenTree/InvenTree/static/script/inventree/tables.js index 4d868f94b4..ef17d91015 100644 --- a/InvenTree/InvenTree/static/script/inventree/tables.js +++ b/InvenTree/InvenTree/static/script/inventree/tables.js @@ -154,7 +154,7 @@ $.fn.inventreeTable = function(options) { // Which columns are currently visible? var visible = table.bootstrapTable('getVisibleColumns'); - if (visible) { + if (visible && isArray(visible)) { visible.forEach(function(column) { // Visible field should *not* be visible! (hide it!) From 0dee4df8fb8ec5b2ebca6e007eaab12d616c7e9f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Jan 2021 17:11:46 +1100 Subject: [PATCH 32/32] Bug fix --- InvenTree/InvenTree/static/script/inventree/tables.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/static/script/inventree/tables.js b/InvenTree/InvenTree/static/script/inventree/tables.js index ef17d91015..a40eb37285 100644 --- a/InvenTree/InvenTree/static/script/inventree/tables.js +++ b/InvenTree/InvenTree/static/script/inventree/tables.js @@ -154,7 +154,7 @@ $.fn.inventreeTable = function(options) { // Which columns are currently visible? var visible = table.bootstrapTable('getVisibleColumns'); - if (visible && isArray(visible)) { + if (visible && Array.isArray(visible)) { visible.forEach(function(column) { // Visible field should *not* be visible! (hide it!)