From 1356718bb709c0ce4b47b9d477eb21585fa4c884 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 00:19:43 +1000 Subject: [PATCH 01/23] Improver company website icon --- InvenTree/company/templates/company/company_base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/company/templates/company/company_base.html b/InvenTree/company/templates/company/company_base.html index 19ef2a0e60..8ec68a401c 100644 --- a/InvenTree/company/templates/company/company_base.html +++ b/InvenTree/company/templates/company/company_base.html @@ -46,7 +46,7 @@ InvenTree | {% trans "Company" %} - {{ company.name }} {% if company.website %} - + {% trans "Website" %} {{ company.website }} From 97f605ef55076dc4ee72abff26ddf381627effbc Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 00:19:51 +1000 Subject: [PATCH 02/23] Remove some weird trailing zeros --- InvenTree/stock/templates/stock/item_base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index 949823b83b..6c38335b3e 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -11,7 +11,7 @@ {% if item.serialized %}

{{ item.part.full_name}} # {{ item.serial }}

{% else %} -

{{ item.quantity }} × {{ item.part.full_name }}

+

{% decimal item.quantity %} × {{ item.part.full_name }}

{% endif %}

From 7fb89e4dbe2cbed4ef37e13073d4fa3f2a650049 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 08:08:54 +1000 Subject: [PATCH 03/23] Check for missing part thumbnails when the server first runs --- InvenTree/part/apps.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/InvenTree/part/apps.py b/InvenTree/part/apps.py index 43f6429c19..ae17f7ffe0 100644 --- a/InvenTree/part/apps.py +++ b/InvenTree/part/apps.py @@ -1,7 +1,36 @@ from __future__ import unicode_literals +import os + +from django.db.utils import OperationalError, ProgrammingError from django.apps import AppConfig +from django.conf import settings class PartConfig(AppConfig): name = 'part' + + def ready(self): + """ + This function is called whenever the Part app is loaded. + """ + + self.generate_part_thumbnails() + + def generate_part_thumbnails(self): + from .models import Part + + print("Checking Part image thumbnails") + + try: + for part in Part.objects.all(): + if part.image: + url = part.image.thumbnail.name + #if url.startswith('/'): + # url = url[1:] + loc = os.path.join(settings.MEDIA_ROOT, url) + if not os.path.exists(loc): + print("InvenTree: Generating thumbnail for Part '{p}'".format(p=part.name)) + part.image.render_variations(replace=False) + except (OperationalError, ProgrammingError): + print("Could not generate Part thumbnails") From 16d3a87e789d7ac994e273b9863c064b705e9d9e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 08:12:10 +1000 Subject: [PATCH 04/23] Delete old code --- InvenTree/part/apps.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/InvenTree/part/apps.py b/InvenTree/part/apps.py index ae17f7ffe0..7b61443d24 100644 --- a/InvenTree/part/apps.py +++ b/InvenTree/part/apps.py @@ -26,8 +26,6 @@ class PartConfig(AppConfig): for part in Part.objects.all(): if part.image: url = part.image.thumbnail.name - #if url.startswith('/'): - # url = url[1:] loc = os.path.join(settings.MEDIA_ROOT, url) if not os.path.exists(loc): print("InvenTree: Generating thumbnail for Part '{p}'".format(p=part.name)) From 1a233e7949616115d3f6fc3cbe6fcdd0ebb87665 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 11:17:00 +1000 Subject: [PATCH 05/23] Create thumbnails for Company model --- .../migrations/0014_auto_20200407_0116.py | 20 +++++++++++++++++++ InvenTree/company/models.py | 10 +++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 InvenTree/company/migrations/0014_auto_20200407_0116.py diff --git a/InvenTree/company/migrations/0014_auto_20200407_0116.py b/InvenTree/company/migrations/0014_auto_20200407_0116.py new file mode 100644 index 0000000000..03985a1ef3 --- /dev/null +++ b/InvenTree/company/migrations/0014_auto_20200407_0116.py @@ -0,0 +1,20 @@ +# Generated by Django 2.2.10 on 2020-04-07 01:16 + +import company.models +from django.db import migrations +import stdimage.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('company', '0013_auto_20200406_0131'), + ] + + operations = [ + migrations.AlterField( + model_name='company', + name='image', + field=stdimage.models.StdImageField(blank=True, null=True, upload_to=company.models.rename_company_image), + ), + ] diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index 6f14700184..a7dd2e53e8 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -21,6 +21,8 @@ from django.conf import settings from markdownx.models import MarkdownxField +from stdimage.models import StdImageField + from InvenTree.fields import InvenTreeURLField, RoundingDecimalField from InvenTree.status_codes import OrderStatus from common.models import Currency @@ -90,7 +92,13 @@ class Company(models.Model): link = InvenTreeURLField(blank=True, help_text=_('Link to external company information')) - image = models.ImageField(upload_to=rename_company_image, max_length=255, null=True, blank=True) + image = StdImageField( + upload_to=rename_company_image, + null=True, + blank=True, + variations={'thumnbnail': (128, 128)}, + delete_orphans=True, + ) notes = MarkdownxField(blank=True) From e0655f61d8c2ff1ffabcfb75e0e6837a739ba1cc Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 11:23:30 +1000 Subject: [PATCH 06/23] Check if Company thumbnails are created on Company app start --- InvenTree/company/apps.py | 31 ++++++++++++++++++++++++++++++- InvenTree/company/models.py | 2 +- InvenTree/part/apps.py | 3 ++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/InvenTree/company/apps.py b/InvenTree/company/apps.py index c55451e882..25f3bd96dc 100644 --- a/InvenTree/company/apps.py +++ b/InvenTree/company/apps.py @@ -1,7 +1,36 @@ from __future__ import unicode_literals -from django.apps import AppConfig +import os +from django.apps import AppConfig +from django.db.utils import OperationalError, ProgrammingError +from django.conf import settings class CompanyConfig(AppConfig): name = 'company' + + def ready(self): + """ + This function is called whenever the Company app is loaded. + """ + + self.generate_company_thumbs() + + def generate_company_thumbs(self): + + from .models import Company + + print("InvenTree: Checking Company image thumbnails") + + try: + for company in Company.objects.all(): + if company.image: + url = company.image.thumbnail.name + loc = os.path.join(settings.MEDIA_ROOT, url) + + if not os.path.exists(loc): + print("InvenTree: Generating thumbnail for Company '{c}'".format(c=company.name)) + company.image.render_variations(replace=False) + except (OperationalError, ProgrammingError): + print("Could not generate Company thumbnails") + \ No newline at end of file diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index a7dd2e53e8..59a6a2b37a 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -96,7 +96,7 @@ class Company(models.Model): upload_to=rename_company_image, null=True, blank=True, - variations={'thumnbnail': (128, 128)}, + variations={'thumbnail': (128, 128)}, delete_orphans=True, ) diff --git a/InvenTree/part/apps.py b/InvenTree/part/apps.py index 7b61443d24..95193a9527 100644 --- a/InvenTree/part/apps.py +++ b/InvenTree/part/apps.py @@ -20,13 +20,14 @@ class PartConfig(AppConfig): def generate_part_thumbnails(self): from .models import Part - print("Checking Part image thumbnails") + print("InvenTree: Checking Part image thumbnails") try: for part in Part.objects.all(): if part.image: url = part.image.thumbnail.name loc = os.path.join(settings.MEDIA_ROOT, url) + if not os.path.exists(loc): print("InvenTree: Generating thumbnail for Part '{p}'".format(p=part.name)) part.image.render_variations(replace=False) From ae9ef040130dc5aa7ba62cf9b8584e0e2c28f840 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 11:27:56 +1000 Subject: [PATCH 07/23] Use the company thumbnail in the Company API --- InvenTree/company/models.py | 8 ++++++++ InvenTree/company/serializers.py | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index 59a6a2b37a..69c98a008a 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -122,6 +122,14 @@ class Company(models.Model): else: return os.path.join(settings.STATIC_URL, 'img/blank_image.png') + def get_thumbnail_url(self): + """ Return the URL for the thumbnail image for this Company """ + + if self.image: + return os.path.join(settings.MEDIA_URL, str(self.image.thumbnail.url)) + else: + return os.path.join(settings.STATIC_URL, 'img/blank_image.thumbnail.png') + @property def part_count(self): """ The number of parts supplied by this company """ diff --git a/InvenTree/company/serializers.py b/InvenTree/company/serializers.py index 161edd286e..935712a180 100644 --- a/InvenTree/company/serializers.py +++ b/InvenTree/company/serializers.py @@ -32,7 +32,7 @@ class CompanySerializer(InvenTreeModelSerializer): url = serializers.CharField(source='get_absolute_url', read_only=True) part_count = serializers.CharField(read_only=True) - image = serializers.CharField(source='get_image_url', read_only=True) + image = serializers.CharField(source='get_thumbnail_url', read_only=True) class Meta: model = Company @@ -64,7 +64,7 @@ class SupplierPartSerializer(InvenTreeModelSerializer): part_detail = PartBriefSerializer(source='part', many=False, read_only=True) supplier_name = serializers.CharField(source='supplier.name', read_only=True) - supplier_logo = serializers.CharField(source='supplier.get_image_url', read_only=True) + supplier_logo = serializers.CharField(source='supplier.get_thumbnail_url', read_only=True) pricing = serializers.CharField(source='unit_pricing', read_only=True) From 95032141ce4c7384f1731b23bb0276adec003bc9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 11:38:57 +1000 Subject: [PATCH 08/23] Toot toot! It's the refactor tractor. - Create helper functions to qualify media and static files --- InvenTree/InvenTree/helpers.py | 35 ++++++++++++++++++++++++++++++++++ InvenTree/company/models.py | 11 ++++++----- InvenTree/part/models.py | 10 +++++----- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 5492f13a05..d46f35daf4 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -14,6 +14,41 @@ from django.core.exceptions import ValidationError from django.utils.translation import ugettext as _ from .version import inventreeVersion, inventreeInstanceName +from .settings import MEDIA_URL, STATIC_URL + + +def getMediaUrl(filename): + """ + Return the qualified access path for the given file, + under the media directory. + """ + + return os.path.join(MEDIA_URL, str(filename)) + + +def getStaticUrl(filename): + """ + Return the qualified access path for the given file, + under the static media directory. + """ + + return os.path.join(STATIC_URL, str(filename)) + + +def getBlankImage(): + """ + Return the qualified path for the 'blank image' placeholder. + """ + + return getStaticUrl("img/blank_image.png") + + +def getBlankThumbnail(): + """ + Return the qualified path for the 'blank image' thumbnail placeholder. + """ + + return getStaticUrl("img/blank_image.thumbnail.png") def TestIfImage(img): diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index 69c98a008a..0493cbbfa1 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -23,6 +23,7 @@ from markdownx.models import MarkdownxField from stdimage.models import StdImageField +from InvenTree.helpers import getMediaUrl, getBlankImage, getBlankThumbnail from InvenTree.fields import InvenTreeURLField, RoundingDecimalField from InvenTree.status_codes import OrderStatus from common.models import Currency @@ -118,18 +119,18 @@ class Company(models.Model): """ Return the URL of the image for this company """ if self.image: - return os.path.join(settings.MEDIA_URL, str(self.image.url)) + return getMediaUrl(self.image.url) else: - return os.path.join(settings.STATIC_URL, 'img/blank_image.png') + return getBlankImage() def get_thumbnail_url(self): """ Return the URL for the thumbnail image for this Company """ if self.image: - return os.path.join(settings.MEDIA_URL, str(self.image.thumbnail.url)) + return getMediaUrl(self.image.thumbnail.url) else: - return os.path.join(settings.STATIC_URL, 'img/blank_image.thumbnail.png') - + return getBlankThumbnail() + @property def part_count(self): """ The number of parts supplied by this company """ diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index da0bff16b8..f255d2a77b 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -300,9 +300,9 @@ class Part(models.Model): """ Return the URL of the image for this part """ if self.image: - return os.path.join(settings.MEDIA_URL, str(self.image.url)) + return helpers.getMediaUrl(self.image.url) else: - return os.path.join(settings.STATIC_URL, 'img/blank_image.png') + return helpers.getBlankImage() def get_thumbnail_url(self): """ @@ -310,10 +310,10 @@ class Part(models.Model): """ if self.image: - return os.path.join(settings.MEDIA_URL, str(self.image.thumbnail.url)) + return helpers.getMediaUrl(self.image.thumbnail.url) else: - return os.path.join(settings.STATIC_URL, 'img/blank_image.thumbnail.png') - + return helpers.getBlankThumbnail() + def validate_unique(self, exclude=None): """ Validate that a part is 'unique'. Uniqueness is checked across the following (case insensitive) fields: From d06018cbbe22b56aaaad94a8d69da7699a7a6854 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 11:40:10 +1000 Subject: [PATCH 09/23] PEP fixes --- InvenTree/company/apps.py | 2 +- InvenTree/company/models.py | 1 - InvenTree/part/models.py | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/InvenTree/company/apps.py b/InvenTree/company/apps.py index 25f3bd96dc..949ee152c0 100644 --- a/InvenTree/company/apps.py +++ b/InvenTree/company/apps.py @@ -6,6 +6,7 @@ from django.apps import AppConfig from django.db.utils import OperationalError, ProgrammingError from django.conf import settings + class CompanyConfig(AppConfig): name = 'company' @@ -33,4 +34,3 @@ class CompanyConfig(AppConfig): company.image.render_variations(replace=False) except (OperationalError, ProgrammingError): print("Could not generate Company thumbnails") - \ No newline at end of file diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index 0493cbbfa1..462b4ff847 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -17,7 +17,6 @@ from django.db.models import Sum from django.apps import apps from django.urls import reverse -from django.conf import settings from markdownx.models import MarkdownxField diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index f255d2a77b..d751dca215 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -10,7 +10,6 @@ import os from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError from django.urls import reverse -from django.conf import settings from django.db import models, transaction from django.db.models import Sum @@ -313,7 +312,7 @@ class Part(models.Model): return helpers.getMediaUrl(self.image.thumbnail.url) else: return helpers.getBlankThumbnail() - + def validate_unique(self, exclude=None): """ Validate that a part is 'unique'. Uniqueness is checked across the following (case insensitive) fields: From 623a0844d3c01d5584863168ed06d93eee22dcc2 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 11:50:46 +1000 Subject: [PATCH 10/23] Coverage tests for new functions --- InvenTree/InvenTree/helpers.py | 2 +- InvenTree/InvenTree/tests.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index d46f35daf4..6b29adb4c4 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -101,7 +101,7 @@ def isNull(text): True if the text looks like a null value """ - return str(text).strip().lower() in ['top', 'null', 'none', 'empty', 'false', '-1'] + return str(text).strip().lower() in ['top', 'null', 'none', 'empty', 'false', '-1', ''] def decimal2string(d): diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index 2511cf4318..1fc660c7d8 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -72,6 +72,24 @@ class TestHelpers(TestCase): self.assertFalse(helpers.str2bool(s)) self.assertFalse(helpers.str2bool(s, test=False)) + def test_isnull(self): + + for s in ['null', 'none', '', '-1', 'false']: + self.assertTrue(helpers.isNull(s)) + + for s in ['yes', 'frog', 'llama', 'true']: + self.assertFalse(helpers.isNull(s)) + + def testStaticUrl(self): + + self.assertEqual(helpers.getStaticUrl('test.jpg'), '/static/test.jpg') + self.assertEqual(helpers.getBlankImage(), '/static/img/blank_image.png') + self.assertEqual(helpers.getBlankThumbnail(), '/static/img/blank_image.thumbnail.png') + + def testMediaUrl(self): + + self.assertEqual(helpers.getMediaUrl('xx/yy.png'), '/media/xx/yy.png') + class TestQuoteWrap(TestCase): """ Tests for string wrapping """ From e94592e42d83568fc21b16ae40a0c78a3cdd0aea Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 12:09:25 +1000 Subject: [PATCH 11/23] Moar unit testing plz --- InvenTree/InvenTree/tests.py | 18 ++++++++++++++++++ Makefile | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index 1fc660c7d8..75ece9748d 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -1,12 +1,18 @@ + +import os + from django.test import TestCase import django.core.exceptions as django_exceptions from django.core.exceptions import ValidationError from .validators import validate_overage, validate_part_name from . import helpers +from .settings import STATIC_ROOT from mptt.exceptions import InvalidMove +from decimal import Decimal + from stock.models import StockLocation @@ -48,6 +54,13 @@ class ValidatorTest(TestCase): class TestHelpers(TestCase): """ Tests for InvenTree helper functions """ + def test_is_image(self): + img = os.path.abspath(os.path.join(STATIC_ROOT, 'img/blank_image.png')) + self.assertTrue(helpers.TestIfImage(img)) + + css = os.path.abspath(os.path.join(STATIC_ROOT, 'css/inventree.css')) + self.assertFalse(helpers.TestIfImage(css)) + def test_image_url(self): """ Test if a filename looks like an image """ @@ -90,6 +103,11 @@ class TestHelpers(TestCase): self.assertEqual(helpers.getMediaUrl('xx/yy.png'), '/media/xx/yy.png') + def testDecimal2String(self): + + self.assertEqual(helpers.decimal2string(Decimal('1.2345000')), '1.2345') + self.assertEqual(helpers.decimal2string('test'), 'test') + class TestQuoteWrap(TestCase): """ Tests for string wrapping """ diff --git a/Makefile b/Makefile index cb38a601d8..32e1675b45 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ test: # Run code coverage coverage: cd InvenTree && python3 manage.py check - coverage run InvenTree/manage.py test build common company order part stock InvenTree + cd InvenTree && coverage run manage.py test build common company order part stock InvenTree coverage html # Install packages required to generate code docs From 8786776fd6de87d17dadf4c30cfb067ea9c6f550 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 13:08:30 +1000 Subject: [PATCH 12/23] Remove some tests - CI complications --- InvenTree/InvenTree/tests.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index 75ece9748d..7553d1b10c 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -54,13 +54,6 @@ class ValidatorTest(TestCase): class TestHelpers(TestCase): """ Tests for InvenTree helper functions """ - def test_is_image(self): - img = os.path.abspath(os.path.join(STATIC_ROOT, 'img/blank_image.png')) - self.assertTrue(helpers.TestIfImage(img)) - - css = os.path.abspath(os.path.join(STATIC_ROOT, 'css/inventree.css')) - self.assertFalse(helpers.TestIfImage(css)) - def test_image_url(self): """ Test if a filename looks like an image """ From 1a0a4622a2e9ff0e6eed22be01c62f1a40c58409 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 13:16:23 +1000 Subject: [PATCH 13/23] Revert makefile change --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 32e1675b45..cb38a601d8 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ test: # Run code coverage coverage: cd InvenTree && python3 manage.py check - cd InvenTree && coverage run manage.py test build common company order part stock InvenTree + coverage run InvenTree/manage.py test build common company order part stock InvenTree coverage html # Install packages required to generate code docs From 5aec63d9e4e651bb110e135efc6908304e494f3c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 7 Apr 2020 14:20:43 +1000 Subject: [PATCH 14/23] Remove unused includes --- InvenTree/InvenTree/tests.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index 7553d1b10c..d93a40e631 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -1,13 +1,10 @@ -import os - from django.test import TestCase import django.core.exceptions as django_exceptions from django.core.exceptions import ValidationError from .validators import validate_overage, validate_part_name from . import helpers -from .settings import STATIC_ROOT from mptt.exceptions import InvalidMove From f6a1ddf8e7dc28bd9cfe92b64a6e94d39adf0b76 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 9 Apr 2020 21:18:55 +1000 Subject: [PATCH 15/23] Re-enable stocktake API --- InvenTree/stock/api.py | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index b0d3b3bd62..a1e2e3e768 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -98,7 +98,7 @@ class StockFilter(FilterSet): class StockStocktake(APIView): """ Stocktake API endpoint provides stock update of multiple items simultaneously. The 'action' field tells the type of stock action to perform: - - stocktake: Count the stock item(s) + - count: Count the stock item(s) - remove: Remove the quantity provided from stock - add: Add the quantity provided from stock """ @@ -114,7 +114,7 @@ class StockStocktake(APIView): action = request.data['action'] - ACTIONS = ['stocktake', 'remove', 'add'] + ACTIONS = ['count', 'remove', 'add'] if action not in ACTIONS: raise ValidationError({'action': 'Action must be one of ' + ','.join(ACTIONS)}) @@ -157,7 +157,7 @@ class StockStocktake(APIView): for item in items: quantity = int(item['quantity']) - if action == u'stocktake': + if action == u'count': if item['item'].stocktake(quantity, request.user, notes=notes): n += 1 elif action == u'remove': @@ -170,7 +170,7 @@ class StockStocktake(APIView): return Response({'success': 'Updated stock for {n} items'.format(n=n)}) -class StockMove(APIView): +class StockTransfer(APIView): """ API endpoint for performing stock movements """ permission_classes = [ @@ -512,22 +512,6 @@ class StockList(generics.ListCreateAPIView): ] -class StockStocktakeEndpoint(generics.UpdateAPIView): - """ API endpoint for performing stocktake """ - - queryset = StockItem.objects.all() - serializer_class = StockQuantitySerializer - permission_classes = (permissions.IsAuthenticated,) - - def update(self, request, *args, **kwargs): - object = self.get_object() - object.stocktake(request.data['quantity'], request.user) - - serializer = self.get_serializer(object) - - return response.Response(serializer.data) - - class StockTrackingList(generics.ListCreateAPIView): """ API endpoint for list view of StockItemTracking objects. @@ -591,8 +575,8 @@ stock_api_urls = [ url(r'location/', include(location_endpoints)), # These JSON endpoints have been replaced (for now) with server-side form rendering - 02/06/2019 - # url(r'stocktake/?', StockStocktake.as_view(), name='api-stock-stocktake'), - # url(r'move/?', StockMove.as_view(), name='api-stock-move'), + url(r'stocktake/?', StockStocktake.as_view(), name='api-stock-stocktake'), + # url(r'transfer/?', StockTransfer.as_view(), name='api-stock-transfer'), url(r'track/?', StockTrackingList.as_view(), name='api-stock-track'), From 1b3f8a930991de22ab201033b1f015087d17f994 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 9 Apr 2020 21:19:13 +1000 Subject: [PATCH 16/23] Unit testing for the stocktake API --- InvenTree/stock/test_api.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index 27207020b4..c76e016668 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -63,3 +63,40 @@ class StockItemTest(APITestCase): def test_get_stock_list(self): response = self.client.get(self.list_url, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) + + +class StocktakeTest(APITestCase): + """ + Series of tests for the Stocktake API + """ + + def setUp(self): + User = get_user_model() + User.objects.create_user('testuser', 'test@testing.com', 'password') + self.client.login(username='testuser', password='password') + + def doPost(self, data={}): + url = reverse('api-stock-stocktake') + response = self.client.post(url, data=data, format='json') + + return response + + def test_action(self): + + data = {} + + # POST without any action + response = self.doPost(data) + self.assertContains(response, "action must be provided", status_code=status.HTTP_400_BAD_REQUEST) + + data['action'] = 'fake' + + # POST with an invalid action + response = self.doPost(data) + self.assertContains(response, "must be one of", status_code=status.HTTP_400_BAD_REQUEST) + + data['action'] = 'count' + + # POST with a valid action + response = self.doPost(data) + self.assertContains(response, "must contain list", status_code=status.HTTP_400_BAD_REQUEST) \ No newline at end of file From 58a0f408898ae0042fe668897f1eab93142398a6 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 9 Apr 2020 22:24:05 +1000 Subject: [PATCH 17/23] Simplifiy stock adjustment APIs - Separate API endpoints for count / add / remove / transfer - Unit testing --- InvenTree/stock/api.py | 144 ++++++++++++++++++++++++------------ InvenTree/stock/test_api.py | 71 ++++++++++++++---- 2 files changed, 153 insertions(+), 62 deletions(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index a1e2e3e768..b387e823bd 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -14,7 +14,7 @@ from .models import StockItemTracking from part.models import Part, PartCategory -from .serializers import StockItemSerializer, StockQuantitySerializer +from .serializers import StockItemSerializer from .serializers import LocationSerializer from .serializers import StockTrackingSerializer @@ -23,11 +23,12 @@ from InvenTree.helpers import str2bool, isNull from InvenTree.status_codes import StockStatus import os +from decimal import Decimal, InvalidOperation from rest_framework.serializers import ValidationError from rest_framework.views import APIView from rest_framework.response import Response -from rest_framework import generics, response, filters, permissions +from rest_framework import generics, filters, permissions class StockCategoryTree(TreeSerializer): @@ -95,60 +96,74 @@ class StockFilter(FilterSet): fields = ['quantity', 'part', 'location'] -class StockStocktake(APIView): - """ Stocktake API endpoint provides stock update of multiple items simultaneously. - The 'action' field tells the type of stock action to perform: - - count: Count the stock item(s) - - remove: Remove the quantity provided from stock - - add: Add the quantity provided from stock +class StockAdjust(APIView): + """ + A generic class for handling stocktake actions. + + Subclasses exist for: + + - StockCount: count stock items + - StockAdd: add stock items + - StockRemove: remove stock items + - StockTransfer: transfer stock items """ permission_classes = [ permissions.IsAuthenticated, ] + def get_items(self, request): + """ + Return a list of items posted to the endpoint. + Will raise validation errors if the items are not + correctly formatted. + """ + + _items = [] + + if 'item' in request.data: + _items = [request.data['item']] + elif 'items' in request.data: + _items = request.data['items'] + else: + raise ValidationError({'items': 'Request must contain list of stock items'}) + + # List of validated items + self.items = [] + + for entry in _items: + + try: + item = StockItem.objects.get(pk=entry.get('pk', None)) + except (ValueError, StockItem.DoesNotExist): + raise ValidationError({'pk': 'Each entry must contain a valid pk field'}) + + try: + quantity = Decimal(str(entry.get('quantity', None))) + except (ValueError, TypeError, InvalidOperation): + raise ValidationError({'quantity': 'Each entry must contain a valid quantity field'}) + + if quantity <= 0: + raise ValidationError({'quantity': 'Quantity field must be greater than zero'}) + + self.items.append({ + 'item': item, + 'quantity': quantity + }) + + self.notes = str(request.POST.get('notes', '')) + + +class StockCount(StockAdjust): + """ + Endpoint for counting stock (performing a stocktake). + """ + def post(self, request, *args, **kwargs): - if 'action' not in request.data: - raise ValidationError({'action': 'Stocktake action must be provided'}) - - action = request.data['action'] - - ACTIONS = ['count', 'remove', 'add'] - - if action not in ACTIONS: - raise ValidationError({'action': 'Action must be one of ' + ','.join(ACTIONS)}) - - elif 'items[]' not in request.data: - raise ValidationError({'items[]:' 'Request must contain list of items'}) - - items = [] - - # Ensure each entry is valid - for entry in request.data['items[]']: - if 'pk' not in entry: - raise ValidationError({'pk': 'Each entry must contain pk field'}) - elif 'quantity' not in entry: - raise ValidationError({'quantity': 'Each entry must contain quantity field'}) - - item = {} - try: - item['item'] = StockItem.objects.get(pk=entry['pk']) - except StockItem.DoesNotExist: - raise ValidationError({'pk': 'No matching StockItem found for pk={pk}'.format(pk=entry['pk'])}) - try: - item['quantity'] = int(entry['quantity']) - except ValueError: - raise ValidationError({'quantity': 'Quantity must be an integer'}) - - if item['quantity'] < 0: - raise ValidationError({'quantity': 'Quantity must be >= 0'}) - - items.append(item) - - # Stocktake notes - notes = '' + self.get_items(request) + """ if 'notes' in request.data: notes = request.data['notes'] @@ -166,10 +181,41 @@ class StockStocktake(APIView): elif action == u'add': if item['item'].add_stock(quantity, request.user, notes=notes): n += 1 + """ + + n = 0 return Response({'success': 'Updated stock for {n} items'.format(n=n)}) +class StockAdd(StockAdjust): + """ + Endpoint for adding stock + """ + + def post(self, request, *args, **kwargs): + + self.get_items(request) + + n = 0 + + return Response({"success": "Added stock for {n} items".format(n=n)}) + + +class StockRemove(StockAdjust): + """ + Endpoint for removing stock. + """ + + def post(self, request, *args, **kwargs): + + self.get_items(request) + + n = 0 + + return Response({"success": "Added stock for {n} items".format(n=n)}) + + class StockTransfer(APIView): """ API endpoint for performing stock movements """ @@ -575,7 +621,9 @@ stock_api_urls = [ url(r'location/', include(location_endpoints)), # These JSON endpoints have been replaced (for now) with server-side form rendering - 02/06/2019 - url(r'stocktake/?', StockStocktake.as_view(), name='api-stock-stocktake'), + url(r'count/?', StockCount.as_view(), name='api-stock-count'), + url(r'add/?', StockAdd.as_view(), name='api-stock-add'), + url(r'remove/?', StockRemove.as_view(), name='api-stock-remove'), # url(r'transfer/?', StockTransfer.as_view(), name='api-stock-transfer'), url(r'track/?', StockTrackingList.as_view(), name='api-stock-track'), diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index c76e016668..e85997ae1d 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -70,33 +70,76 @@ class StocktakeTest(APITestCase): Series of tests for the Stocktake API """ + fixtures = [ + 'category', + 'part', + 'company', + 'location', + 'supplier_part', + 'stock', + ] + def setUp(self): User = get_user_model() User.objects.create_user('testuser', 'test@testing.com', 'password') self.client.login(username='testuser', password='password') - def doPost(self, data={}): - url = reverse('api-stock-stocktake') + def doPost(self, url, data={}): response = self.client.post(url, data=data, format='json') return response def test_action(self): + """ + Test each stocktake action endpoint, + for validation + """ - data = {} + for endpoint in ['api-stock-count', 'api-stock-add', 'api-stock-remove']: - # POST without any action - response = self.doPost(data) - self.assertContains(response, "action must be provided", status_code=status.HTTP_400_BAD_REQUEST) + url = reverse(endpoint) - data['action'] = 'fake' + data = {} - # POST with an invalid action - response = self.doPost(data) - self.assertContains(response, "must be one of", status_code=status.HTTP_400_BAD_REQUEST) + # POST with a valid action + response = self.doPost(url, data) + self.assertContains(response, "must contain list", status_code=status.HTTP_400_BAD_REQUEST) - data['action'] = 'count' + data['items'] = [{ + 'no': 'aa' + }] - # POST with a valid action - response = self.doPost(data) - self.assertContains(response, "must contain list", status_code=status.HTTP_400_BAD_REQUEST) \ No newline at end of file + # POST without a PK + response = self.doPost(url, data) + self.assertContains(response, 'must contain a valid pk', status_code=status.HTTP_400_BAD_REQUEST) + + # POST with a PK but no quantity + data['items'] = [{ + 'pk': 10 + }] + + response = self.doPost(url, data) + self.assertContains(response, 'must contain a valid pk', status_code=status.HTTP_400_BAD_REQUEST) + + data['items'] = [{ + 'pk': 1234 + }] + + response = self.doPost(url, data) + self.assertContains(response, 'must contain a valid quantity', status_code=status.HTTP_400_BAD_REQUEST) + + data['items'] = [{ + 'pk': 1234, + 'quantity': '10x0d' + }] + + response = self.doPost(url, data) + self.assertContains(response, 'must contain a valid quantity', status_code=status.HTTP_400_BAD_REQUEST) + + data['items'] = [{ + 'pk': 1234, + 'quantity': "-1.234" + }] + + response = self.doPost(url, data) + self.assertContains(response, 'must be greater than zero', status_code=status.HTTP_400_BAD_REQUEST) From 3e5dc65c492762ba8b6c5cc46b37399fab14560a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 10 Apr 2020 00:03:21 +1000 Subject: [PATCH 18/23] Bugfix for notes field --- InvenTree/stock/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index b387e823bd..ea5cb3e634 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -151,7 +151,7 @@ class StockAdjust(APIView): 'quantity': quantity }) - self.notes = str(request.POST.get('notes', '')) + self.notes = str(request.data.get('notes', '')) class StockCount(StockAdjust): From 41b3f1d39c3d940794ccb0a52d966880c73f126b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 10 Apr 2020 00:03:43 +1000 Subject: [PATCH 19/23] API cleanup Add / Remove / Count endpoints now work --- InvenTree/stock/api.py | 32 +++++++++++++------------------- InvenTree/stock/test_api.py | 2 +- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index ea5cb3e634..39b660732f 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -163,27 +163,12 @@ class StockCount(StockAdjust): self.get_items(request) - """ - if 'notes' in request.data: - notes = request.data['notes'] - n = 0 - for item in items: - quantity = int(item['quantity']) + for item in self.items: - if action == u'count': - if item['item'].stocktake(quantity, request.user, notes=notes): - n += 1 - elif action == u'remove': - if item['item'].take_stock(quantity, request.user, notes=notes): - n += 1 - elif action == u'add': - if item['item'].add_stock(quantity, request.user, notes=notes): - n += 1 - """ - - n = 0 + if item['item'].stocktake(item['quantity'], request.user, notes=self.notes): + n += 1 return Response({'success': 'Updated stock for {n} items'.format(n=n)}) @@ -199,6 +184,10 @@ class StockAdd(StockAdjust): n = 0 + for item in self.items: + if item['item'].add_stock(item['quantity'], request.user, notes=self.notes): + n += 1 + return Response({"success": "Added stock for {n} items".format(n=n)}) @@ -213,7 +202,12 @@ class StockRemove(StockAdjust): n = 0 - return Response({"success": "Added stock for {n} items".format(n=n)}) + for item in self.items: + + if item['item'].take_stock(item['quantity'], request.user, notes=self.notes): + n += 1 + + return Response({"success": "Removed stock for {n} items".format(n=n)}) class StockTransfer(APIView): diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index e85997ae1d..8c8372ebc7 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -85,7 +85,7 @@ class StocktakeTest(APITestCase): self.client.login(username='testuser', password='password') def doPost(self, url, data={}): - response = self.client.post(url, data=data, format='json') + response = self.client.post(url, data=data, format='json') return response From 5b2665edb17b069f6bf6339f72430c00ccc3dbcb Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 10 Apr 2020 00:53:04 +1000 Subject: [PATCH 20/23] Better API validation --- InvenTree/stock/api.py | 10 +++++++--- InvenTree/stock/test_api.py | 13 ++++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 39b660732f..4ef9fac8ef 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -133,8 +133,12 @@ class StockAdjust(APIView): for entry in _items: + if not type(entry) == dict: + raise ValidationError({'error': 'Improperly formatted data'}) + try: - item = StockItem.objects.get(pk=entry.get('pk', None)) + pk = entry.get('pk', None) + item = StockItem.objects.get(pk=pk) except (ValueError, StockItem.DoesNotExist): raise ValidationError({'pk': 'Each entry must contain a valid pk field'}) @@ -143,8 +147,8 @@ class StockAdjust(APIView): except (ValueError, TypeError, InvalidOperation): raise ValidationError({'quantity': 'Each entry must contain a valid quantity field'}) - if quantity <= 0: - raise ValidationError({'quantity': 'Quantity field must be greater than zero'}) + if quantity < 0: + raise ValidationError({'quantity': 'Quantity field must not be less than zero'}) self.items.append({ 'item': item, diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index 8c8372ebc7..4d5e29cda6 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -142,4 +142,15 @@ class StocktakeTest(APITestCase): }] response = self.doPost(url, data) - self.assertContains(response, 'must be greater than zero', status_code=status.HTTP_400_BAD_REQUEST) + self.assertContains(response, 'must not be less than zero', status_code=status.HTTP_400_BAD_REQUEST) + + # Test with a single item + data = { + 'item': { + 'pk': 1234, + 'quantity': '10', + } + } + + response = self.doPost(url, data) + self.assertEqual(response.status_code, status.HTTP_200_OK) From bc91975f2cc8db24a5b1372c82204890d3723f56 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 10 Apr 2020 01:01:39 +1000 Subject: [PATCH 21/23] Fixes for Stocktransfer API endpoint --- InvenTree/stock/api.py | 73 ++++++++++--------------------------- InvenTree/stock/test_api.py | 25 +++++++++++++ 2 files changed, 45 insertions(+), 53 deletions(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 4ef9fac8ef..ad989459ee 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -214,69 +214,36 @@ class StockRemove(StockAdjust): return Response({"success": "Removed stock for {n} items".format(n=n)}) -class StockTransfer(APIView): - """ API endpoint for performing stock movements """ - - permission_classes = [ - permissions.IsAuthenticated, - ] +class StockTransfer(StockAdjust): + """ + API endpoint for performing stock movements + """ def post(self, request, *args, **kwargs): + self.get_items(request) + data = request.data - if 'location' not in data: - raise ValidationError({'location': 'Destination must be specified'}) - try: - loc_id = int(data.get('location')) - except ValueError: - raise ValidationError({'location': 'Integer ID required'}) + location = StockLocation.objects.get(pk=data.get('location', None)) + except (ValueError, StockLocation.DoesNotExist): + raise ValidationError({'location': 'Valid location must be specified'}) - try: - location = StockLocation.objects.get(pk=loc_id) - except StockLocation.DoesNotExist: - raise ValidationError({'location': 'Location does not exist'}) + n = 0 - if 'stock' not in data: - raise ValidationError({'stock': 'Stock list must be specified'}) - - stock_list = data.get('stock') + for item in self.items: - if type(stock_list) is not list: - raise ValidationError({'stock': 'Stock must be supplied as a list'}) + # If quantity is not specified, move the entire stock + if item['quantity'] in [0, None]: + item['quantity'] = item['item'].quantity - if 'notes' not in data: - raise ValidationError({'notes': 'Notes field must be supplied'}) + if item['item'].move(location, self.notes, request.user, quantity=item['quantity']): + n += 1 - for item in stock_list: - try: - stock_id = int(item['pk']) - if 'quantity' in item: - quantity = int(item['quantity']) - else: - # If quantity not supplied, we'll move the entire stock - quantity = None - except ValueError: - # Ignore this one - continue - - # Ignore a zero quantity movement - if quantity <= 0: - continue - - try: - stock = StockItem.objects.get(pk=stock_id) - except StockItem.DoesNotExist: - continue - - if quantity is None: - quantity = stock.quantity - - stock.move(location, data.get('notes'), request.user, quantity=quantity) - - return Response({'success': 'Moved parts to {loc}'.format( - loc=str(location) + return Response({'success': 'Moved {n} parts to {loc}'.format( + n=n, + loc=str(location), )}) @@ -622,7 +589,7 @@ stock_api_urls = [ url(r'count/?', StockCount.as_view(), name='api-stock-count'), url(r'add/?', StockAdd.as_view(), name='api-stock-add'), url(r'remove/?', StockRemove.as_view(), name='api-stock-remove'), - # url(r'transfer/?', StockTransfer.as_view(), name='api-stock-transfer'), + url(r'transfer/?', StockTransfer.as_view(), name='api-stock-transfer'), url(r'track/?', StockTrackingList.as_view(), name='api-stock-track'), diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index 4d5e29cda6..fe49547cee 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -154,3 +154,28 @@ class StocktakeTest(APITestCase): response = self.doPost(url, data) self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_transfer(self): + """ + Test stock transfers + """ + + data = { + 'item': { + 'pk': 1234, + 'quantity': 10, + }, + 'location': 1, + 'notes': "Moving to a new location" + } + + url = reverse('api-stock-transfer') + + response = self.doPost(url, data) + self.assertContains(response, "Moved 1 parts to", status_code=status.HTTP_200_OK) + + # Now try one which will fail due to a bad location + data['location'] = 'not a location' + + response = self.doPost(url, data) + self.assertContains(response, 'Valid location must be specified', status_code=status.HTTP_400_BAD_REQUEST) From 47764ca179aa2c54d0387bd2238cc005f5e9be5b Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 10 Apr 2020 01:03:54 +1000 Subject: [PATCH 22/23] Update version.py Add a _pre suffix --- InvenTree/InvenTree/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index ae812a2695..386409646a 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -5,7 +5,7 @@ Provides information on the current InvenTree version import subprocess from common.models import InvenTreeSetting -INVENTREE_SW_VERSION = "0.0.10" +INVENTREE_SW_VERSION = "0.0.11_pre" def inventreeInstanceName(): From 8da71037ae68c31af58e1e18f098e6bf4a1fc45d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 10 Apr 2020 01:04:55 +1000 Subject: [PATCH 23/23] Update translations --- InvenTree/locale/de/LC_MESSAGES/django.mo | Bin 26419 -> 26331 bytes InvenTree/locale/de/LC_MESSAGES/django.po | 431 +++++++++++----------- InvenTree/locale/en/LC_MESSAGES/django.po | 419 ++++++++++----------- InvenTree/locale/es/LC_MESSAGES/django.po | 419 ++++++++++----------- 4 files changed, 649 insertions(+), 620 deletions(-) diff --git a/InvenTree/locale/de/LC_MESSAGES/django.mo b/InvenTree/locale/de/LC_MESSAGES/django.mo index 1632eb47b23685fd78456f964ee0a84198be2b68..4038658f79cb21087ae837bd8467e380985ea54e 100644 GIT binary patch delta 7781 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 Oxi?2|n7e7rwEqE*=Oym| delta 7864 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 DO?oLE diff --git a/InvenTree/locale/de/LC_MESSAGES/django.po b/InvenTree/locale/de/LC_MESSAGES/django.po index 22ea2c52ad..212ae38002 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: 2020-04-05 10:55+0000\n" +"POT-Creation-Date: 2020-04-09 15:04+0000\n" "PO-Revision-Date: 2020-02-02 08:07+0100\n" "Last-Translator: Christian Schlüter \n" "Language-Team: C \n" @@ -17,30 +17,30 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Lokalize 19.12.0\n" -#: InvenTree/helpers.py:201 order/models.py:164 order/models.py:215 +#: InvenTree/helpers.py:240 order/models.py:164 order/models.py:215 msgid "Invalid quantity provided" msgstr "Keine gültige Menge" -#: InvenTree/helpers.py:204 +#: InvenTree/helpers.py:243 msgid "Empty serial number string" msgstr "Keine Seriennummer angegeben" -#: InvenTree/helpers.py:225 InvenTree/helpers.py:242 +#: InvenTree/helpers.py:264 InvenTree/helpers.py:281 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "Doppelte Seriennummer: {n}" -#: InvenTree/helpers.py:229 InvenTree/helpers.py:232 InvenTree/helpers.py:235 -#: InvenTree/helpers.py:246 +#: InvenTree/helpers.py:268 InvenTree/helpers.py:271 InvenTree/helpers.py:274 +#: InvenTree/helpers.py:285 #, python-brace-format msgid "Invalid group: {g}" msgstr "Ungültige Gruppe: {g}" -#: InvenTree/helpers.py:252 +#: InvenTree/helpers.py:291 msgid "No serial numbers found" msgstr "Keine Seriennummern gefunden" -#: InvenTree/helpers.py:256 +#: InvenTree/helpers.py:295 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" @@ -113,7 +113,7 @@ msgstr "Zerstört" #: InvenTree/status_codes.py:98 build/templates/build/allocate_edit.html:28 #: build/templates/build/allocate_view.html:21 -#: part/templates/part/part_base.html:106 part/templates/part/tabs.html:21 +#: part/templates/part/part_base.html:109 part/templates/part/tabs.html:21 msgid "Allocated" msgstr "Zugeordnet" @@ -142,7 +142,7 @@ msgstr "Überschuss darf 100% nicht überschreiten" msgid "Overage must be an integer value or a percentage" msgstr "Überschuss muss eine Ganzzahl oder ein Prozentwert sein" -#: InvenTree/views.py:548 +#: InvenTree/views.py:549 msgid "Database Statistics" msgstr "" @@ -186,7 +186,7 @@ msgstr "Bau-Status" msgid "Batch code for this build output" msgstr "Chargennummer für diese Bau-Ausgabe" -#: build/models.py:97 +#: build/models.py:97 stock/models.py:331 msgid "Link to external URL" msgstr "Link zu einer externen URL" @@ -231,7 +231,7 @@ msgstr "Zuweisung aufheben" #: build/templates/build/allocate_edit.html:19 #: build/templates/build/allocate_view.html:17 -#: build/templates/build/detail.html:17 +#: build/templates/build/detail.html:21 #: company/templates/company/detail_part.html:65 #: order/templates/order/order_wizard/select_parts.html:30 #: order/templates/order/purchase_order_detail.html:25 @@ -267,12 +267,12 @@ msgstr "Teile bestellen" #: company/templates/company/supplier_part_base.html:50 #: company/templates/company/supplier_part_detail.html:27 #: order/templates/order/purchase_order_detail.html:26 -#: part/templates/part/detail.html:37 +#: part/templates/part/detail.html:38 msgid "Description" msgstr "Beschreibung" #: build/templates/build/allocate_view.html:22 -#: part/templates/part/part_base.html:112 +#: part/templates/part/part_base.html:115 msgid "On Order" msgstr "bestellt" @@ -293,65 +293,64 @@ msgstr "" msgid "Build Details" msgstr "Bau-Status" -#: build/templates/build/detail.html:14 +#: build/templates/build/detail.html:16 msgid "Title" msgstr "Titel" -#: build/templates/build/detail.html:20 +#: build/templates/build/detail.html:26 #: company/templates/company/supplier_part_pricing.html:27 #: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:29 -#: stock/templates/stock/item_base.html:101 +#: stock/templates/stock/item_base.html:107 #: stock/templates/stock/stock_adjust.html:18 msgid "Quantity" msgstr "Anzahl" -#: build/templates/build/detail.html:23 +#: build/templates/build/detail.html:30 msgid "Stock Source" msgstr "Lagerobjekt" -#: build/templates/build/detail.html:28 +#: build/templates/build/detail.html:35 msgid "Stock can be taken from any available location." msgstr "Bestand kann jedem verfügbaren Lagerort entnommen werden." -#: build/templates/build/detail.html:33 +#: build/templates/build/detail.html:41 #: order/templates/order/order_base.html:71 -#: stock/templates/stock/item_base.html:158 +#: stock/templates/stock/item_base.html:174 msgid "Status" msgstr "Status" -#: build/templates/build/detail.html:37 -#: stock/templates/stock/item_base.html:107 +#: build/templates/build/detail.html:47 +#: stock/templates/stock/item_base.html:114 msgid "Batch" msgstr "Los" -#: build/templates/build/detail.html:42 -#: company/templates/company/detail_part.html:90 +#: build/templates/build/detail.html:54 #: company/templates/company/supplier_part_base.html:47 #: company/templates/company/supplier_part_detail.html:24 -#: part/templates/part/part_base.html:81 -#: stock/templates/stock/item_base.html:131 -msgid "URL" -msgstr "URL" +#: part/templates/part/detail.html:67 part/templates/part/part_base.html:84 +#: stock/templates/stock/item_base.html:142 +msgid "External Link" +msgstr "" -#: build/templates/build/detail.html:46 -#: order/templates/order/order_base.html:75 +#: build/templates/build/detail.html:60 +#: order/templates/order/order_base.html:83 msgid "Created" msgstr "Erstellt" -#: build/templates/build/detail.html:50 +#: build/templates/build/detail.html:66 msgid "Enough Parts?" msgstr "Genügend Teile?" -#: build/templates/build/detail.html:53 +#: build/templates/build/detail.html:69 msgid "Yes" msgstr "Ja" -#: build/templates/build/detail.html:55 +#: build/templates/build/detail.html:71 msgid "No" msgstr "Nein" -#: build/templates/build/detail.html:62 +#: build/templates/build/detail.html:79 msgid "Completed" msgstr "Fertig" @@ -380,7 +379,7 @@ msgstr "Details" msgid "Outputs" msgstr "" -#: build/templates/build/tabs.html:11 company/models.py:248 +#: build/templates/build/tabs.html:11 company/models.py:264 #: company/templates/company/tabs.html:26 order/templates/order/tabs.html:15 #: part/templates/part/tabs.html:58 stock/templates/stock/tabs.html:17 msgid "Notes" @@ -571,81 +570,81 @@ msgstr "" msgid "Delete Currency" msgstr "" -#: company/models.py:74 +#: company/models.py:76 msgid "Company name" msgstr "Firmenname" -#: company/models.py:76 +#: company/models.py:78 msgid "Description of the company" msgstr "Firmenbeschreibung" -#: company/models.py:78 +#: company/models.py:80 msgid "Company website URL" msgstr "Firmenwebsite" -#: company/models.py:81 +#: company/models.py:83 msgid "Company address" msgstr "Firmenadresse" -#: company/models.py:84 +#: company/models.py:86 msgid "Contact phone number" msgstr "Kontakt-Tel." -#: company/models.py:86 +#: company/models.py:88 msgid "Contact email address" msgstr "Kontakt-Email" -#: company/models.py:89 +#: company/models.py:91 msgid "Point of contact" msgstr "Anlaufstelle" -#: company/models.py:91 +#: company/models.py:93 msgid "Link to external company information" msgstr "Link auf externe Firmeninformation" -#: company/models.py:97 +#: company/models.py:105 msgid "Do you sell items to this company?" msgstr "Verkaufen Sie Teile an diese Firma?" -#: company/models.py:99 +#: company/models.py:107 msgid "Do you purchase items from this company?" msgstr "Kaufen Sie Teile von dieser Firma?" -#: company/models.py:229 +#: company/models.py:245 msgid "Select part" msgstr "Teil auswählen" -#: company/models.py:235 +#: company/models.py:251 msgid "Select supplier" msgstr "Zulieferer auswählen" -#: company/models.py:238 +#: company/models.py:254 msgid "Supplier stock keeping unit" msgstr "Stock Keeping Units (SKU) des Zulieferers" -#: company/models.py:240 company/templates/company/detail_part.html:81 +#: company/models.py:256 company/templates/company/detail_part.html:81 #: company/templates/company/supplier_part_base.html:53 #: company/templates/company/supplier_part_detail.html:30 msgid "Manufacturer" msgstr "Hersteller" -#: company/models.py:242 +#: company/models.py:258 msgid "Manufacturer part number" msgstr "Hersteller-Teilenummer" -#: company/models.py:244 +#: company/models.py:260 msgid "URL for external supplier part link" msgstr "Teil-URL des Zulieferers" -#: company/models.py:246 +#: company/models.py:262 msgid "Supplier part description" msgstr "Zuliefererbeschreibung des Teils" -#: company/models.py:250 +#: company/models.py:266 msgid "Minimum charge (e.g. stocking fee)" msgstr "Mindestpreis" -#: company/models.py:252 +#: company/models.py:268 msgid "Part packaging" msgstr "Teile-Packaging" @@ -653,24 +652,24 @@ msgstr "Teile-Packaging" msgid "Company" msgstr "Firma" -#: company/templates/company/company_base.html:48 +#: company/templates/company/company_base.html:50 #: company/templates/company/index.html:59 msgid "Website" msgstr "" -#: company/templates/company/company_base.html:53 +#: company/templates/company/company_base.html:57 msgid "Address" msgstr "" -#: company/templates/company/company_base.html:58 +#: company/templates/company/company_base.html:64 msgid "Phone" msgstr "" -#: company/templates/company/company_base.html:63 +#: company/templates/company/company_base.html:71 msgid "Email" msgstr "" -#: company/templates/company/company_base.html:68 +#: company/templates/company/company_base.html:78 msgid "Contact" msgstr "" @@ -680,18 +679,18 @@ msgstr "" msgid "Company Details" msgstr "Firmenbemerkungen" -#: company/templates/company/detail.html:13 -#: stock/templates/stock/item_base.html:125 +#: company/templates/company/detail.html:16 +#: stock/templates/stock/item_base.html:135 msgid "Customer" msgstr "Kunde" -#: company/templates/company/detail.html:17 +#: company/templates/company/detail.html:21 #: company/templates/company/index.html:46 #: company/templates/company/supplier_part_base.html:44 #: company/templates/company/supplier_part_detail.html:21 -#: order/templates/order/order_base.html:67 +#: order/templates/order/order_base.html:66 #: order/templates/order/order_wizard/select_pos.html:30 -#: stock/templates/stock/item_base.html:137 +#: stock/templates/stock/item_base.html:149 msgid "Supplier" msgstr "Zulieferer" @@ -723,6 +722,10 @@ msgstr "Anhang löschen" msgid "SKU" msgstr "" +#: company/templates/company/detail_part.html:90 +msgid "Link" +msgstr "" + #: company/templates/company/detail_purchase_orders.html:8 #: company/templates/company/tabs.html:15 part/templates/part/tabs.html:43 msgid "Purchase Orders" @@ -763,8 +766,8 @@ msgstr "Zulieferer" msgid "ID" msgstr "" -#: company/templates/company/index.html:69 part/templates/part/category.html:81 -#: templates/navbar.html:10 templates/stats.html:7 templates/stats.html:10 +#: company/templates/company/index.html:69 part/templates/part/category.html:83 +#: templates/navbar.html:10 templates/stats.html:8 templates/stats.html:17 msgid "Parts" msgstr "Teile" @@ -780,7 +783,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:6 #: company/templates/company/supplier_part_base.html:13 -#: stock/templates/stock/item_base.html:141 +#: stock/templates/stock/item_base.html:154 msgid "Supplier Part" msgstr "Zulieferer-Teil" @@ -1003,7 +1006,7 @@ msgid "Order notes" msgstr "Bestell-Notizen" #: order/models.py:162 order/models.py:213 part/views.py:1119 -#: stock/models.py:463 +#: stock/models.py:467 msgid "Quantity must be greater than zero" msgstr "Anzahl muss größer Null sein" @@ -1027,7 +1030,7 @@ msgstr "Position - Referenz" msgid "Line item notes" msgstr "Position - Notizen" -#: order/models.py:298 stock/templates/stock/item_base.html:119 +#: order/models.py:298 stock/templates/stock/item_base.html:128 msgid "Purchase Order" msgstr "Kaufvertrag" @@ -1039,15 +1042,15 @@ msgstr "Zulieferer-Teil" msgid "Number of items received" msgstr "Empfangene Objekt-Anzahl" -#: order/templates/order/order_base.html:64 +#: order/templates/order/order_base.html:61 msgid "Purchase Order Details" msgstr "Bestelldetails" -#: order/templates/order/order_base.html:80 +#: order/templates/order/order_base.html:89 msgid "Issued" msgstr "Aufgegeben" -#: order/templates/order/order_base.html:86 +#: order/templates/order/order_base.html:96 #: order/templates/order/purchase_order_detail.html:31 msgid "Received" msgstr "Empfangen" @@ -1362,173 +1365,173 @@ msgstr "Eintragsmenge zur Preisberechnung" msgid "Select currency for price calculation" msgstr "Währung zur Preisberechnung wählen" -#: part/models.py:62 +#: part/models.py:61 msgid "Default location for parts in this category" msgstr "Standard-Standort für Teile dieser Kategorie" -#: part/models.py:65 +#: part/models.py:64 msgid "Default keywords for parts in this category" msgstr "Standard-Stichworte für Teile dieser Kategorie" -#: part/models.py:339 +#: part/models.py:338 msgid "Part must be unique for name, IPN and revision" msgstr "Namen, Teile- und Revisionsnummern müssen eindeutig sein" -#: part/models.py:353 +#: part/models.py:352 msgid "Part cannot be a template part if it is a variant of another part" msgstr "Teil kann keine Vorlage sein wenn es Variante eines anderen Teils ist" -#: part/models.py:354 +#: part/models.py:353 msgid "Part cannot be a variant of another part if it is already a template" msgstr "" "Teil kann keine Variante eines anderen Teils sein wenn es bereits eine " "Vorlage ist" -#: part/models.py:358 part/templates/part/detail.html:18 +#: part/models.py:357 part/templates/part/detail.html:19 msgid "Part name" msgstr "Name des Teils" -#: part/models.py:362 +#: part/models.py:361 msgid "Is this part a template part?" msgstr "Ist dieses Teil eine Vorlage?" -#: part/models.py:371 +#: part/models.py:370 msgid "Is this part a variant of another part?" msgstr "Ist dieses Teil eine Variante eines anderen Teils?" -#: part/models.py:373 +#: part/models.py:372 msgid "Part description" msgstr "Beschreibung des Teils" -#: part/models.py:375 +#: part/models.py:374 msgid "Part keywords to improve visibility in search results" msgstr "Schlüsselworte um die Sichtbarkeit in Suchergebnissen zu verbessern" -#: part/models.py:380 +#: part/models.py:379 msgid "Part category" msgstr "Teile-Kategorie" -#: part/models.py:382 +#: part/models.py:381 msgid "Internal Part Number" msgstr "Interne Teilenummer" -#: part/models.py:384 +#: part/models.py:383 msgid "Part revision or version number" msgstr "Revisions- oder Versionsnummer" -#: part/models.py:386 +#: part/models.py:385 msgid "Link to extenal URL" msgstr "Link zu einer Externen URL" -#: part/models.py:398 +#: part/models.py:397 msgid "Where is this item normally stored?" msgstr "Wo wird dieses Teil normalerweise gelagert?" -#: part/models.py:442 +#: part/models.py:441 msgid "Default supplier part" msgstr "Standard-Zulieferer?" -#: part/models.py:445 +#: part/models.py:444 msgid "Minimum allowed stock level" msgstr "Minimal zulässiger Lagerbestand" -#: part/models.py:447 +#: part/models.py:446 msgid "Stock keeping units for this part" msgstr "Stock Keeping Units (SKU) für dieses Teil" -#: part/models.py:449 +#: part/models.py:448 msgid "Can this part be built from other parts?" msgstr "Kann dieses Teil aus anderen Teilen angefertigt werden?" -#: part/models.py:451 +#: part/models.py:450 msgid "Can this part be used to build other parts?" msgstr "Kann dieses Teil zum Bau von anderen genutzt werden?" -#: part/models.py:453 +#: part/models.py:452 msgid "Does this part have tracking for unique items?" msgstr "Hat dieses Teil Tracking für einzelne Objekte?" -#: part/models.py:455 +#: part/models.py:454 msgid "Can this part be purchased from external suppliers?" msgstr "Kann dieses Teil von externen Zulieferern gekauft werden?" -#: part/models.py:457 +#: part/models.py:456 msgid "Can this part be sold to customers?" msgstr "Kann dieses Teil an Kunden verkauft werden?" -#: part/models.py:459 +#: part/models.py:458 msgid "Is this part active?" msgstr "Ist dieses Teil aktiv?" -#: part/models.py:461 +#: part/models.py:460 msgid "Is this a virtual part, such as a software product or license?" msgstr "Ist dieses Teil virtuell, wie zum Beispiel eine Software oder Lizenz?" -#: part/models.py:463 +#: part/models.py:462 msgid "Part notes - supports Markdown formatting" msgstr "Bemerkungen - unterstüzt Markdown-Formatierung" -#: part/models.py:465 +#: part/models.py:464 msgid "Stored BOM checksum" msgstr "Prüfsumme der Stückliste gespeichert" -#: part/models.py:1041 +#: part/models.py:1040 msgid "Parameter template name must be unique" msgstr "Vorlagen-Name des Parameters muss eindeutig sein" -#: part/models.py:1046 +#: part/models.py:1045 msgid "Parameter Name" msgstr "Name des Parameters" -#: part/models.py:1048 +#: part/models.py:1047 msgid "Parameter Units" msgstr "Parameter Einheit" -#: part/models.py:1074 +#: part/models.py:1073 msgid "Parent Part" msgstr "Ausgangsteil" -#: part/models.py:1076 +#: part/models.py:1075 msgid "Parameter Template" msgstr "Parameter Vorlage" -#: part/models.py:1078 +#: part/models.py:1077 msgid "Parameter Value" msgstr "Parameter Wert" -#: part/models.py:1102 +#: part/models.py:1101 msgid "Select parent part" msgstr "Ausgangsteil auswählen" -#: part/models.py:1111 +#: part/models.py:1110 msgid "Select part to be used in BOM" msgstr "Teil für die Nutzung in der Stückliste auswählen" -#: part/models.py:1118 +#: part/models.py:1117 msgid "BOM quantity for this BOM item" msgstr "Stücklisten-Anzahl für dieses Stücklisten-Teil" -#: part/models.py:1121 +#: part/models.py:1120 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "Geschätzter Ausschuss (absolut oder prozentual)" -#: part/models.py:1124 +#: part/models.py:1123 msgid "BOM item reference" msgstr "Referenz des Objekts auf der Stückliste" -#: part/models.py:1127 +#: part/models.py:1126 msgid "BOM item notes" msgstr "Notizen zum Stücklisten-Objekt" -#: part/models.py:1129 +#: part/models.py:1128 msgid "BOM line checksum" msgstr "Prüfsumme der Stückliste" -#: part/models.py:1192 +#: part/models.py:1191 msgid "Part cannot be added to its own Bill of Materials" msgstr "Teil kann nicht zu seiner eigenen Stückliste hinzugefügt werden" -#: part/models.py:1199 +#: part/models.py:1198 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "Teil '{p1}' wird in Stückliste für Teil '{p2}' benutzt (rekursiv)" @@ -1537,8 +1540,8 @@ msgstr "Teil '{p1}' wird in Stückliste für Teil '{p2}' benutzt (rekursiv)" msgid "Part Attachments" msgstr "Anhänge" -#: part/templates/part/category.html:13 part/templates/part/category.html:76 -#: templates/stats.html:14 +#: part/templates/part/category.html:13 part/templates/part/category.html:78 +#: templates/stats.html:12 msgid "Part Categories" msgstr "Teile-Kategorien" @@ -1546,31 +1549,31 @@ msgstr "Teile-Kategorien" msgid "All parts" msgstr "Alle Teile" -#: part/templates/part/category.html:34 part/templates/part/category.html:72 +#: part/templates/part/category.html:34 part/templates/part/category.html:73 msgid "Category Details" msgstr "Kategorie-Details" -#: part/templates/part/category.html:38 +#: part/templates/part/category.html:39 msgid "Category Path" msgstr "Pfad zur Kategorie" -#: part/templates/part/category.html:43 +#: part/templates/part/category.html:44 msgid "Category Description" msgstr "Kategorie-Beschreibung" -#: part/templates/part/category.html:49 part/templates/part/detail.html:73 +#: part/templates/part/category.html:50 part/templates/part/detail.html:74 msgid "Default Location" msgstr "Standard-Lagerort" -#: part/templates/part/category.html:56 part/templates/part/detail.html:50 +#: part/templates/part/category.html:57 part/templates/part/detail.html:51 msgid "Keywords" msgstr "Schlüsselwörter" -#: part/templates/part/category.html:62 +#: part/templates/part/category.html:63 msgid "Subcategories" msgstr "Unter-Kategorien" -#: part/templates/part/category.html:67 +#: part/templates/part/category.html:68 msgid "Parts (Including subcategories)" msgstr "Teile (inklusive Unter-Kategorien)" @@ -1578,119 +1581,115 @@ msgstr "Teile (inklusive Unter-Kategorien)" msgid "Part Details" msgstr "Teile-Details" -#: part/templates/part/detail.html:24 part/templates/part/part_base.html:75 +#: part/templates/part/detail.html:25 part/templates/part/part_base.html:77 msgid "IPN" msgstr "IPN (Interne Produktnummer)" -#: part/templates/part/detail.html:31 +#: part/templates/part/detail.html:32 msgid "Revision" msgstr "Revision" -#: part/templates/part/detail.html:43 +#: part/templates/part/detail.html:44 msgid "Variant Of" msgstr "Variante von" -#: part/templates/part/detail.html:56 +#: part/templates/part/detail.html:57 msgid "Category" msgstr "Kategorie" -#: part/templates/part/detail.html:66 -msgid "Link" -msgstr "" - -#: part/templates/part/detail.html:80 +#: part/templates/part/detail.html:81 msgid "Default Supplier" msgstr "Standard-Zulieferer" -#: part/templates/part/detail.html:88 +#: part/templates/part/detail.html:89 msgid "Units" msgstr "Einheiten" -#: part/templates/part/detail.html:94 +#: part/templates/part/detail.html:95 msgid "Minimum Stock" msgstr "Minimaler Lagerbestand" -#: part/templates/part/detail.html:100 +#: part/templates/part/detail.html:101 #, fuzzy #| msgid "Create new Stock Item" msgid "Creation Date" msgstr "Neues Lagerobjekt hinzufügen" -#: part/templates/part/detail.html:106 +#: part/templates/part/detail.html:107 #, fuzzy #| msgid "Created" msgid "Created By" msgstr "Erstellt" -#: part/templates/part/detail.html:113 +#: part/templates/part/detail.html:114 msgid "Responsible User" msgstr "" -#: part/templates/part/detail.html:122 +#: part/templates/part/detail.html:123 msgid "Virtual" msgstr "Virtuell" -#: part/templates/part/detail.html:125 +#: part/templates/part/detail.html:126 msgid "Part is virtual (not a physical part)" msgstr "Teil ist virtuell (kein physisches Teil)" -#: part/templates/part/detail.html:127 +#: part/templates/part/detail.html:128 msgid "Part is not a virtual part" msgstr "Teil ist nicht virtuell" -#: part/templates/part/detail.html:131 +#: part/templates/part/detail.html:132 msgid "Assembly" msgstr "Baugruppe" -#: part/templates/part/detail.html:134 +#: part/templates/part/detail.html:135 msgid "Part can be assembled from other parts" msgstr "Teil kann aus anderen Teilen angefertigt werden" -#: part/templates/part/detail.html:136 +#: part/templates/part/detail.html:137 msgid "Part cannot be assembled from other parts" msgstr "Teil kann nicht aus anderen Teilen angefertigt werden" -#: part/templates/part/detail.html:140 +#: part/templates/part/detail.html:141 msgid "Component" msgstr "Komponente" -#: part/templates/part/detail.html:143 +#: part/templates/part/detail.html:144 msgid "Part can be used in assemblies" msgstr "Teil kann in Baugruppen benutzt werden" -#: part/templates/part/detail.html:145 +#: part/templates/part/detail.html:146 msgid "Part cannot be used in assemblies" msgstr "Teil kann nicht in Baugruppen benutzt werden" -#: part/templates/part/detail.html:149 +#: part/templates/part/detail.html:150 msgid "Trackable" msgstr "nachverfolgbar" -#: part/templates/part/detail.html:152 +#: part/templates/part/detail.html:153 msgid "Part stock is tracked by serial number" msgstr "Teilebestand in der Seriennummer hinterlegt" -#: part/templates/part/detail.html:154 +#: part/templates/part/detail.html:155 msgid "Part stock is not tracked by serial number" msgstr "Teilebestand ist nicht in der Seriennummer hinterlegt" -#: part/templates/part/detail.html:158 +#: part/templates/part/detail.html:159 msgid "Purchaseable" msgstr "Kaufbar" -#: part/templates/part/detail.html:161 part/templates/part/detail.html:163 +#: part/templates/part/detail.html:162 part/templates/part/detail.html:164 msgid "Part can be purchased from external suppliers" msgstr "Teil kann von externen Zulieferern gekauft werden" -#: part/templates/part/detail.html:168 +#: part/templates/part/detail.html:169 msgid "Sellable" msgstr "Verkaufbar" -#: part/templates/part/detail.html:171 +#: part/templates/part/detail.html:172 msgid "Part can be sold to customers" msgstr "Teil kann an Kunden verkauft werden" -#: part/templates/part/detail.html:173 +#: part/templates/part/detail.html:174 msgid "Part cannot be sold to customers" msgstr "Teil kann nicht an Kunden verkauft werden" @@ -1722,23 +1721,23 @@ msgstr "Teil favorisieren" msgid "Show pricing information" msgstr "Kosteninformationen ansehen" -#: part/templates/part/part_base.html:95 +#: part/templates/part/part_base.html:98 msgid "Available Stock" msgstr "Verfügbarer Lagerbestand" -#: part/templates/part/part_base.html:100 +#: part/templates/part/part_base.html:103 msgid "In Stock" msgstr "Auf Lager" -#: part/templates/part/part_base.html:121 +#: part/templates/part/part_base.html:124 msgid "Build Status" msgstr "Bau-Status" -#: part/templates/part/part_base.html:125 +#: part/templates/part/part_base.html:128 msgid "Can Build" msgstr "Herstellbar?" -#: part/templates/part/part_base.html:130 +#: part/templates/part/part_base.html:133 msgid "Underway" msgstr "unterwegs" @@ -1788,7 +1787,7 @@ msgstr "Varianten" msgid "BOM" msgstr "Stückliste" -#: part/templates/part/tabs.html:28 stock/templates/stock/item_base.html:113 +#: part/templates/part/tabs.html:28 stock/templates/stock/item_base.html:121 #: templates/navbar.html:12 msgid "Build" msgstr "Bau" @@ -1932,93 +1931,93 @@ msgstr "Anzahl angeben" msgid "Export Bill of Materials" msgstr "" -#: part/views.py:1406 +#: part/views.py:1404 #, fuzzy #| msgid "Confirm part creation" msgid "Confirm Part Deletion" msgstr "Erstellen des Teils bestätigen" -#: part/views.py:1413 +#: part/views.py:1411 msgid "Part was deleted" msgstr "" -#: part/views.py:1422 +#: part/views.py:1420 #, fuzzy #| msgid "Part packaging" msgid "Part Pricing" msgstr "Teile-Packaging" -#: part/views.py:1544 +#: part/views.py:1542 #, fuzzy #| msgid "Parameter Template" msgid "Create Part Parameter Template" msgstr "Parameter Vorlage" -#: part/views.py:1552 +#: part/views.py:1550 #, fuzzy #| msgid "Parameter Template" msgid "Edit Part Parameter Template" msgstr "Parameter Vorlage" -#: part/views.py:1559 +#: part/views.py:1557 #, fuzzy #| msgid "Parameter Template" msgid "Delete Part Parameter Template" msgstr "Parameter Vorlage" -#: part/views.py:1567 +#: part/views.py:1565 msgid "Create Part Parameter" msgstr "" -#: part/views.py:1617 +#: part/views.py:1615 #, fuzzy #| msgid "Edit attachment" msgid "Edit Part Parameter" msgstr "Anhang bearbeiten" -#: part/views.py:1631 +#: part/views.py:1629 #, fuzzy #| msgid "Delete attachment" msgid "Delete Part Parameter" msgstr "Anhang löschen" -#: part/views.py:1647 +#: part/views.py:1645 #, fuzzy #| msgid "Part category" msgid "Edit Part Category" msgstr "Teile-Kategorie" -#: part/views.py:1682 +#: part/views.py:1680 #, fuzzy #| msgid "Select part category" msgid "Delete Part Category" msgstr "Teilekategorie wählen" -#: part/views.py:1688 +#: part/views.py:1686 #, fuzzy #| msgid "Part category" msgid "Part category was deleted" msgstr "Teile-Kategorie" -#: part/views.py:1696 +#: part/views.py:1694 #, fuzzy #| msgid "Select part category" msgid "Create new part category" msgstr "Teilekategorie wählen" -#: part/views.py:1747 +#: part/views.py:1745 #, fuzzy #| msgid "Created new stock item" msgid "Create BOM item" msgstr "Neues Lagerobjekt erstellt" -#: part/views.py:1813 +#: part/views.py:1811 #, fuzzy #| msgid "Edit Stock Item" msgid "Edit BOM item" msgstr "Lagerobjekt bearbeiten" -#: part/views.py:1861 +#: part/views.py:1859 #, fuzzy #| msgid "Confirm build completion" msgid "Confim BOM item deletion" @@ -2119,45 +2118,45 @@ msgstr "Objekt löschen wenn Lagerbestand aufgebraucht" msgid "Stock Item Notes" msgstr "Lagerobjekt-Notizen" -#: stock/models.py:460 +#: stock/models.py:464 msgid "Quantity must be integer" msgstr "Anzahl muss eine Ganzzahl sein" -#: stock/models.py:466 +#: stock/models.py:470 #, 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:469 stock/models.py:472 +#: stock/models.py:473 stock/models.py:476 msgid "Serial numbers must be a list of integers" msgstr "Seriennummern muss eine Liste von Ganzzahlen sein" -#: stock/models.py:475 +#: stock/models.py:479 msgid "Quantity does not match serial numbers" msgstr "Anzahl stimmt nicht mit den Seriennummern überein" -#: stock/models.py:485 +#: stock/models.py:489 msgid "Serial numbers already exist: " msgstr "Seriennummern existieren bereits:" -#: stock/models.py:507 +#: stock/models.py:511 msgid "Add serial number" msgstr "Seriennummer hinzufügen" -#: stock/models.py:510 +#: stock/models.py:514 #, python-brace-format msgid "Serialized {n} items" msgstr "{n} Teile serialisiert" -#: stock/models.py:810 +#: stock/models.py:814 msgid "Tracking entry title" msgstr "Name des Eintrags-Trackings" -#: stock/models.py:812 +#: stock/models.py:816 msgid "Entry notes" msgstr "Eintrags-Notizen" -#: stock/models.py:814 +#: stock/models.py:818 msgid "Link to external page for further information" msgstr "Link auf externe Seite für weitere Informationen" @@ -2194,28 +2193,28 @@ msgstr "" msgid "This stock item was split from " msgstr "" -#: stock/templates/stock/item_base.html:85 +#: stock/templates/stock/item_base.html:88 msgid "Belongs To" msgstr "Gehört zu" -#: stock/templates/stock/item_base.html:90 +#: stock/templates/stock/item_base.html:94 #: stock/templates/stock/stock_adjust.html:17 msgid "Location" msgstr "Standort" -#: stock/templates/stock/item_base.html:96 +#: stock/templates/stock/item_base.html:101 msgid "Serial Number" msgstr "Seriennummer" -#: stock/templates/stock/item_base.html:146 +#: stock/templates/stock/item_base.html:160 msgid "Last Updated" msgstr "Zuletzt aktualisiert" -#: stock/templates/stock/item_base.html:150 +#: stock/templates/stock/item_base.html:165 msgid "Last Stocktake" msgstr "Letzte Inventur" -#: stock/templates/stock/item_base.html:154 +#: stock/templates/stock/item_base.html:169 msgid "No stocktake performed" msgstr "Keine Inventur ausgeführt" @@ -2233,29 +2232,29 @@ msgstr "" msgid "Location Details" msgstr "Standort-Details" -#: stock/templates/stock/location.html:41 +#: stock/templates/stock/location.html:42 msgid "Location Path" msgstr "Standord-Pfad" -#: stock/templates/stock/location.html:46 +#: stock/templates/stock/location.html:47 msgid "Location Description" msgstr "Standort-Beschreibung" -#: stock/templates/stock/location.html:51 +#: stock/templates/stock/location.html:52 msgid "Sublocations" msgstr "Sub-Standorte" -#: stock/templates/stock/location.html:56 -#: stock/templates/stock/location.html:70 templates/stats.html:18 -#: templates/stats.html:21 +#: stock/templates/stock/location.html:57 +#: stock/templates/stock/location.html:72 templates/stats.html:21 +#: templates/stats.html:30 msgid "Stock Items" msgstr "Lagerobjekte" -#: stock/templates/stock/location.html:61 +#: stock/templates/stock/location.html:62 msgid "Stock Details" msgstr "Objekt-Details" -#: stock/templates/stock/location.html:65 +#: stock/templates/stock/location.html:67 #: templates/InvenTree/search_stock_location.html:6 templates/stats.html:25 msgid "Stock Locations" msgstr "Lagerobjekt-Standorte" @@ -2433,30 +2432,40 @@ msgstr "" msgid "No results found" msgstr "Keine Seriennummern gefunden" -#: templates/about.html:18 +#: templates/about.html:13 msgid "InvenTree Version Information" msgstr "InvenTree-Versionsinformationen" #: templates/about.html:21 -msgid "Version" -msgstr "Version" +msgid "Instance Name" +msgstr "" -#: templates/about.html:24 +#: templates/about.html:26 +#, fuzzy +#| msgid "InvenTree Version Information" +msgid "InvenTree Version" +msgstr "InvenTree-Versionsinformationen" + +#: templates/about.html:30 msgid "Commit Hash" msgstr "Commit-Hash" -#: templates/about.html:27 +#: templates/about.html:34 msgid "Commit Date" msgstr "Commit-Datum" -#: templates/about.html:33 +#: templates/about.html:38 msgid "InvenTree Documentation" msgstr "InvenTree-Dokumentation" -#: templates/about.html:37 +#: templates/about.html:43 msgid "View Code on GitHub" msgstr "Code auf GitHub ansehen" +#: templates/about.html:47 +msgid "Submit Bug Report" +msgstr "" + #: templates/navbar.html:23 msgid "Admin" msgstr "" @@ -2530,3 +2539,9 @@ msgstr "bestellt" #| msgid "Delete Stock Item" msgid "Delete Stock" msgstr "Lagerobjekt löschen" + +#~ msgid "URL" +#~ msgstr "URL" + +#~ msgid "Version" +#~ msgstr "Version" diff --git a/InvenTree/locale/en/LC_MESSAGES/django.po b/InvenTree/locale/en/LC_MESSAGES/django.po index def566c9da..9291ccd461 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: 2020-04-05 10:55+0000\n" +"POT-Creation-Date: 2020-04-09 15:04+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,30 +18,30 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: InvenTree/helpers.py:201 order/models.py:164 order/models.py:215 +#: InvenTree/helpers.py:240 order/models.py:164 order/models.py:215 msgid "Invalid quantity provided" msgstr "" -#: InvenTree/helpers.py:204 +#: InvenTree/helpers.py:243 msgid "Empty serial number string" msgstr "" -#: InvenTree/helpers.py:225 InvenTree/helpers.py:242 +#: InvenTree/helpers.py:264 InvenTree/helpers.py:281 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:229 InvenTree/helpers.py:232 InvenTree/helpers.py:235 -#: InvenTree/helpers.py:246 +#: InvenTree/helpers.py:268 InvenTree/helpers.py:271 InvenTree/helpers.py:274 +#: InvenTree/helpers.py:285 #, python-brace-format msgid "Invalid group: {g}" msgstr "" -#: InvenTree/helpers.py:252 +#: InvenTree/helpers.py:291 msgid "No serial numbers found" msgstr "" -#: InvenTree/helpers.py:256 +#: InvenTree/helpers.py:295 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" @@ -112,7 +112,7 @@ msgstr "" #: InvenTree/status_codes.py:98 build/templates/build/allocate_edit.html:28 #: build/templates/build/allocate_view.html:21 -#: part/templates/part/part_base.html:106 part/templates/part/tabs.html:21 +#: part/templates/part/part_base.html:109 part/templates/part/tabs.html:21 msgid "Allocated" msgstr "" @@ -141,7 +141,7 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:548 +#: InvenTree/views.py:549 msgid "Database Statistics" msgstr "" @@ -183,7 +183,7 @@ msgstr "" msgid "Batch code for this build output" msgstr "" -#: build/models.py:97 +#: build/models.py:97 stock/models.py:331 msgid "Link to external URL" msgstr "" @@ -227,7 +227,7 @@ msgstr "" #: build/templates/build/allocate_edit.html:19 #: build/templates/build/allocate_view.html:17 -#: build/templates/build/detail.html:17 +#: build/templates/build/detail.html:21 #: company/templates/company/detail_part.html:65 #: order/templates/order/order_wizard/select_parts.html:30 #: order/templates/order/purchase_order_detail.html:25 @@ -263,12 +263,12 @@ msgstr "" #: company/templates/company/supplier_part_base.html:50 #: company/templates/company/supplier_part_detail.html:27 #: order/templates/order/purchase_order_detail.html:26 -#: part/templates/part/detail.html:37 +#: part/templates/part/detail.html:38 msgid "Description" msgstr "" #: build/templates/build/allocate_view.html:22 -#: part/templates/part/part_base.html:112 +#: part/templates/part/part_base.html:115 msgid "On Order" msgstr "" @@ -284,65 +284,64 @@ msgstr "" msgid "Build Details" msgstr "" -#: build/templates/build/detail.html:14 +#: build/templates/build/detail.html:16 msgid "Title" msgstr "" -#: build/templates/build/detail.html:20 +#: build/templates/build/detail.html:26 #: company/templates/company/supplier_part_pricing.html:27 #: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:29 -#: stock/templates/stock/item_base.html:101 +#: stock/templates/stock/item_base.html:107 #: stock/templates/stock/stock_adjust.html:18 msgid "Quantity" msgstr "" -#: build/templates/build/detail.html:23 +#: build/templates/build/detail.html:30 msgid "Stock Source" msgstr "" -#: build/templates/build/detail.html:28 +#: build/templates/build/detail.html:35 msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:33 +#: build/templates/build/detail.html:41 #: order/templates/order/order_base.html:71 -#: stock/templates/stock/item_base.html:158 +#: stock/templates/stock/item_base.html:174 msgid "Status" msgstr "" -#: build/templates/build/detail.html:37 -#: stock/templates/stock/item_base.html:107 +#: build/templates/build/detail.html:47 +#: stock/templates/stock/item_base.html:114 msgid "Batch" msgstr "" -#: build/templates/build/detail.html:42 -#: company/templates/company/detail_part.html:90 +#: build/templates/build/detail.html:54 #: company/templates/company/supplier_part_base.html:47 #: company/templates/company/supplier_part_detail.html:24 -#: part/templates/part/part_base.html:81 -#: stock/templates/stock/item_base.html:131 -msgid "URL" +#: part/templates/part/detail.html:67 part/templates/part/part_base.html:84 +#: stock/templates/stock/item_base.html:142 +msgid "External Link" msgstr "" -#: build/templates/build/detail.html:46 -#: order/templates/order/order_base.html:75 +#: build/templates/build/detail.html:60 +#: order/templates/order/order_base.html:83 msgid "Created" msgstr "" -#: build/templates/build/detail.html:50 +#: build/templates/build/detail.html:66 msgid "Enough Parts?" msgstr "" -#: build/templates/build/detail.html:53 +#: build/templates/build/detail.html:69 msgid "Yes" msgstr "" -#: build/templates/build/detail.html:55 +#: build/templates/build/detail.html:71 msgid "No" msgstr "" -#: build/templates/build/detail.html:62 +#: build/templates/build/detail.html:79 msgid "Completed" msgstr "" @@ -371,7 +370,7 @@ msgstr "" msgid "Outputs" msgstr "" -#: build/templates/build/tabs.html:11 company/models.py:248 +#: build/templates/build/tabs.html:11 company/models.py:264 #: company/templates/company/tabs.html:26 order/templates/order/tabs.html:15 #: part/templates/part/tabs.html:58 stock/templates/stock/tabs.html:17 msgid "Notes" @@ -530,81 +529,81 @@ msgstr "" msgid "Delete Currency" msgstr "" -#: company/models.py:74 +#: company/models.py:76 msgid "Company name" msgstr "" -#: company/models.py:76 +#: company/models.py:78 msgid "Description of the company" msgstr "" -#: company/models.py:78 +#: company/models.py:80 msgid "Company website URL" msgstr "" -#: company/models.py:81 +#: company/models.py:83 msgid "Company address" msgstr "" -#: company/models.py:84 +#: company/models.py:86 msgid "Contact phone number" msgstr "" -#: company/models.py:86 +#: company/models.py:88 msgid "Contact email address" msgstr "" -#: company/models.py:89 +#: company/models.py:91 msgid "Point of contact" msgstr "" -#: company/models.py:91 +#: company/models.py:93 msgid "Link to external company information" msgstr "" -#: company/models.py:97 +#: company/models.py:105 msgid "Do you sell items to this company?" msgstr "" -#: company/models.py:99 +#: company/models.py:107 msgid "Do you purchase items from this company?" msgstr "" -#: company/models.py:229 +#: company/models.py:245 msgid "Select part" msgstr "" -#: company/models.py:235 +#: company/models.py:251 msgid "Select supplier" msgstr "" -#: company/models.py:238 +#: company/models.py:254 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:240 company/templates/company/detail_part.html:81 +#: company/models.py:256 company/templates/company/detail_part.html:81 #: company/templates/company/supplier_part_base.html:53 #: company/templates/company/supplier_part_detail.html:30 msgid "Manufacturer" msgstr "" -#: company/models.py:242 +#: company/models.py:258 msgid "Manufacturer part number" msgstr "" -#: company/models.py:244 +#: company/models.py:260 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:246 +#: company/models.py:262 msgid "Supplier part description" msgstr "" -#: company/models.py:250 +#: company/models.py:266 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:252 +#: company/models.py:268 msgid "Part packaging" msgstr "" @@ -612,24 +611,24 @@ msgstr "" msgid "Company" msgstr "" -#: company/templates/company/company_base.html:48 +#: company/templates/company/company_base.html:50 #: company/templates/company/index.html:59 msgid "Website" msgstr "" -#: company/templates/company/company_base.html:53 +#: company/templates/company/company_base.html:57 msgid "Address" msgstr "" -#: company/templates/company/company_base.html:58 +#: company/templates/company/company_base.html:64 msgid "Phone" msgstr "" -#: company/templates/company/company_base.html:63 +#: company/templates/company/company_base.html:71 msgid "Email" msgstr "" -#: company/templates/company/company_base.html:68 +#: company/templates/company/company_base.html:78 msgid "Contact" msgstr "" @@ -637,18 +636,18 @@ msgstr "" msgid "Company Details" msgstr "" -#: company/templates/company/detail.html:13 -#: stock/templates/stock/item_base.html:125 +#: company/templates/company/detail.html:16 +#: stock/templates/stock/item_base.html:135 msgid "Customer" msgstr "" -#: company/templates/company/detail.html:17 +#: company/templates/company/detail.html:21 #: company/templates/company/index.html:46 #: company/templates/company/supplier_part_base.html:44 #: company/templates/company/supplier_part_detail.html:21 -#: order/templates/order/order_base.html:67 +#: order/templates/order/order_base.html:66 #: order/templates/order/order_wizard/select_pos.html:30 -#: stock/templates/stock/item_base.html:137 +#: stock/templates/stock/item_base.html:149 msgid "Supplier" msgstr "" @@ -676,6 +675,10 @@ msgstr "" msgid "SKU" msgstr "" +#: company/templates/company/detail_part.html:90 +msgid "Link" +msgstr "" + #: company/templates/company/detail_purchase_orders.html:8 #: company/templates/company/tabs.html:15 part/templates/part/tabs.html:43 msgid "Purchase Orders" @@ -708,8 +711,8 @@ msgstr "" msgid "ID" msgstr "" -#: company/templates/company/index.html:69 part/templates/part/category.html:81 -#: templates/navbar.html:10 templates/stats.html:7 templates/stats.html:10 +#: company/templates/company/index.html:69 part/templates/part/category.html:83 +#: templates/navbar.html:10 templates/stats.html:8 templates/stats.html:17 msgid "Parts" msgstr "" @@ -724,7 +727,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:6 #: company/templates/company/supplier_part_base.html:13 -#: stock/templates/stock/item_base.html:141 +#: stock/templates/stock/item_base.html:154 msgid "Supplier Part" msgstr "" @@ -903,7 +906,7 @@ msgid "Order notes" msgstr "" #: order/models.py:162 order/models.py:213 part/views.py:1119 -#: stock/models.py:463 +#: stock/models.py:467 msgid "Quantity must be greater than zero" msgstr "" @@ -927,7 +930,7 @@ msgstr "" msgid "Line item notes" msgstr "" -#: order/models.py:298 stock/templates/stock/item_base.html:119 +#: order/models.py:298 stock/templates/stock/item_base.html:128 msgid "Purchase Order" msgstr "" @@ -939,15 +942,15 @@ msgstr "" msgid "Number of items received" msgstr "" -#: order/templates/order/order_base.html:64 +#: order/templates/order/order_base.html:61 msgid "Purchase Order Details" msgstr "" -#: order/templates/order/order_base.html:80 +#: order/templates/order/order_base.html:89 msgid "Issued" msgstr "" -#: order/templates/order/order_base.html:86 +#: order/templates/order/order_base.html:96 #: order/templates/order/purchase_order_detail.html:31 msgid "Received" msgstr "" @@ -1213,171 +1216,171 @@ msgstr "" msgid "Select currency for price calculation" msgstr "" -#: part/models.py:62 +#: part/models.py:61 msgid "Default location for parts in this category" msgstr "" -#: part/models.py:65 +#: part/models.py:64 msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:339 +#: part/models.py:338 msgid "Part must be unique for name, IPN and revision" msgstr "" -#: part/models.py:353 +#: part/models.py:352 msgid "Part cannot be a template part if it is a variant of another part" msgstr "" -#: part/models.py:354 +#: part/models.py:353 msgid "Part cannot be a variant of another part if it is already a template" msgstr "" -#: part/models.py:358 part/templates/part/detail.html:18 +#: part/models.py:357 part/templates/part/detail.html:19 msgid "Part name" msgstr "" -#: part/models.py:362 +#: part/models.py:361 msgid "Is this part a template part?" msgstr "" -#: part/models.py:371 +#: part/models.py:370 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:373 +#: part/models.py:372 msgid "Part description" msgstr "" -#: part/models.py:375 +#: part/models.py:374 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:380 +#: part/models.py:379 msgid "Part category" msgstr "" -#: part/models.py:382 +#: part/models.py:381 msgid "Internal Part Number" msgstr "" -#: part/models.py:384 +#: part/models.py:383 msgid "Part revision or version number" msgstr "" -#: part/models.py:386 +#: part/models.py:385 msgid "Link to extenal URL" msgstr "" -#: part/models.py:398 +#: part/models.py:397 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:442 +#: part/models.py:441 msgid "Default supplier part" msgstr "" -#: part/models.py:445 +#: part/models.py:444 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:447 +#: part/models.py:446 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:449 +#: part/models.py:448 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:451 +#: part/models.py:450 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:453 +#: part/models.py:452 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:455 +#: part/models.py:454 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:457 +#: part/models.py:456 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:459 +#: part/models.py:458 msgid "Is this part active?" msgstr "" -#: part/models.py:461 +#: part/models.py:460 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:463 +#: part/models.py:462 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:465 +#: part/models.py:464 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:1041 +#: part/models.py:1040 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:1046 +#: part/models.py:1045 msgid "Parameter Name" msgstr "" -#: part/models.py:1048 +#: part/models.py:1047 msgid "Parameter Units" msgstr "" -#: part/models.py:1074 +#: part/models.py:1073 msgid "Parent Part" msgstr "" -#: part/models.py:1076 +#: part/models.py:1075 msgid "Parameter Template" msgstr "" -#: part/models.py:1078 +#: part/models.py:1077 msgid "Parameter Value" msgstr "" -#: part/models.py:1102 +#: part/models.py:1101 msgid "Select parent part" msgstr "" -#: part/models.py:1111 +#: part/models.py:1110 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:1118 +#: part/models.py:1117 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:1121 +#: part/models.py:1120 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:1124 +#: part/models.py:1123 msgid "BOM item reference" msgstr "" -#: part/models.py:1127 +#: part/models.py:1126 msgid "BOM item notes" msgstr "" -#: part/models.py:1129 +#: part/models.py:1128 msgid "BOM line checksum" msgstr "" -#: part/models.py:1192 +#: part/models.py:1191 msgid "Part cannot be added to its own Bill of Materials" msgstr "" -#: part/models.py:1199 +#: part/models.py:1198 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" @@ -1386,8 +1389,8 @@ msgstr "" msgid "Part Attachments" msgstr "" -#: part/templates/part/category.html:13 part/templates/part/category.html:76 -#: templates/stats.html:14 +#: part/templates/part/category.html:13 part/templates/part/category.html:78 +#: templates/stats.html:12 msgid "Part Categories" msgstr "" @@ -1395,31 +1398,31 @@ msgstr "" msgid "All parts" msgstr "" -#: part/templates/part/category.html:34 part/templates/part/category.html:72 +#: part/templates/part/category.html:34 part/templates/part/category.html:73 msgid "Category Details" msgstr "" -#: part/templates/part/category.html:38 +#: part/templates/part/category.html:39 msgid "Category Path" msgstr "" -#: part/templates/part/category.html:43 +#: part/templates/part/category.html:44 msgid "Category Description" msgstr "" -#: part/templates/part/category.html:49 part/templates/part/detail.html:73 +#: part/templates/part/category.html:50 part/templates/part/detail.html:74 msgid "Default Location" msgstr "" -#: part/templates/part/category.html:56 part/templates/part/detail.html:50 +#: part/templates/part/category.html:57 part/templates/part/detail.html:51 msgid "Keywords" msgstr "" -#: part/templates/part/category.html:62 +#: part/templates/part/category.html:63 msgid "Subcategories" msgstr "" -#: part/templates/part/category.html:67 +#: part/templates/part/category.html:68 msgid "Parts (Including subcategories)" msgstr "" @@ -1427,115 +1430,111 @@ msgstr "" msgid "Part Details" msgstr "" -#: part/templates/part/detail.html:24 part/templates/part/part_base.html:75 +#: part/templates/part/detail.html:25 part/templates/part/part_base.html:77 msgid "IPN" msgstr "" -#: part/templates/part/detail.html:31 +#: part/templates/part/detail.html:32 msgid "Revision" msgstr "" -#: part/templates/part/detail.html:43 +#: part/templates/part/detail.html:44 msgid "Variant Of" msgstr "" -#: part/templates/part/detail.html:56 +#: part/templates/part/detail.html:57 msgid "Category" msgstr "" -#: part/templates/part/detail.html:66 -msgid "Link" -msgstr "" - -#: part/templates/part/detail.html:80 +#: part/templates/part/detail.html:81 msgid "Default Supplier" msgstr "" -#: part/templates/part/detail.html:88 +#: part/templates/part/detail.html:89 msgid "Units" msgstr "" -#: part/templates/part/detail.html:94 +#: part/templates/part/detail.html:95 msgid "Minimum Stock" msgstr "" -#: part/templates/part/detail.html:100 +#: part/templates/part/detail.html:101 msgid "Creation Date" msgstr "" -#: part/templates/part/detail.html:106 +#: part/templates/part/detail.html:107 msgid "Created By" msgstr "" -#: part/templates/part/detail.html:113 +#: part/templates/part/detail.html:114 msgid "Responsible User" msgstr "" -#: part/templates/part/detail.html:122 +#: part/templates/part/detail.html:123 msgid "Virtual" msgstr "" -#: part/templates/part/detail.html:125 +#: part/templates/part/detail.html:126 msgid "Part is virtual (not a physical part)" msgstr "" -#: part/templates/part/detail.html:127 +#: part/templates/part/detail.html:128 msgid "Part is not a virtual part" msgstr "" -#: part/templates/part/detail.html:131 +#: part/templates/part/detail.html:132 msgid "Assembly" msgstr "" -#: part/templates/part/detail.html:134 +#: part/templates/part/detail.html:135 msgid "Part can be assembled from other parts" msgstr "" -#: part/templates/part/detail.html:136 +#: part/templates/part/detail.html:137 msgid "Part cannot be assembled from other parts" msgstr "" -#: part/templates/part/detail.html:140 +#: part/templates/part/detail.html:141 msgid "Component" msgstr "" -#: part/templates/part/detail.html:143 +#: part/templates/part/detail.html:144 msgid "Part can be used in assemblies" msgstr "" -#: part/templates/part/detail.html:145 +#: part/templates/part/detail.html:146 msgid "Part cannot be used in assemblies" msgstr "" -#: part/templates/part/detail.html:149 +#: part/templates/part/detail.html:150 msgid "Trackable" msgstr "" -#: part/templates/part/detail.html:152 +#: part/templates/part/detail.html:153 msgid "Part stock is tracked by serial number" msgstr "" -#: part/templates/part/detail.html:154 +#: part/templates/part/detail.html:155 msgid "Part stock is not tracked by serial number" msgstr "" -#: part/templates/part/detail.html:158 +#: part/templates/part/detail.html:159 msgid "Purchaseable" msgstr "" -#: part/templates/part/detail.html:161 part/templates/part/detail.html:163 +#: part/templates/part/detail.html:162 part/templates/part/detail.html:164 msgid "Part can be purchased from external suppliers" msgstr "" -#: part/templates/part/detail.html:168 +#: part/templates/part/detail.html:169 msgid "Sellable" msgstr "" -#: part/templates/part/detail.html:171 +#: part/templates/part/detail.html:172 msgid "Part can be sold to customers" msgstr "" -#: part/templates/part/detail.html:173 +#: part/templates/part/detail.html:174 msgid "Part cannot be sold to customers" msgstr "" @@ -1563,23 +1562,23 @@ msgstr "" msgid "Show pricing information" msgstr "" -#: part/templates/part/part_base.html:95 +#: part/templates/part/part_base.html:98 msgid "Available Stock" msgstr "" -#: part/templates/part/part_base.html:100 +#: part/templates/part/part_base.html:103 msgid "In Stock" msgstr "" -#: part/templates/part/part_base.html:121 +#: part/templates/part/part_base.html:124 msgid "Build Status" msgstr "" -#: part/templates/part/part_base.html:125 +#: part/templates/part/part_base.html:128 msgid "Can Build" msgstr "" -#: part/templates/part/part_base.html:130 +#: part/templates/part/part_base.html:133 msgid "Underway" msgstr "" @@ -1619,7 +1618,7 @@ msgstr "" msgid "BOM" msgstr "" -#: part/templates/part/tabs.html:28 stock/templates/stock/item_base.html:113 +#: part/templates/part/tabs.html:28 stock/templates/stock/item_base.html:121 #: templates/navbar.html:12 msgid "Build" msgstr "" @@ -1737,67 +1736,67 @@ msgstr "" msgid "Export Bill of Materials" msgstr "" -#: part/views.py:1406 +#: part/views.py:1404 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:1413 +#: part/views.py:1411 msgid "Part was deleted" msgstr "" -#: part/views.py:1422 +#: part/views.py:1420 msgid "Part Pricing" msgstr "" -#: part/views.py:1544 +#: part/views.py:1542 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:1552 +#: part/views.py:1550 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:1559 +#: part/views.py:1557 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:1567 +#: part/views.py:1565 msgid "Create Part Parameter" msgstr "" -#: part/views.py:1617 +#: part/views.py:1615 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:1631 +#: part/views.py:1629 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:1647 +#: part/views.py:1645 msgid "Edit Part Category" msgstr "" -#: part/views.py:1682 +#: part/views.py:1680 msgid "Delete Part Category" msgstr "" -#: part/views.py:1688 +#: part/views.py:1686 msgid "Part category was deleted" msgstr "" -#: part/views.py:1696 +#: part/views.py:1694 msgid "Create new part category" msgstr "" -#: part/views.py:1747 +#: part/views.py:1745 msgid "Create BOM item" msgstr "" -#: part/views.py:1813 +#: part/views.py:1811 msgid "Edit BOM item" msgstr "" -#: part/views.py:1861 +#: part/views.py:1859 msgid "Confim BOM item deletion" msgstr "" @@ -1893,45 +1892,45 @@ msgstr "" msgid "Stock Item Notes" msgstr "" -#: stock/models.py:460 +#: stock/models.py:464 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:466 +#: stock/models.py:470 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:469 stock/models.py:472 +#: stock/models.py:473 stock/models.py:476 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:475 +#: stock/models.py:479 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:485 +#: stock/models.py:489 msgid "Serial numbers already exist: " msgstr "" -#: stock/models.py:507 +#: stock/models.py:511 msgid "Add serial number" msgstr "" -#: stock/models.py:510 +#: stock/models.py:514 #, python-brace-format msgid "Serialized {n} items" msgstr "" -#: stock/models.py:810 +#: stock/models.py:814 msgid "Tracking entry title" msgstr "" -#: stock/models.py:812 +#: stock/models.py:816 msgid "Entry notes" msgstr "" -#: stock/models.py:814 +#: stock/models.py:818 msgid "Link to external page for further information" msgstr "" @@ -1962,28 +1961,28 @@ msgstr "" msgid "This stock item was split from " msgstr "" -#: stock/templates/stock/item_base.html:85 +#: stock/templates/stock/item_base.html:88 msgid "Belongs To" msgstr "" -#: stock/templates/stock/item_base.html:90 +#: stock/templates/stock/item_base.html:94 #: stock/templates/stock/stock_adjust.html:17 msgid "Location" msgstr "" -#: stock/templates/stock/item_base.html:96 +#: stock/templates/stock/item_base.html:101 msgid "Serial Number" msgstr "" -#: stock/templates/stock/item_base.html:146 +#: stock/templates/stock/item_base.html:160 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:150 +#: stock/templates/stock/item_base.html:165 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:154 +#: stock/templates/stock/item_base.html:169 msgid "No stocktake performed" msgstr "" @@ -1999,29 +1998,29 @@ msgstr "" msgid "Location Details" msgstr "" -#: stock/templates/stock/location.html:41 +#: stock/templates/stock/location.html:42 msgid "Location Path" msgstr "" -#: stock/templates/stock/location.html:46 +#: stock/templates/stock/location.html:47 msgid "Location Description" msgstr "" -#: stock/templates/stock/location.html:51 +#: stock/templates/stock/location.html:52 msgid "Sublocations" msgstr "" -#: stock/templates/stock/location.html:56 -#: stock/templates/stock/location.html:70 templates/stats.html:18 -#: templates/stats.html:21 +#: stock/templates/stock/location.html:57 +#: stock/templates/stock/location.html:72 templates/stats.html:21 +#: templates/stats.html:30 msgid "Stock Items" msgstr "" -#: stock/templates/stock/location.html:61 +#: stock/templates/stock/location.html:62 msgid "Stock Details" msgstr "" -#: stock/templates/stock/location.html:65 +#: stock/templates/stock/location.html:67 #: templates/InvenTree/search_stock_location.html:6 templates/stats.html:25 msgid "Stock Locations" msgstr "" @@ -2194,30 +2193,38 @@ msgstr "" msgid "No results found" msgstr "" -#: templates/about.html:18 +#: templates/about.html:13 msgid "InvenTree Version Information" msgstr "" #: templates/about.html:21 -msgid "Version" +msgid "Instance Name" msgstr "" -#: templates/about.html:24 +#: templates/about.html:26 +msgid "InvenTree Version" +msgstr "" + +#: templates/about.html:30 msgid "Commit Hash" msgstr "" -#: templates/about.html:27 +#: templates/about.html:34 msgid "Commit Date" msgstr "" -#: templates/about.html:33 +#: templates/about.html:38 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:37 +#: templates/about.html:43 msgid "View Code on GitHub" msgstr "" +#: templates/about.html:47 +msgid "Submit Bug Report" +msgstr "" + #: templates/navbar.html:23 msgid "Admin" msgstr "" diff --git a/InvenTree/locale/es/LC_MESSAGES/django.po b/InvenTree/locale/es/LC_MESSAGES/django.po index def566c9da..9291ccd461 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: 2020-04-05 10:55+0000\n" +"POT-Creation-Date: 2020-04-09 15:04+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,30 +18,30 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: InvenTree/helpers.py:201 order/models.py:164 order/models.py:215 +#: InvenTree/helpers.py:240 order/models.py:164 order/models.py:215 msgid "Invalid quantity provided" msgstr "" -#: InvenTree/helpers.py:204 +#: InvenTree/helpers.py:243 msgid "Empty serial number string" msgstr "" -#: InvenTree/helpers.py:225 InvenTree/helpers.py:242 +#: InvenTree/helpers.py:264 InvenTree/helpers.py:281 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:229 InvenTree/helpers.py:232 InvenTree/helpers.py:235 -#: InvenTree/helpers.py:246 +#: InvenTree/helpers.py:268 InvenTree/helpers.py:271 InvenTree/helpers.py:274 +#: InvenTree/helpers.py:285 #, python-brace-format msgid "Invalid group: {g}" msgstr "" -#: InvenTree/helpers.py:252 +#: InvenTree/helpers.py:291 msgid "No serial numbers found" msgstr "" -#: InvenTree/helpers.py:256 +#: InvenTree/helpers.py:295 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" @@ -112,7 +112,7 @@ msgstr "" #: InvenTree/status_codes.py:98 build/templates/build/allocate_edit.html:28 #: build/templates/build/allocate_view.html:21 -#: part/templates/part/part_base.html:106 part/templates/part/tabs.html:21 +#: part/templates/part/part_base.html:109 part/templates/part/tabs.html:21 msgid "Allocated" msgstr "" @@ -141,7 +141,7 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:548 +#: InvenTree/views.py:549 msgid "Database Statistics" msgstr "" @@ -183,7 +183,7 @@ msgstr "" msgid "Batch code for this build output" msgstr "" -#: build/models.py:97 +#: build/models.py:97 stock/models.py:331 msgid "Link to external URL" msgstr "" @@ -227,7 +227,7 @@ msgstr "" #: build/templates/build/allocate_edit.html:19 #: build/templates/build/allocate_view.html:17 -#: build/templates/build/detail.html:17 +#: build/templates/build/detail.html:21 #: company/templates/company/detail_part.html:65 #: order/templates/order/order_wizard/select_parts.html:30 #: order/templates/order/purchase_order_detail.html:25 @@ -263,12 +263,12 @@ msgstr "" #: company/templates/company/supplier_part_base.html:50 #: company/templates/company/supplier_part_detail.html:27 #: order/templates/order/purchase_order_detail.html:26 -#: part/templates/part/detail.html:37 +#: part/templates/part/detail.html:38 msgid "Description" msgstr "" #: build/templates/build/allocate_view.html:22 -#: part/templates/part/part_base.html:112 +#: part/templates/part/part_base.html:115 msgid "On Order" msgstr "" @@ -284,65 +284,64 @@ msgstr "" msgid "Build Details" msgstr "" -#: build/templates/build/detail.html:14 +#: build/templates/build/detail.html:16 msgid "Title" msgstr "" -#: build/templates/build/detail.html:20 +#: build/templates/build/detail.html:26 #: company/templates/company/supplier_part_pricing.html:27 #: order/templates/order/order_wizard/select_parts.html:32 #: order/templates/order/purchase_order_detail.html:29 -#: stock/templates/stock/item_base.html:101 +#: stock/templates/stock/item_base.html:107 #: stock/templates/stock/stock_adjust.html:18 msgid "Quantity" msgstr "" -#: build/templates/build/detail.html:23 +#: build/templates/build/detail.html:30 msgid "Stock Source" msgstr "" -#: build/templates/build/detail.html:28 +#: build/templates/build/detail.html:35 msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:33 +#: build/templates/build/detail.html:41 #: order/templates/order/order_base.html:71 -#: stock/templates/stock/item_base.html:158 +#: stock/templates/stock/item_base.html:174 msgid "Status" msgstr "" -#: build/templates/build/detail.html:37 -#: stock/templates/stock/item_base.html:107 +#: build/templates/build/detail.html:47 +#: stock/templates/stock/item_base.html:114 msgid "Batch" msgstr "" -#: build/templates/build/detail.html:42 -#: company/templates/company/detail_part.html:90 +#: build/templates/build/detail.html:54 #: company/templates/company/supplier_part_base.html:47 #: company/templates/company/supplier_part_detail.html:24 -#: part/templates/part/part_base.html:81 -#: stock/templates/stock/item_base.html:131 -msgid "URL" +#: part/templates/part/detail.html:67 part/templates/part/part_base.html:84 +#: stock/templates/stock/item_base.html:142 +msgid "External Link" msgstr "" -#: build/templates/build/detail.html:46 -#: order/templates/order/order_base.html:75 +#: build/templates/build/detail.html:60 +#: order/templates/order/order_base.html:83 msgid "Created" msgstr "" -#: build/templates/build/detail.html:50 +#: build/templates/build/detail.html:66 msgid "Enough Parts?" msgstr "" -#: build/templates/build/detail.html:53 +#: build/templates/build/detail.html:69 msgid "Yes" msgstr "" -#: build/templates/build/detail.html:55 +#: build/templates/build/detail.html:71 msgid "No" msgstr "" -#: build/templates/build/detail.html:62 +#: build/templates/build/detail.html:79 msgid "Completed" msgstr "" @@ -371,7 +370,7 @@ msgstr "" msgid "Outputs" msgstr "" -#: build/templates/build/tabs.html:11 company/models.py:248 +#: build/templates/build/tabs.html:11 company/models.py:264 #: company/templates/company/tabs.html:26 order/templates/order/tabs.html:15 #: part/templates/part/tabs.html:58 stock/templates/stock/tabs.html:17 msgid "Notes" @@ -530,81 +529,81 @@ msgstr "" msgid "Delete Currency" msgstr "" -#: company/models.py:74 +#: company/models.py:76 msgid "Company name" msgstr "" -#: company/models.py:76 +#: company/models.py:78 msgid "Description of the company" msgstr "" -#: company/models.py:78 +#: company/models.py:80 msgid "Company website URL" msgstr "" -#: company/models.py:81 +#: company/models.py:83 msgid "Company address" msgstr "" -#: company/models.py:84 +#: company/models.py:86 msgid "Contact phone number" msgstr "" -#: company/models.py:86 +#: company/models.py:88 msgid "Contact email address" msgstr "" -#: company/models.py:89 +#: company/models.py:91 msgid "Point of contact" msgstr "" -#: company/models.py:91 +#: company/models.py:93 msgid "Link to external company information" msgstr "" -#: company/models.py:97 +#: company/models.py:105 msgid "Do you sell items to this company?" msgstr "" -#: company/models.py:99 +#: company/models.py:107 msgid "Do you purchase items from this company?" msgstr "" -#: company/models.py:229 +#: company/models.py:245 msgid "Select part" msgstr "" -#: company/models.py:235 +#: company/models.py:251 msgid "Select supplier" msgstr "" -#: company/models.py:238 +#: company/models.py:254 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:240 company/templates/company/detail_part.html:81 +#: company/models.py:256 company/templates/company/detail_part.html:81 #: company/templates/company/supplier_part_base.html:53 #: company/templates/company/supplier_part_detail.html:30 msgid "Manufacturer" msgstr "" -#: company/models.py:242 +#: company/models.py:258 msgid "Manufacturer part number" msgstr "" -#: company/models.py:244 +#: company/models.py:260 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:246 +#: company/models.py:262 msgid "Supplier part description" msgstr "" -#: company/models.py:250 +#: company/models.py:266 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:252 +#: company/models.py:268 msgid "Part packaging" msgstr "" @@ -612,24 +611,24 @@ msgstr "" msgid "Company" msgstr "" -#: company/templates/company/company_base.html:48 +#: company/templates/company/company_base.html:50 #: company/templates/company/index.html:59 msgid "Website" msgstr "" -#: company/templates/company/company_base.html:53 +#: company/templates/company/company_base.html:57 msgid "Address" msgstr "" -#: company/templates/company/company_base.html:58 +#: company/templates/company/company_base.html:64 msgid "Phone" msgstr "" -#: company/templates/company/company_base.html:63 +#: company/templates/company/company_base.html:71 msgid "Email" msgstr "" -#: company/templates/company/company_base.html:68 +#: company/templates/company/company_base.html:78 msgid "Contact" msgstr "" @@ -637,18 +636,18 @@ msgstr "" msgid "Company Details" msgstr "" -#: company/templates/company/detail.html:13 -#: stock/templates/stock/item_base.html:125 +#: company/templates/company/detail.html:16 +#: stock/templates/stock/item_base.html:135 msgid "Customer" msgstr "" -#: company/templates/company/detail.html:17 +#: company/templates/company/detail.html:21 #: company/templates/company/index.html:46 #: company/templates/company/supplier_part_base.html:44 #: company/templates/company/supplier_part_detail.html:21 -#: order/templates/order/order_base.html:67 +#: order/templates/order/order_base.html:66 #: order/templates/order/order_wizard/select_pos.html:30 -#: stock/templates/stock/item_base.html:137 +#: stock/templates/stock/item_base.html:149 msgid "Supplier" msgstr "" @@ -676,6 +675,10 @@ msgstr "" msgid "SKU" msgstr "" +#: company/templates/company/detail_part.html:90 +msgid "Link" +msgstr "" + #: company/templates/company/detail_purchase_orders.html:8 #: company/templates/company/tabs.html:15 part/templates/part/tabs.html:43 msgid "Purchase Orders" @@ -708,8 +711,8 @@ msgstr "" msgid "ID" msgstr "" -#: company/templates/company/index.html:69 part/templates/part/category.html:81 -#: templates/navbar.html:10 templates/stats.html:7 templates/stats.html:10 +#: company/templates/company/index.html:69 part/templates/part/category.html:83 +#: templates/navbar.html:10 templates/stats.html:8 templates/stats.html:17 msgid "Parts" msgstr "" @@ -724,7 +727,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:6 #: company/templates/company/supplier_part_base.html:13 -#: stock/templates/stock/item_base.html:141 +#: stock/templates/stock/item_base.html:154 msgid "Supplier Part" msgstr "" @@ -903,7 +906,7 @@ msgid "Order notes" msgstr "" #: order/models.py:162 order/models.py:213 part/views.py:1119 -#: stock/models.py:463 +#: stock/models.py:467 msgid "Quantity must be greater than zero" msgstr "" @@ -927,7 +930,7 @@ msgstr "" msgid "Line item notes" msgstr "" -#: order/models.py:298 stock/templates/stock/item_base.html:119 +#: order/models.py:298 stock/templates/stock/item_base.html:128 msgid "Purchase Order" msgstr "" @@ -939,15 +942,15 @@ msgstr "" msgid "Number of items received" msgstr "" -#: order/templates/order/order_base.html:64 +#: order/templates/order/order_base.html:61 msgid "Purchase Order Details" msgstr "" -#: order/templates/order/order_base.html:80 +#: order/templates/order/order_base.html:89 msgid "Issued" msgstr "" -#: order/templates/order/order_base.html:86 +#: order/templates/order/order_base.html:96 #: order/templates/order/purchase_order_detail.html:31 msgid "Received" msgstr "" @@ -1213,171 +1216,171 @@ msgstr "" msgid "Select currency for price calculation" msgstr "" -#: part/models.py:62 +#: part/models.py:61 msgid "Default location for parts in this category" msgstr "" -#: part/models.py:65 +#: part/models.py:64 msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:339 +#: part/models.py:338 msgid "Part must be unique for name, IPN and revision" msgstr "" -#: part/models.py:353 +#: part/models.py:352 msgid "Part cannot be a template part if it is a variant of another part" msgstr "" -#: part/models.py:354 +#: part/models.py:353 msgid "Part cannot be a variant of another part if it is already a template" msgstr "" -#: part/models.py:358 part/templates/part/detail.html:18 +#: part/models.py:357 part/templates/part/detail.html:19 msgid "Part name" msgstr "" -#: part/models.py:362 +#: part/models.py:361 msgid "Is this part a template part?" msgstr "" -#: part/models.py:371 +#: part/models.py:370 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:373 +#: part/models.py:372 msgid "Part description" msgstr "" -#: part/models.py:375 +#: part/models.py:374 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:380 +#: part/models.py:379 msgid "Part category" msgstr "" -#: part/models.py:382 +#: part/models.py:381 msgid "Internal Part Number" msgstr "" -#: part/models.py:384 +#: part/models.py:383 msgid "Part revision or version number" msgstr "" -#: part/models.py:386 +#: part/models.py:385 msgid "Link to extenal URL" msgstr "" -#: part/models.py:398 +#: part/models.py:397 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:442 +#: part/models.py:441 msgid "Default supplier part" msgstr "" -#: part/models.py:445 +#: part/models.py:444 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:447 +#: part/models.py:446 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:449 +#: part/models.py:448 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:451 +#: part/models.py:450 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:453 +#: part/models.py:452 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:455 +#: part/models.py:454 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:457 +#: part/models.py:456 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:459 +#: part/models.py:458 msgid "Is this part active?" msgstr "" -#: part/models.py:461 +#: part/models.py:460 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:463 +#: part/models.py:462 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:465 +#: part/models.py:464 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:1041 +#: part/models.py:1040 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:1046 +#: part/models.py:1045 msgid "Parameter Name" msgstr "" -#: part/models.py:1048 +#: part/models.py:1047 msgid "Parameter Units" msgstr "" -#: part/models.py:1074 +#: part/models.py:1073 msgid "Parent Part" msgstr "" -#: part/models.py:1076 +#: part/models.py:1075 msgid "Parameter Template" msgstr "" -#: part/models.py:1078 +#: part/models.py:1077 msgid "Parameter Value" msgstr "" -#: part/models.py:1102 +#: part/models.py:1101 msgid "Select parent part" msgstr "" -#: part/models.py:1111 +#: part/models.py:1110 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:1118 +#: part/models.py:1117 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:1121 +#: part/models.py:1120 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:1124 +#: part/models.py:1123 msgid "BOM item reference" msgstr "" -#: part/models.py:1127 +#: part/models.py:1126 msgid "BOM item notes" msgstr "" -#: part/models.py:1129 +#: part/models.py:1128 msgid "BOM line checksum" msgstr "" -#: part/models.py:1192 +#: part/models.py:1191 msgid "Part cannot be added to its own Bill of Materials" msgstr "" -#: part/models.py:1199 +#: part/models.py:1198 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" @@ -1386,8 +1389,8 @@ msgstr "" msgid "Part Attachments" msgstr "" -#: part/templates/part/category.html:13 part/templates/part/category.html:76 -#: templates/stats.html:14 +#: part/templates/part/category.html:13 part/templates/part/category.html:78 +#: templates/stats.html:12 msgid "Part Categories" msgstr "" @@ -1395,31 +1398,31 @@ msgstr "" msgid "All parts" msgstr "" -#: part/templates/part/category.html:34 part/templates/part/category.html:72 +#: part/templates/part/category.html:34 part/templates/part/category.html:73 msgid "Category Details" msgstr "" -#: part/templates/part/category.html:38 +#: part/templates/part/category.html:39 msgid "Category Path" msgstr "" -#: part/templates/part/category.html:43 +#: part/templates/part/category.html:44 msgid "Category Description" msgstr "" -#: part/templates/part/category.html:49 part/templates/part/detail.html:73 +#: part/templates/part/category.html:50 part/templates/part/detail.html:74 msgid "Default Location" msgstr "" -#: part/templates/part/category.html:56 part/templates/part/detail.html:50 +#: part/templates/part/category.html:57 part/templates/part/detail.html:51 msgid "Keywords" msgstr "" -#: part/templates/part/category.html:62 +#: part/templates/part/category.html:63 msgid "Subcategories" msgstr "" -#: part/templates/part/category.html:67 +#: part/templates/part/category.html:68 msgid "Parts (Including subcategories)" msgstr "" @@ -1427,115 +1430,111 @@ msgstr "" msgid "Part Details" msgstr "" -#: part/templates/part/detail.html:24 part/templates/part/part_base.html:75 +#: part/templates/part/detail.html:25 part/templates/part/part_base.html:77 msgid "IPN" msgstr "" -#: part/templates/part/detail.html:31 +#: part/templates/part/detail.html:32 msgid "Revision" msgstr "" -#: part/templates/part/detail.html:43 +#: part/templates/part/detail.html:44 msgid "Variant Of" msgstr "" -#: part/templates/part/detail.html:56 +#: part/templates/part/detail.html:57 msgid "Category" msgstr "" -#: part/templates/part/detail.html:66 -msgid "Link" -msgstr "" - -#: part/templates/part/detail.html:80 +#: part/templates/part/detail.html:81 msgid "Default Supplier" msgstr "" -#: part/templates/part/detail.html:88 +#: part/templates/part/detail.html:89 msgid "Units" msgstr "" -#: part/templates/part/detail.html:94 +#: part/templates/part/detail.html:95 msgid "Minimum Stock" msgstr "" -#: part/templates/part/detail.html:100 +#: part/templates/part/detail.html:101 msgid "Creation Date" msgstr "" -#: part/templates/part/detail.html:106 +#: part/templates/part/detail.html:107 msgid "Created By" msgstr "" -#: part/templates/part/detail.html:113 +#: part/templates/part/detail.html:114 msgid "Responsible User" msgstr "" -#: part/templates/part/detail.html:122 +#: part/templates/part/detail.html:123 msgid "Virtual" msgstr "" -#: part/templates/part/detail.html:125 +#: part/templates/part/detail.html:126 msgid "Part is virtual (not a physical part)" msgstr "" -#: part/templates/part/detail.html:127 +#: part/templates/part/detail.html:128 msgid "Part is not a virtual part" msgstr "" -#: part/templates/part/detail.html:131 +#: part/templates/part/detail.html:132 msgid "Assembly" msgstr "" -#: part/templates/part/detail.html:134 +#: part/templates/part/detail.html:135 msgid "Part can be assembled from other parts" msgstr "" -#: part/templates/part/detail.html:136 +#: part/templates/part/detail.html:137 msgid "Part cannot be assembled from other parts" msgstr "" -#: part/templates/part/detail.html:140 +#: part/templates/part/detail.html:141 msgid "Component" msgstr "" -#: part/templates/part/detail.html:143 +#: part/templates/part/detail.html:144 msgid "Part can be used in assemblies" msgstr "" -#: part/templates/part/detail.html:145 +#: part/templates/part/detail.html:146 msgid "Part cannot be used in assemblies" msgstr "" -#: part/templates/part/detail.html:149 +#: part/templates/part/detail.html:150 msgid "Trackable" msgstr "" -#: part/templates/part/detail.html:152 +#: part/templates/part/detail.html:153 msgid "Part stock is tracked by serial number" msgstr "" -#: part/templates/part/detail.html:154 +#: part/templates/part/detail.html:155 msgid "Part stock is not tracked by serial number" msgstr "" -#: part/templates/part/detail.html:158 +#: part/templates/part/detail.html:159 msgid "Purchaseable" msgstr "" -#: part/templates/part/detail.html:161 part/templates/part/detail.html:163 +#: part/templates/part/detail.html:162 part/templates/part/detail.html:164 msgid "Part can be purchased from external suppliers" msgstr "" -#: part/templates/part/detail.html:168 +#: part/templates/part/detail.html:169 msgid "Sellable" msgstr "" -#: part/templates/part/detail.html:171 +#: part/templates/part/detail.html:172 msgid "Part can be sold to customers" msgstr "" -#: part/templates/part/detail.html:173 +#: part/templates/part/detail.html:174 msgid "Part cannot be sold to customers" msgstr "" @@ -1563,23 +1562,23 @@ msgstr "" msgid "Show pricing information" msgstr "" -#: part/templates/part/part_base.html:95 +#: part/templates/part/part_base.html:98 msgid "Available Stock" msgstr "" -#: part/templates/part/part_base.html:100 +#: part/templates/part/part_base.html:103 msgid "In Stock" msgstr "" -#: part/templates/part/part_base.html:121 +#: part/templates/part/part_base.html:124 msgid "Build Status" msgstr "" -#: part/templates/part/part_base.html:125 +#: part/templates/part/part_base.html:128 msgid "Can Build" msgstr "" -#: part/templates/part/part_base.html:130 +#: part/templates/part/part_base.html:133 msgid "Underway" msgstr "" @@ -1619,7 +1618,7 @@ msgstr "" msgid "BOM" msgstr "" -#: part/templates/part/tabs.html:28 stock/templates/stock/item_base.html:113 +#: part/templates/part/tabs.html:28 stock/templates/stock/item_base.html:121 #: templates/navbar.html:12 msgid "Build" msgstr "" @@ -1737,67 +1736,67 @@ msgstr "" msgid "Export Bill of Materials" msgstr "" -#: part/views.py:1406 +#: part/views.py:1404 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:1413 +#: part/views.py:1411 msgid "Part was deleted" msgstr "" -#: part/views.py:1422 +#: part/views.py:1420 msgid "Part Pricing" msgstr "" -#: part/views.py:1544 +#: part/views.py:1542 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:1552 +#: part/views.py:1550 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:1559 +#: part/views.py:1557 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:1567 +#: part/views.py:1565 msgid "Create Part Parameter" msgstr "" -#: part/views.py:1617 +#: part/views.py:1615 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:1631 +#: part/views.py:1629 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:1647 +#: part/views.py:1645 msgid "Edit Part Category" msgstr "" -#: part/views.py:1682 +#: part/views.py:1680 msgid "Delete Part Category" msgstr "" -#: part/views.py:1688 +#: part/views.py:1686 msgid "Part category was deleted" msgstr "" -#: part/views.py:1696 +#: part/views.py:1694 msgid "Create new part category" msgstr "" -#: part/views.py:1747 +#: part/views.py:1745 msgid "Create BOM item" msgstr "" -#: part/views.py:1813 +#: part/views.py:1811 msgid "Edit BOM item" msgstr "" -#: part/views.py:1861 +#: part/views.py:1859 msgid "Confim BOM item deletion" msgstr "" @@ -1893,45 +1892,45 @@ msgstr "" msgid "Stock Item Notes" msgstr "" -#: stock/models.py:460 +#: stock/models.py:464 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:466 +#: stock/models.py:470 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:469 stock/models.py:472 +#: stock/models.py:473 stock/models.py:476 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:475 +#: stock/models.py:479 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:485 +#: stock/models.py:489 msgid "Serial numbers already exist: " msgstr "" -#: stock/models.py:507 +#: stock/models.py:511 msgid "Add serial number" msgstr "" -#: stock/models.py:510 +#: stock/models.py:514 #, python-brace-format msgid "Serialized {n} items" msgstr "" -#: stock/models.py:810 +#: stock/models.py:814 msgid "Tracking entry title" msgstr "" -#: stock/models.py:812 +#: stock/models.py:816 msgid "Entry notes" msgstr "" -#: stock/models.py:814 +#: stock/models.py:818 msgid "Link to external page for further information" msgstr "" @@ -1962,28 +1961,28 @@ msgstr "" msgid "This stock item was split from " msgstr "" -#: stock/templates/stock/item_base.html:85 +#: stock/templates/stock/item_base.html:88 msgid "Belongs To" msgstr "" -#: stock/templates/stock/item_base.html:90 +#: stock/templates/stock/item_base.html:94 #: stock/templates/stock/stock_adjust.html:17 msgid "Location" msgstr "" -#: stock/templates/stock/item_base.html:96 +#: stock/templates/stock/item_base.html:101 msgid "Serial Number" msgstr "" -#: stock/templates/stock/item_base.html:146 +#: stock/templates/stock/item_base.html:160 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:150 +#: stock/templates/stock/item_base.html:165 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:154 +#: stock/templates/stock/item_base.html:169 msgid "No stocktake performed" msgstr "" @@ -1999,29 +1998,29 @@ msgstr "" msgid "Location Details" msgstr "" -#: stock/templates/stock/location.html:41 +#: stock/templates/stock/location.html:42 msgid "Location Path" msgstr "" -#: stock/templates/stock/location.html:46 +#: stock/templates/stock/location.html:47 msgid "Location Description" msgstr "" -#: stock/templates/stock/location.html:51 +#: stock/templates/stock/location.html:52 msgid "Sublocations" msgstr "" -#: stock/templates/stock/location.html:56 -#: stock/templates/stock/location.html:70 templates/stats.html:18 -#: templates/stats.html:21 +#: stock/templates/stock/location.html:57 +#: stock/templates/stock/location.html:72 templates/stats.html:21 +#: templates/stats.html:30 msgid "Stock Items" msgstr "" -#: stock/templates/stock/location.html:61 +#: stock/templates/stock/location.html:62 msgid "Stock Details" msgstr "" -#: stock/templates/stock/location.html:65 +#: stock/templates/stock/location.html:67 #: templates/InvenTree/search_stock_location.html:6 templates/stats.html:25 msgid "Stock Locations" msgstr "" @@ -2194,30 +2193,38 @@ msgstr "" msgid "No results found" msgstr "" -#: templates/about.html:18 +#: templates/about.html:13 msgid "InvenTree Version Information" msgstr "" #: templates/about.html:21 -msgid "Version" +msgid "Instance Name" msgstr "" -#: templates/about.html:24 +#: templates/about.html:26 +msgid "InvenTree Version" +msgstr "" + +#: templates/about.html:30 msgid "Commit Hash" msgstr "" -#: templates/about.html:27 +#: templates/about.html:34 msgid "Commit Date" msgstr "" -#: templates/about.html:33 +#: templates/about.html:38 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:37 +#: templates/about.html:43 msgid "View Code on GitHub" msgstr "" +#: templates/about.html:47 +msgid "Submit Bug Report" +msgstr "" + #: templates/navbar.html:23 msgid "Admin" msgstr ""